MWPW-206311: preload first-section LCP content before MEP - #6643
MWPW-206311: preload first-section LCP content before MEP#6643vhargrave wants to merge 15 commits into
Conversation
Warm the first (LCP) section's assets — authored blocks, link-autoblocks, placeholders, and icons.js — in loadArea immediately before the MEP await in checkForPageMods() holds up section processing, so their fetches are already in flight when processing resumes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Warm the first section's block code, non-merch/mas autoblocks, placeholder sheets and icons during checkForPageMods() instead of after it, so the LCP element can paint sooner. fetchpriority=high; commerce (merch/mas) autoblocks excluded (heavy dep chain hurts non-store heroes). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Hello, I'm the AEM Code Sync Bot and I will run some actions to deploy your branch.
|
Emergency opt-out: <meta name="disable-mep-perf-optimization" content="on"> skips the pre-MEP preload (page-level or site-wide via the global metadata sheet). Default = enabled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…PageMods high == browser default for these preload types, so the explicit fetchpriority plumbing is removed (preloadBlockResources reverts to its original signature). The preload now fires inside checkForPageMods right after the mep=off early return, co-locating it with MEP logic while still running before the MEP await. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…clusion) Export preloadLcpCodeFiles and add focused tests: kill-switch metadata, authored-block preload, non-commerce autoblock warming with merch/mas excluded, media_*.mp4 video guard (anchor + img alt), placeholder and icon gating, and the no-first-section early return. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move getValidatedMasLibsUrl, getMasDepUrl, STATIC_BLOCK_DEPS, blockDeps, preloadBlockResources and preloadLcpCodeFiles above checkForPageMods so the pre-MEP preloadLcpCodeFiles() call no longer needs an eslint-disable for no-use-before-define. Pure reorder, no behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-only-pre-mep # Conflicts: # libs/utils/utils.js
…e-MEP) #6589 hoisted geo-ip sheet warming into loadArea, but it runs after `await checkForPageMods()` — i.e. behind the MEP/Target wait, the exact latency this LCP work removes. Fold the same warmGeoIpSheet(config) call into preloadLcpCodeFiles alongside the placeholder warms so a {{...-geo-ip}} LCP token (or geo-ip-lcp MEP flag) is warmed before the await. Idempotent via geoIpWarm[url] ??=, so loadArea's later call dedupes. Geo-ip helpers hoisted above preloadLcpCodeFiles to keep it in scope. Adds two tests (warms when lingo active + token; no-op otherwise). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both callers (preloadLcpCodeFiles and loadArea) repeated the same lingoActive + -geo-ip-token + geo-ip-lcp gate. Move it inside warmGeoIpSheet(config, section, isDoc) so each caller is a single line. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
loadLink's dedup selector is rel-aware (link[href][rel=stylesheet] for loadStyle vs link[href] for preload), so the preload does not shadow the rel=stylesheet that decorateIcons later appends -- both coexist and the browser consumes the preload (single fetch). Warm the render-affecting sheet in parallel alongside icons.js. Tighten two decorateIcons tests to query the stylesheet specifically now that a preload link with the same href also exists. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The /merch|^mas-/ filter was applied only to link-derived autoblocks, so an authored <div class="merch"> in the first section still pulled the heavy commerce dep chain (commerce.js + autoblock.js) before MEP -- the opposite of the change's intent. Apply the same exclusion to authored blocks. Adds a test covering the authored-block path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
preloadLcpCodeFiles ran preloadBlockResources before MEP, which applied the
DEFAULT block stylesheet via loadStyle. For a block MEP redirects with
useBlockCode (e.g. marquee -> libs/mep/sample-block-code/marquee, whose css
is `body { color: purple }`), the default blocks/marquee/marquee.css
(`.marquee { color: var(--color-white) }`, higher specificity) then overrode
the custom styling -> text rendered white, failing the cross-browser
mep-actions useBlockCode test.
Add a warmStyles option to preloadBlockResources: when set, css is warmed as
`rel=preload as=style` instead of applied via loadStyle. preloadLcpCodeFiles
now passes it, so the pre-MEP path only warms resources (nothing applied) and
decoration applies the correct (MEP-redirected) sheet post-MEP. Unit test
asserts the css is preloaded, not stylesheet-applied.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review — PR #6643 (
|
mokimo
left a comment
There was a problem hiding this comment.
We ran over this in person conceptually, and I think the idea is great. Will be great to observe this in the real world and observe the LCP data accordingly
overmyheadandbody
left a comment
There was a problem hiding this comment.
Mostly looking good, I just have the placeholders note for now that might be worth looking into
|
|
||
| if (/{{|%7B%7B/.test(firstSection.innerHTML) && config.locale?.contentRoot) { | ||
| loadLink(`${base}/features/placeholders.js`, { rel: 'modulepreload', crossorigin: 'anonymous' }); | ||
| getPlaceholderPaths(config).forEach((path) => loadLink(path, { rel: 'preload', as: 'fetch' })); |
There was a problem hiding this comment.
I think this might also need a crossorigin value. Comparing the before / after links for the homepage surfaces that there's a new additional request to placeholder.json, which is likely redundant, this might be the place to address that.
There was a problem hiding this comment.
Confirmed and fixed - added crossorigin: 'anonymous' to that loadLink call. as=fetch preloads only get reused by a later same-URL fetch when crossorigin matches (which is exactly why the other pre-existing as: 'fetch' preload in this file already sets it); without it the browser treats the preload as a mismatched resource and double-fetches, which is the extra request you spotted. See #6662.
* fix(perf): address review feedback on MWPW-206311 pre-MEP LCP preload - add missing crossorigin to the placeholders.json preload link so the browser reuses it instead of double-fetching (overmyheadandbody) - decouple preloadLcpCodeFiles() from ?mep=off - it preloads ordinary block/icon/placeholder resources, not MEP-specific ones, so only its own kill switch should gate it (mokimo, zagi25) - anchor isCommerceBlock's merch alternative so a future block name containing "merch" as a substring isn't misclassified (mokimo) - drop the unused catch binding to match the file's own convention (overmyheadandbody) - note that the auto-block detector is intentionally approximate vs decorateAutoBlock (mokimo) * fix(perf): drop added comments; keep mep=off short-circuit as-is - no comments in libs/utils/utils.js, per repo convention - revert the preloadLcpCodeFiles()/mepParam==='off' ordering: when MEP is off there's no MEP/Target await to hide the preload behind, and the normal block-loading path already loads everything fast enough on its own, so this only needs to run when MEP is present
|
Follow-up on the nice-to-haves from my review above, now that #6662 merged into this branch:
Also fixed overmyheadandbody's crossorigin/redundant-request find and the unused catch binding - replied on those threads too. All green (215/215 |
…6663) fix(perf): drop JSDoc on getValidatedMasLibsUrl, no replacement comment zagi25 flagged this JSDoc as inconsistent with the rest of the PR (#6643). It was pre-existing code being relocated, not new authorship, but per repo convention libs/utils/utils.js carries no comments - dropping it outright rather than converting to a plain comment.
|
Reminder to set the |
What
Preload the first section's block code + non-commerce autoblocks + placeholder sheets + icons during the MEP/Target await in
loadArea, instead of after it, so the LCP element can start painting sooner. Commerce (merch/mas) autoblocks are excluded — their heavy dependency chain slows pages whose hero isn't a store block.Wins (measured on live www.adobe.com, Slow-4G + 4× CPU)
/creativecloud.html~80ms — follow-up).Full analysis + raw crawl data (zips): MWPW-206183.
Kill switch
Emergency opt-out (default is enabled):
<meta name="disable-mep-perf-optimization" content="on">skips the preload entirely. Works per-page or site-wide via the global metadata sheet.Test
To test performance you'll want to go to adobe.com pages and override the utils.js with the one in this PR.
You'll also want to test that pages still look the same (they should in theory and unit tests are all passing, but just to be safe)
Before: https://main--milo--adobecom.aem.page/?martech=off
After: https://vhargrave-lcp-blocks-only-pre-mep--milo--adobecom.aem.page/?martech=off
Before: https://main--upp--adobecom.aem.live/homepage/index-loggedout
After: https://main--upp--adobecom.aem.live/homepage/index-loggedout?milolibs=vhargrave-lcp-blocks-only-pre-mep
Before: http://main--da-cc--adobecom.aem.live/products/photoshop
After: http://main--da-cc--adobecom.aem.live/products/photoshop?milolibs=vhargrave-lcp-blocks-only-pre-mep
Before: https://main--da-dc--adobecom.aem.live/acrobat
After: https://main--da-dc--adobecom.aem.live/acrobat?milolibs=vhargrave-lcp-blocks-only-pre-mep
Before: https://main--da-express-milo--adobecom.aem.live/express/
After: https://main--da-express-milo--adobecom.aem.live/express/?milolibs=vhargrave-lcp-blocks-only-pre-mep
Resolves: MWPW-206311