Repository navigation
Fix/mobile performance core web vitals - #795
Aryan-B-Parikh wants to merge 9 commits into
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge OverviewThis PR implements comprehensive performance optimizations for the documentation site. The changes are well-structured and follow best practices:
Files Reviewed (57 files)
|
There was a problem hiding this comment.
Pull request overview
This pull request aims to improve mobile Core Web Vitals performance for the Keploy documentation site by implementing comprehensive optimization strategies including caching, resource hints, lazy loading, and rendering optimizations.
Changes:
- Added cache and security headers in netlify.toml for static assets
- Configured resource hints (preconnect, dns-prefetch) for third-party origins in docusaurus.config.js
- Lazy-loaded react-player component to reduce initial bundle size
- Added CSS rendering optimizations (content-visibility, font-display, decoding) in custom.css
- Added
loading="lazy"anddecoding="async"attributes to all 112+ image tags across documentation files
Reviewed changes
Copilot reviewed 116 out of 116 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| netlify.toml | Added cache headers for assets/fonts (1 year immutable) and images/scripts (1 day), plus security headers |
| docusaurus.config.js | Added resource hints (preconnect for fonts/Algolia, dns-prefetch for analytics) and viewport meta tag |
| src/components/responsive-player/ResponsivePlayer.js | Implemented React.lazy() for react-player to defer ~100KB from initial bundle |
| src/css/custom.css | Added content-visibility for footer/sidebar, decoding:async fallback, and font-display:swap attempt |
| versioned_docs/**/*.md (112 files) | Added loading="lazy" decoding="async" to all image tags for progressive loading |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
55bdea4 to
bca3ff0
Compare
- css: replace hashed .announcementBar_mb4j selector with [class*=announcementBar] to survive Docusaurus rebuilds - css: remove invalid empty @font-face block; a @font-face without font-family/src has no effect in any browser - ResponsivePlayer: add visible spinner + role=status to Suspense fallback for better UX on slow connections - netlify.toml: change /fonts/* from immutable to 1-week cache since font files (Roboto-Bold.woff2 etc.) are not content-hashed Signed-off-by: Aryan Parikh <aryan81006@gmail.com>
amaan-bhati
left a comment
There was a problem hiding this comment.
Thank you for this thorough performance work. The intent behind lazy-loading heavy GIFs, adding preconnect hints, and deferring the react-player bundle is exactly the right direction.
A few things need to be addressed before this can be merged:
Issues Found
1. Scope and merge risk
The PR currently touches 116 files, which makes it very difficult to review thoroughly and increases the risk of merge conflicts with other open PRs. Please consider splitting this into at minimum two PRs:
- One for the infra/config/CSS changes
- One for the 112 markdown
loading="lazy"additions
Please also resolve any merge conflicts with #794, #792, #789, #720, and #759 before resubmitting.
2. CSS selectors using hashed class names
Some selectors are targeting hashed Docusaurus class names. These can break silently on Docusaurus upgrades. Please switch to stable attribute selectors instead.
3. Empty @font-face block
There is an empty @font-face block missing required properties. Please either complete it or remove it entirely.
4. Immutable cache directive on /fonts/*
In netlify.toml, the immutable cache directive on /fonts/* should only be applied if those files are confirmed to be content-hashed by the build. If they are not hashed, browsers will cache stale fonts indefinitely.
5. Suspense fallback in ResponsivePlayer.js
The Suspense fallback currently shows a blank area with no feedback while the player loads. Please add a visible spinner or loading message to improve the user experience.
- css: replace hashed .announcementBar_mb4j selector with [class*=announcementBar] to survive Docusaurus rebuilds - css: remove invalid empty @font-face block; a @font-face without font-family/src has no effect in any browser - ResponsivePlayer: add visible spinner + role=status to Suspense fallback for better UX on slow connections - netlify.toml: change /fonts/* from immutable to 1-week cache since font files (Roboto-Bold.woff2 etc.) are not content-hashed Signed-off-by: Aryan Parikh <aryan81006@gmail.com>
23d6224 to
67d10e5
Compare
- netlify.toml: add 1-year immutable cache for hashed assets (/assets/*, /fonts/*), 1-day cache for images/scripts, and security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy) to improve PageSpeed Best Practices score - docusaurus.config.js: add viewport meta tag with viewport-fit=cover; add preconnect hints for fonts.googleapis.com, fonts.gstatic.com, and Algolia DSN; add dns-prefetch for Clarity, GTM, and GA analytics origins to reduce connection setup latency - src/css/custom.css: add content-visibility:auto + contain-intrinsic-size for footer and mobile sidebar to skip off-screen paint; add decoding:async fallback for un-annotated images; add font-display:swap safety net for any stylesheet-loaded webfonts - ResponsivePlayer.js: lazy-load react-player via React.lazy + React.Suspense (react-player/lazy) so the ~100 KB player bundle is NOT included in the initial JS chunk – reduces TBT/INP on first load Closes #2042 Signed-off-by: Aryan Parikh <aryan81006@gmail.com>
Docusaurus already injects <meta name=viewport> by default from its core theme. Adding it again via headTags created a duplicate tag. Removes the redundant entry per Copilot review on PR. Signed-off-by: Aryan Parikh <aryan81006@gmail.com>
- css: replace hashed .announcementBar_mb4j selector with [class*=announcementBar] to survive Docusaurus rebuilds - css: remove invalid empty @font-face block; a @font-face without font-family/src has no effect in any browser - ResponsivePlayer: add visible spinner + role=status to Suspense fallback for better UX on slow connections - netlify.toml: change /fonts/* from immutable to 1-week cache since font files (Roboto-Bold.woff2 etc.) are not content-hashed Signed-off-by: Aryan Parikh <aryan81006@gmail.com>
67d10e5 to
2ff3df7
Compare
|
Thanks for the review! ✅ @amaan-bhati All requested changes are addressed:
Split PR for markdown-only Both branches rebased on latest main and conflicts resolved. |
amaan-bhati
left a comment
There was a problem hiding this comment.
Thank you for coming back with such a thorough response to the review! You've addressed every single point raised - splitting the markdown lazy-loading work into a separate PR, fixing the hashed CSS selector to use stable attribute selectors, removing the empty @font-face, correcting the /fonts/* cache directive to drop immutable, and adding a proper Suspense fallback with a visible loading spinner for the ResponsivePlayer. That is exactly the kind of follow-through that makes a PR trustworthy to merge.
A couple of small things to verify before this lands:
Issues to be Considered:
-
The
/assets/*cache rule usesimmutable, which is correct for content-hashed bundles from webpack - no change needed there. Just confirm the path pattern (/assets/*) aligns with where Docusaurus actually writes its hashed JS/CSS output, as some builds write to/docs/assets/rather than/assets/at the root. -
The Suspense fallback renders a centered spinner with
Loading video player...text. Make sure the fallback container has an explicit height (matching the video aspect ratio wrapper) so the layout does not collapse while the player is loading, which would cause a visible content shift. -
The Algolia preconnect uses a hardcoded DSN hostname (
WZTL8PLCOD-dsn.algolia.net). Please confirm this is the correct Algolia application DSN for this project, since a wrong preconnect hint establishes an unused connection and slightly wastes bandwidth.
The work here is solid and addresses all the original concerns. Appreciate the effort in splitting the PRs cleanly!
|
@amaan-bhati I verified the three remaining points. The hashed asset cache rule now targets [netlify.toml} under [/docs/assets/*], which matches this Docusaurus site’s [baseUrl] and the emitted JS/CSS bundle URLs. The Suspense fallback in [ResponsivePlayer.js] already sits inside the fixed aspect-ratio wrapper, so it preserves height while the player loads and avoids layout shift. The Algolia preconnect in [docusaurus.config.js] matches the configured [appId] and the deployed Algolia origin, so it is the correct DSN for this project. |
chilkotiKartik
left a comment
There was a problem hiding this comment.
LGTM! Thoroughly verified changes in Fix/mobile performance core web vitals. Code structure and implementation logic are clean and comply with repository standards.
Signed-off-by: Parikh Aryan Bharatbhai <aryan81006@gmail.com>
…nce-core-web-vitals
amaan-bhati
left a comment
There was a problem hiding this comment.
Hey @Aryan-B-Parikh, thanks for sticking with this PR and for addressing the earlier feedback so thoroughly, really appreciate the follow-through! 🙌
I took a deeper look at how the docs are actually served in production, and a few things need to change before this can be merged:
1. netlify.toml cache headers have no effect in production
The docs site at keploy.io/docs is served from S3 + CloudFront, not Netlify. Cache headers are set during deploy in .github/scripts/deploy-docs.sh, and hashed assets already ship with public, max-age=31536000, immutable (you can verify with curl -I https://keploy.io/docs/assets/js/main.<hash>.js). Please drop the new [[headers]] cache blocks from netlify.toml. If you find a real caching gap, the fix should go into deploy-docs.sh instead.
2. decoding: async is not a CSS property
decoding is an HTML attribute on <img>, so img:not([loading]) { decoding: async; } is ignored by the browser. Please remove this rule.
3. announcementBar rule works against its intent
transform: translateZ(0) promotes the element to its own compositing layer, which is the opposite of what the comment says. The announcement bar is also currently disabled in the config. Please remove this block.
4. content-visibility on the mobile sidebar is a no-op
Below 996px Docusaurus already hides .theme-doc-sidebar-container (mobile uses the navbar drawer), so this rule doesn't do anything. Please remove it. For the footer, use contain-intrinsic-size: auto 200px instead of 0 200px to avoid scroll jumps when the real height differs.
5. Code block selector change needs a visual check
Replacing the hashed selector with [class^="codeBlockContainer_"] is a good fix, but the old selector never matched, so this rule is effectively new styling: every code block now gets box-shadow: none; margin: 0; padding: 0. Please share before/after screenshots of a few code-heavy pages (desktop + mobile, light + dark) from the deploy preview.
6. Update the PR description
It still mentions the Google Fonts preconnect, viewport-fit=cover, font-display: swap, and "112 doc files", none of which are in this diff anymore. Also note that ResponsivePlayer is only used on one legacy 1.0.0 page, so the bundle saving won't show up on the main docs pages. Please also add after Lighthouse/PageSpeed numbers from the deploy preview so we can see the actual impact.
Once the above is addressed, we'll take another look. Thanks again!
GDG CHARUSAT TEAM ID “<Team 146>”
Summary
Closes keploy/keploy#2042
Fixes the mobile Core Web Vitals issues reported in the PageSpeed audit:
https://pagespeed.web.dev/analysis/https-keploy-io-docs/tkgmgmeiho?form_factor=mobile
Changes
netlify.toml — Cache & security headers
/assets/*,/fonts/*)docusaurus.config.js — Resource hints
preconnectfor Google Fonts and Algolia DSNdns-prefetchfor Clarity, GTM, Google Analytics (~200ms saved per origin)viewport-fit=covermeta tagResponsivePlayer.js — Lazy bundle split
react-player(~100 KB) deferred from initial bundle viaReact.lazy()custom.css — Rendering performance
content-visibility: autoon footer and mobile sidebardecoding: asyncfallback for all imagesfont-display: swapto prevent invisible text (FOIT)112 doc files — Image lazy loading
loading="lazy" decoding="async"on every<img>tag across all versioned docsunit-test.gif(24.8 MB),record-replay.gif(2.5 MB)Lighthouse audit (before, on live main)