fix(html): don't inline preload link targets (fix #13355) - #23387
fix(html): don't inline preload link targets (fix #13355)#23387kakiuwang-ui wants to merge 3 commits into
Conversation
A `<link rel="modulepreload">` whose target is smaller than `build.assetsInlineLimit` was rewritten to a `data:` URL. The browser fetches that data URL as a module distinct from the emitted chunk, so nothing referenced by the page is warmed and the preload is a no-op. Add `modulepreload` to `noInlineLinkRels` so these targets are always emitted as files, matching the existing handling for `icon` and `manifest` links. `preload`/`prefetch` links have the same problem but are left alone here; they interact with vitejs#16269 and need to be handled separately.
I think we can fix these together. Can you add them in this PR? |
Extend the previous commit to `rel="preload"` and `rel="prefetch"`, which are defeated by inlining for the same reason as `modulepreload`. `<link rel="preload" as="image" imagesrcset>` goes through the srcset branch, which called `processAssetUrl` without a `shouldInline` argument and so ignored `noInlineLinkRels` entirely. Hoist the no-inline decision out of the `src` branch so both use it. Also drop the comment above `noInlineLinkRels` per review.
|
Done — While adding them I found the fix wasn't complete for <link class="preload-imagesrcset" rel="preload" as="image"
imagesrcset="data:image/png;base64,iVBORw0KGgoAAAAN..." />So I hoisted the no-inline decision out of the Tests now cover One thing I did not touch: |
Description
A
<link rel="modulepreload">whose target is smaller thanbuild.assetsInlineLimitgets rewritten to adata:URL at build time:That data URL is a different module specifier from the emitted chunk, so the browser warms a module nothing else on the page will request. The preload becomes a silent no-op.
Cause
In
html.ts, alink[href]that isn't a CSS request falls through toprocessAssetUrl(url, shouldInline)withshouldInline === undefined, which leaves the decision to the default size heuristic. There is already anoInlineLinkRelsset for rels where inlining is wrong (icon,manifest, ...), andmodulepreloadbelongs in it for the same reason.Fix
Add
modulepreloadtonoInlineLinkRels.Scope
Covers
modulepreload,preloadandprefetch(preload/prefetchadded on review request).For
preloadthis needed one extra thing:<link rel="preload" as="image" imagesrcset>is handled by thesrcsetbranch, which calledprocessAssetUrlwithout ashouldInlineargument and so ignorednoInlineLinkRels. The no-inline decision is now hoisted out of thesrcbranch so both use it.<link rel="preload" as="style" href="x.css">is untouched — theisCSSRequestcheck above converts it into a CSS import before reaching this code.#13355 also mentions that the emitted file is the unminified original, i.e. it never went through the JS pipeline at all. That's a distinct problem (related: #9952) and isn't addressed here.
Tests
Added links to the
assetsplayground covering all four cases —modulepreloadhref,preloadhref,preloadimagesrcset,prefetchhref — pointing at files well under that playground'sassetsInlineLimit: 8000, so they are inlined without the fix.Each fails on
mainwith the reported symptom, e.g.:and passes with the fix, in both serve and build mode.
fix #13355