With inlineStyleThreshold set and paths.relative: false, CSS inlined into
<style> tags keeps its relative url() references (e.g.
url(./red-hat-mono-*.woff2)). The browser resolves those against the page URL
instead of the original stylesheet location, so fonts and other CSS assets 404.
pnpm install
pnpm verify # builds, then greps build/index.html for relative url()sExpected: url(/_app/immutable/assets/red-hat-mono-*.woff2)
Actual: url(./red-hat-mono-*.woff2) → resolves to /red-hat-mono-*.woff2 → 404
Minimal config (svelte.config.js):
kit: {
adapter: adapter(), // not adapter-specific; static just makes it easy to inspect
paths: { relative: false },
inlineStyleThreshold: 16384,
}Both options are required: with the default paths.relative: true, the inlined
URLs are rewritten correctly.
Tested by building this repro against each version:
@sveltejs/kit |
inlined url() |
|
|---|---|---|
| 2.50.1 – 2.64.0 | url(/_app/immutable/assets/…) |
works |
| 2.65.0 – 2.69.2 (latest) | url(./…) |
broken |
Two changes interact:
-
Since #15153 (kit 2.50.2), inlined client CSS is passed through
fix_css_urls(), but only behind this gate insrc/exports/vite/build/build_server.js(line 69 in 2.69.2):if (kit.paths.assets || kit.paths.relative) { prepare_css_for_inlining = (css, eager_assets) => { /* fix_css_urls(...) */ }; }
With
paths.relative: falseandpaths.assetsunset, the gate is false andprepare_css_for_inliningstays the identity function — relativeurl()s are inlined verbatim. -
That gate was harmless until #15936 (kit 2.65.0) switched the client build to Vite
base: './'plus arenderBuiltUrlhook. Before, a build withrelative: falseused an absolute base, so CSS assets already contained absoluteurl(/_app/…)and needed no fixing. Since 2.65.0, emitted CSS always contains relativeurl()s — fine for external stylesheets (they resolve against the CSS file), wrong for inlined ones. The gate now skips exactly the rewrite that is always needed.#16026 fixed another fallout of #15936 for
relative: falseapps (JS chunk paths, #16013) but did not touch the CSS-inlining path.
Making the rewrite unconditional (dropping the gate) fixes it: patching
node_modules/@sveltejs/kit/src/exports/vite/build/build_server.js to
if (true) and rebuilding produces url(/_app/immutable/assets/…). The
runtime ${assets}/${base} interpolation inside fix_css_urls already
handles the default empty values correctly.
- Keep the default
paths.relative: true, if the deployment allows it (not always possible, e.g. when a prerendered 404 page is served at any unknown path — GitHub Pages-style404.html, SPA fallbacks — where relative asset paths would resolve against the browser URL and break). - Remove
inlineStyleThreshold— external stylesheets resolve relativeurl()s correctly. paths.assetscannot help: kit's config validation only accepts''or a fully-qualifiedscheme://URL, i.e. an actual separate asset host.
- #15936 — introduced the regression in 2.65.0 (client build switched to relative base +
renderBuiltUrl) - #15153 — added the
kit.paths.assets || kit.paths.relativegate (2.50.2) - #16013 / #16026 — sibling regression of #15936, fixed for JS chunk paths only
- #6720 — 2022 issue with the same symptom, fixed back then by #13068 (an inlining approach later replaced)