fix(landing): revert unoptimized removal, compress source images instead#5528
Conversation
…nstead PR #5522 removed `unoptimized` from local blog/library/integration cover images, expecting next/image's runtime optimizer to serve resized AVIF/WebP. On staging, images broke entirely on /blog - the runtime optimizer is failing there (root cause still under investigation: _next/image requests aren't captured by the app's structured logger, so the underlying error wasn't visible in application logs). Reverting `unoptimized` immediately restores working images. In its place, this compresses the actual source files (mozjpeg quality 82 for JPEGs, palette PNG for PNGs) at their EXACT existing pixel dimensions - verified programmatically per-file (dimension mismatch aborts the write) and spot-checked visually. This gets the same bandwidth/LCP win the runtime optimizer was meant to provide, without depending on it: - 13 blog/library cover images + 3 author avatars + 1 brand logo - ~1.72MB -> ~1.02MB combined (~41% smaller), zero resolution change
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview This reverses the prior removal that relied on the Next.js image optimizer on staging, where those optimized requests were failing and cover images broke. Static assets are expected to be kept lean at source (per the PR description’s recompression work) rather than depending on runtime optimization for these paths. Reviewed by Cursor Bugbot for commit 401d66b. Configure here. |
Greptile SummaryThis PR restores direct serving for landing-page images and recompresses the source assets. The main changes are:
Confidence Score: 5/5This looks safe to merge.
apps/sim/public/authors/sid.jpg Important Files Changed
|
|
Re: Greptile's EXIF orientation concern on |
* fix(landing): repair Lighthouse-flagged CWV audits on production 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. * fix(landing): convert mothership cover from PNG to JPEG (/blog LCP 6.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. * fix(landing): correct mobile sizes tier, drop non-functional cache rule - 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. * fix(landing): correct sizes underestimate + fix dead .map header rule - 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. * fix(llms): serve well-formed llms.txt, remove Mothership + dead static 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. * fix(llms): actually include the route.ts fixes from the prior commit 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.
Summary
unoptimizedfrom local blog/library/integration cover images, expecting next/image's runtime optimizer to serve resized AVIF/WebP. That optimizer is failing on staging (root cause still under investigation —/_next/imagerequests don't go through the app's structured logger, so nothing showed up in application logs). Revertedunoptimizedon all 7 spots immediately.Type of Change
Testing
tsc --noEmitclean,biome checkcleanChecklist