Skip to content

perf: fix render-blocking CSS and font display#930

Closed
moshams272 wants to merge 1 commit into
nodejs:mainfrom
moshams272:perf/render-blocking
Closed

perf: fix render-blocking CSS and font display#930
moshams272 wants to merge 1 commit into
nodejs:mainfrom
moshams272:perf/render-blocking

Conversation

@moshams272

Copy link
Copy Markdown
Contributor

Description

As shown in the attached Lighthouse performance reports, the generated HTML templates have Render-Blocking issues caused by the main styles.css and the Google Fonts CSS files. Furthermore, the Google Fonts lacked display=swap, causing a Flash of Invisible Text (FOIT).

image image

This PR improves performance (both web and legacy) by:

  • Implementing a high-performance rel="preload" pattern: that instructs the browser to download the file with low priority. The onload script flips the attribute back to stylesheet once downloading is complete, applying the styles smoothly.

  • Using display=swap on Google Fonts to ensure text is immediately visible with the default text till the font is downloaded, then apply that.

Validation

Tested on webpack/webpack-doc-kit.

Before:
image

After:
image

Related Issues

None

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@moshams272
moshams272 requested a review from a team as a code owner July 21, 2026 18:02
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
api-docs-tooling Ready Ready Preview Jul 21, 2026 6:03pm

Request Review

@cursor

cursor Bot commented Jul 21, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Static HTML template-only changes with noscript fallbacks; no auth, data, or application logic affected.

Overview
Reduces render-blocking and FOIT in generated documentation pages by changing how legacy and web HTML templates pull in styles and Google Fonts.

Both templates now load styles.css (or assets/style.css on legacy) and font CSS via rel="preload" with an onload handler that switches to stylesheet, plus <noscript> fallbacks for users without JavaScript. Legacy also switches the Lato URL from display=fallback to display=swap; the web template adds &display=swap to the Google Fonts URL.

Reviewed by Cursor Bugbot for commit 09ba17a. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

@moshams272 is attempting to deploy a commit to the OpenJS Foundation Team on Vercel.

A member of the Team first needs to authorize it.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 09ba17a. Configure here.

<link rel="preload" href="${root}styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript>
<link rel="stylesheet" href="${root}styles.css">
</noscript>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Async critical CSS causes FOUC

Medium Severity

The main stylesheets (styles.css / assets/style.css) are loaded with the non-blocking rel="preload" pattern, but no critical CSS is inlined. That pattern is meant for non-critical CSS; applying it to the sole layout stylesheet lets the page paint unstyled, then snap into place when CSS arrives. This undoes the existing theme FOUC guards and can also shift layout-dependent behavior such as sidebar scrolling.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 09ba17a. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use library critters, WDUT?!

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.89%. Comparing base (ecbeaa6) to head (09ba17a).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #930   +/-   ##
=======================================
  Coverage   84.89%   84.89%           
=======================================
  Files         193      193           
  Lines       17512    17512           
  Branches     1551     1551           
=======================================
  Hits        14867    14867           
  Misses       2639     2639           
  Partials        6        6           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment on lines +24 to +35
<link
rel="preload"
href="assets/style.css"
as="style"
onload="
this.onload = null;
this.rel = 'stylesheet';
"
/>
<noscript>
<link rel="stylesheet" href="assets/style.css" />
</noscript>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we shouldn't mix CSS and JavaScript in this way. CSS shouldn't rely on the JavaScript capabilities of a given machine.

Unfortunately, I think we need to just eat the perf issue. We might be able to reduce the size of CSS in doc-kit, perhaps, but I won't make you work on that, it's our fault, and not something that's particularly 'fun' or easy to fix.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use library critters, It extracts the Critical CSS and inlines it directly into a <style> tag in the generated HTML. This means the initial render relies on zero client-side JS and has no render-blocking network requests, WDUT?!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I searched on it since few hours, #930 (comment)

@avivkeller

Copy link
Copy Markdown
Member

I think a better alternative to this is for us to look into improving our CSS at it's core, not ways around it's current state. Thank you anyway :-). We (doc-kit maintainers) can look into this.

@avivkeller avivkeller closed this Jul 22, 2026
Comment on lines +13 to +16
onload="
this.onload = null;
this.rel = 'stylesheet';
"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should preload the Google Fonts stylesheet obviously without any JavaScript, just using the standard preload/prefetch approach. I'm still surprised we're using Google Fonts instead of hosting them ourselves, but that's a separate discussion.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-hosting the fonts would be the ideal solution 👀

@moshams272

Copy link
Copy Markdown
Contributor Author

I think a better alternative to this is for us to look into improving our CSS at it's core, not ways around it's current state. Thank you anyway :-). We (doc-kit maintainers) can look into this.

NP, you're right, BTW.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants