Skip to content

Fix/mobile performance core web vitals - #795

Open
Aryan-B-Parikh wants to merge 9 commits into
keploy:mainfrom
Aryan-B-Parikh:fix/mobile-performance-core-web-vitals
Open

Aryan-B-Parikh wants to merge 9 commits into
keploy:mainfrom
Aryan-B-Parikh:fix/mobile-performance-core-web-vitals

Conversation

@Aryan-B-Parikh

Copy link
Copy Markdown

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

  • 1-year immutable cache for hashed webpack bundles (/assets/*, /fonts/*)
  • 1-day cache for images and scripts
  • Security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy)

docusaurus.config.js — Resource hints

  • preconnect for Google Fonts and Algolia DSN
  • dns-prefetch for Clarity, GTM, Google Analytics (~200ms saved per origin)
  • viewport-fit=cover meta tag

ResponsivePlayer.js — Lazy bundle split

  • react-player (~100 KB) deferred from initial bundle via React.lazy()

custom.css — Rendering performance

  • content-visibility: auto on footer and mobile sidebar
  • decoding: async fallback for all images
  • font-display: swap to prevent invisible text (FOIT)

112 doc files — Image lazy loading

  • loading="lazy" decoding="async" on every <img> tag across all versioned docs
  • Biggest wins: unit-test.gif (24.8 MB), record-replay.gif (2.5 MB)

Lighthouse audit (before, on live main)

Metric Value
Performance 86 (lab) / 65 (CrUX real users)
LCP 3.5s
TBT 250ms
Cache wasted 324 KiB
Render blocking 310ms

Copilot AI review requested due to automatic review settings February 24, 2026 10:39

@github-actions github-actions 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.

Thank you and congratulations 🎉 for opening your very first pull request in keploy

@kilo-code-bot

kilo-code-bot Bot commented Feb 24, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Overview

This PR implements comprehensive performance optimizations for the documentation site. The changes are well-structured and follow best practices:

  • Image lazy loading: Added loading="lazy" decoding="async" attributes to images across documentation files
  • Resource hints: Added preconnect/dns-prefetch for Google Fonts, Algolia, and analytics services
  • Cache headers: Configured appropriate cache policies for static assets (with correct non-immutable caching for fonts)
  • React lazy loading: Implemented Suspense-based lazy loading for ReactPlayer component with accessible fallback
  • CSS optimizations: Added content-visibility for off-screen elements and async decoding for images
Files Reviewed (57 files)
  • docs/gsoc/contribution-guide.md - lazy loading added
  • docs/hacktoberfest/contribution-guide.md - lazy loading added
  • docs/hacktoberfest/non-code.md - lazy loading added
  • docusaurus.config.js - preconnect/dns-prefetch hints added
  • netlify.toml - cache and security headers added
  • src/components/responsive-player/ResponsivePlayer.js - React lazy loading implemented
  • src/css/custom.css - content-visibility and rendering optimizations
  • Multiple versioned docs files - lazy loading added to images

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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" and decoding="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.

Comment thread src/css/custom.css Outdated
Comment thread src/css/custom.css Outdated
Comment thread src/components/responsive-player/ResponsivePlayer.js Outdated
Comment thread netlify.toml Outdated
Comment thread docusaurus.config.js Outdated
@Aryan-B-Parikh
Aryan-B-Parikh force-pushed the fix/mobile-performance-core-web-vitals branch from 55bdea4 to bca3ff0 Compare February 24, 2026 11:41
Aryan-B-Parikh added a commit to Aryan-B-Parikh/docs that referenced this pull request Feb 24, 2026
- 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 amaan-bhati left a comment

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.

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.

Aryan-B-Parikh added a commit to Aryan-B-Parikh/docs that referenced this pull request Apr 10, 2026
- 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>
@Aryan-B-Parikh
Aryan-B-Parikh force-pushed the fix/mobile-performance-core-web-vitals branch from 23d6224 to 67d10e5 Compare April 10, 2026 05:25
- 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>
@Aryan-B-Parikh
Aryan-B-Parikh force-pushed the fix/mobile-performance-core-web-vitals branch from 67d10e5 to 2ff3df7 Compare April 10, 2026 05:34
@Aryan-B-Parikh

Copy link
Copy Markdown
Author

Thanks for the review! ✅ @amaan-bhati

All requested changes are addressed:

  • Split the work into two PRs.
  • Hashed CSS selector replaced with stable attribute selectors.
  • Empty @font-face removed.
  • /fonts/* cache header updated to non‑immutable.
  • ResponsivePlayer fallback now shows a visible loading state.

Split PR for markdown-only loading="lazy" updates:
#828

Both branches rebased on latest main and conflicts resolved.

@amaan-bhati amaan-bhati left a comment

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.

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 uses immutable, 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!

@Aryan-B-Parikh

Copy link
Copy Markdown
Author

@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 chilkotiKartik 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.

LGTM! Thoroughly verified changes in Fix/mobile performance core web vitals. Code structure and implementation logic are clean and comply with repository standards.

@amaan-bhati amaan-bhati left a comment

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.

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!

This branch has not been deployed

No deployments
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.

[performance]: Improve mobile performance issues for docs website

5 participants