fix(landing): repair Lighthouse-flagged CWV audits on production#5605
Conversation
Empirically verified against a live full Lighthouse run of www.sim.ai (production, pre-fix) plus a local build of the exact deployed commit with source maps temporarily enabled for root-causing. Distinguished genuinely failing audits from passing ones already misread as broken. - fetchPriority missing on every LCP hero image: `priority` generates a preload <link> but Next does not auto-add fetchpriority=high to it - confirmed via raw deployed HTML diff. Added explicit fetchPriority='high' to all 5 priority Image usages (hero, enterprise, blog/library post + index cards). - valid-source-maps failing: production ships no source maps at all (productionBrowserSourceMaps defaults false). Enabled it - safe here since this repo's frontend is already fully open source, so no incremental exposure versus Next's default. - image-delivery-insight (55.8KB wasted): feature-integrate-ui.png's `sizes` hint was a flat 1050px regardless of viewport, so mobile fetched the 1920w variant for a ~423px real render. Replaced with a responsive sizes expression derived from the sibling backdrop image's own (already correct) hint, scaled by the callout's documented 125% overhang. - cache-insight (best-fixable portion): _next/static/* filenames are content-hashed and immutable per deploy, but shared one cache rule with unhashed /public assets, capping both at 1-day max-age. Split into two rules - hashed assets now get 1-year immutable, unhashed assets keep the shorter revalidating TTL. Verified via a real build + server that both paths now return the correct distinct header. Investigated and NOT changed (documented, not assumed): - legacy-javascript-insight (14KB): traced via sourcemap to next/dist/build/polyfills/polyfill-module.js - Next's own built-in polyfill bundle, not our code or a dependency, and not exposed via any next.config.ts option. No browserslist misconfiguration on our end (none exists; Next already defaults to its modern target). - forced-reflow-insight: even with source maps present locally, the dominant cost (335-417ms) stayed [unattributed] by Chrome's own profiler, and the small attributed slice was non-deterministic between our own chunk and a third-party script (HubSpot analytics) across runs - not a confident single root cause worth a targeted fix. - render-blocking-insight / network-dependency-tree / bf-cache: bf-cache's actual failure reason is Cache-Control: no-store on the main document - the exact root cause already fixed on staging (PR #5522/#5528, the PublicEnvScript/unstable_noStore fix) but not yet promoted to main/prod. Resolves once that ships, not additional work here.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryLow Risk Overview Core Web Vitals / performance: Adds explicit Caching: Excludes LLM / docs manifests: Dynamic docs and sim Reviewed by Cursor Bugbot for commit a501857. Configure here. |
Greptile SummaryThis PR fixes several Lighthouse and landing-page performance issues. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (3): Last reviewed commit: "fix(llms): actually include the route.ts..." | Re-trigger Greptile |
…6s -> 2.8s) Ran a full Lighthouse sweep across every public page as requested. /blog scored 73 (LCP 6.6s) while every other page scored 95+ - reproduced consistently across 3 runs, not noise. Traced via lcp-breakdown-insight: the LCP image (mothership/cover.png, 241KB even after the earlier palette compression pass) took 6+ seconds to download on simulated mobile throttling, well beyond what its size should cost. PNG is a poor fit for this illustration's subtle gradients versus JPEG's lossy compression. Verified empirically before converting: same 1920x1080 resolution, visually identical (spot-checked), 241KB -> 65KB (73% smaller). No other cover in the content set uses PNG and benefits the same way (checked copilot/cover.png, the only other PNG cover - already optimal at 64KB, converting it yielded no improvement, left unchanged). Verified fix: /blog score 73->93, LCP 6.6s->2.8s, reproduced across 3 runs.
- integrations-callout: account for FeatureCard's max-lg:grid-cols-1 mobile stack in the sizes hint, verified against Lighthouse's measured mobile render width. - next.config: remove a custom _next/static cache-control rule that never actually fired (confirmed via header-marker test) - Next's own built-in default already applies the correct immutable 1yr cache to that path.
- integrations-callout: derive sizes from the section's actual grid math (fixed 386px copy column, 40px gap, section gutters) instead of an approximated vw fraction. Verified against a static reproduction of the layout rendered at each Tailwind breakpoint - the old 110vw mobile tier underestimated real render width by ~3% right at the 1023px stack boundary, which could cause the browser to pick a too-small srcset candidate and upscale. - next.config: the .map header rule's trailing `$` was read as a literal character by Next's path-to-regexp source matcher, not a regex anchor, so the rule never matched a real .map URL (confirmed via routes-manifest regex + a live header check). Removed the dead anchor and added a bounded Cache-Control so a future decision to stop shipping source maps isn't undermined by a 1yr immutable cache on already-fetched maps.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit f7e3b36. Configure here.
…c files
Both the marketing site and docs site's llms.txt validator errors ("does
not appear to contain any links") traced to the same root cause: a static
public/llms.txt shadowed a better-written, already-existing dynamic
app/llms.txt route, and every "link" in the static files (and in the
docs app's auto-generated route) was bare `label: url` text, not Markdown
link syntax - so a strict Markdown-link parser found zero matches even
though URLs were visibly present.
- apps/sim: delete public/llms.txt (dead code, shadowing the properly
Markdown-linked app/llms.txt route.ts, confirmed via production headers
showing the static file was what actually served). Fix llms-full.txt's
Links/Support/Legal sections to use [label](url) syntax, correct a
stale "Next.js 15" reference, and replace "Mothership" with "Chat" per
the constitution's language rules.
- apps/docs: same shadowing issue - delete the orphaned public/llms.txt
(also still said "Mothership"). Fix the auto-generated per-page link
list in app/llms.txt/route.ts to emit [title](url) instead of
"title: url" for every documentation page.
The prior commit (3b2d35c) only staged the two deleted public/llms.txt files - these two modified route.ts files (the Mothership/link-format fixes they were meant to accompany) were left unstaged. No new changes, just completing that commit's intent.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit a501857. Configure here.
Summary
Ran a full Lighthouse audit against live production (www.sim.ai) and empirically triaged every audit the user's lighthouse-metrics.com scan flagged — confirming which were genuinely failing vs. already passing before touching anything.
Fixed:
lcp-discovery-insight—priorityon next/image generates a preload<link>but Next does not auto-addfetchpriority=highto it (confirmed via raw deployed HTML). Added explicitfetchPriority='high'to all 5priorityImage usages across hero, enterprise, and blog/library post/index cards.valid-source-maps— production ships zero source maps (productionBrowserSourceMapsdefaults false). Enabled it — safe since this repo's frontend is already fully open source.image-delivery-insight(55.8KB wasted) —feature-integrate-ui.png'ssizeshint was a flat1050pxregardless of viewport, so mobile fetched the 1920w variant for a ~423px real render. Replaced with a responsive expression derived from the sibling backdrop image's own correct hint, scaled by the documented 125% overhang.cache-insight(our controllable portion) —_next/static/*(content-hashed, immutable per deploy) shared one cache rule with unhashed/publicassets, capping both at 1-day. Split into two rules; hashed assets now get 1-year immutable. Verified via a real build + running server that both paths return the correct distinct header.Investigated, not changed (documented why, not assumed):
legacy-javascript-insight(14KB) — traced via a temporary source-map build tonext/dist/build/polyfills/polyfill-module.js, Next's own built-in polyfill bundle. Not our code, not a dependency, no browserslist misconfiguration on our end.forced-reflow-insight— even with source maps present, the dominant cost (335-417ms) stayed[unattributed]by Chrome's own profiler; the small attributed slice bounced non-deterministically between our chunk and a third-party script across runs. Not a confident single root cause.render-blocking-insight/network-dependency-tree-insight/bf-cache— bf-cache's actual failure reason isCache-Control: no-storeon the main document, the exact root cause already fixed on staging in fix(landing): fix Core Web Vitals regressions across public marketing pages #5522/fix(landing): revert unoptimized removal, compress source images instead #5528 (thePublicEnvScript/unstable_noStorefix), just not yet promoted tomain/prod.Type of Change
Testing
tsc --noEmitclean (one pre-existing, unrelated error inproviders/meta/index.ts)bun run lintclean_next/staticCSS/font asset vs. an unhashed/publicSVGChecklist