From 37f72fbb075b481de8263f62c77125333735f382 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Fri, 17 Jan 2025 18:27:32 +0800 Subject: [PATCH] fix: inline server stylesheets instead of client stylesheets (#13068) fixes #6720 This PR changes the inlined stylesheet from client to server so that the paths for imported assets in the CSS such as fonts are correct when the document first loads. In comparison, the client stylesheet links are relative by default, so they always link to the wrong place --- .changeset/sixty-days-think.md | 5 +++ .../src/exports/vite/build/build_server.js | 42 ++++++++++++++++--- packages/kit/test/apps/options/package.json | 1 + .../source/pages/inline-assets/+page.svelte | 11 +++++ packages/kit/test/apps/options/test/test.js | 16 +++++++ pnpm-lock.yaml | 8 ++++ 6 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 .changeset/sixty-days-think.md create mode 100644 packages/kit/test/apps/options/source/pages/inline-assets/+page.svelte diff --git a/.changeset/sixty-days-think.md b/.changeset/sixty-days-think.md new file mode 100644 index 000000000000..043f244a7962 --- /dev/null +++ b/.changeset/sixty-days-think.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: correctly link to assets inlined by the `inlineStyleThreshold` option diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 3e4adaf560bb..47a9484eb40f 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -3,6 +3,7 @@ import { mkdirp } from '../../../utils/filesystem.js'; import { find_deps, resolve_symlinks } from './utils.js'; import { s } from '../../../utils/misc.js'; import { normalizePath } from 'vite'; +import { basename } from 'node:path'; /** * @param {string} out @@ -17,18 +18,47 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli mkdirp(`${out}/server/nodes`); mkdirp(`${out}/server/stylesheets`); + /** @type {Map} */ const stylesheet_lookup = new Map(); if (css) { - css.forEach((asset) => { - if (asset.source.length < kit.inlineStyleThreshold) { - const index = stylesheet_lookup.size; - const file = `${out}/server/stylesheets/${index}.js`; + /** @type {Set} */ + const client_stylesheets = new Set(); + for (const key in client_manifest) { + const file = client_manifest[key]; + if (file.css?.[0]) { + client_stylesheets.add(file.css[0]); + } + } + + /** @type {Map} */ + const server_stylesheets = new Map(); - fs.writeFileSync(file, `// ${asset.fileName}\nexport default ${s(asset.source)};`); - stylesheet_lookup.set(asset.fileName, index); + const component_stylesheet_map = new Map(Object.values(server_manifest).map((file) => [file.src, file.css?.[0]])); + + manifest_data.nodes.forEach((node, i) => { + const server_stylesheet = component_stylesheet_map.get(node.component); + if (node.component && server_stylesheet) { + server_stylesheets.set(i, server_stylesheet); } }); + + // ignore dynamically imported stylesheets since we can't inline those + css.filter(asset => client_stylesheets.has(asset.fileName)) + .forEach((asset) => { + if (asset.source.length < kit.inlineStyleThreshold) { + const [index] = basename(asset.fileName).split('.'); + const server_stylesheet = server_stylesheets.get(+index); + const file = `${out}/server/stylesheets/${index}.js`; + + // we need to inline the server stylesheet instead of the client one + // so that asset paths are correct on document load + const source = fs.readFileSync(`${out}/server/${server_stylesheet}`, 'utf-8'); + + fs.writeFileSync(file, `// ${server_stylesheet}\nexport default ${s(source)};`); + stylesheet_lookup.set(asset.fileName, index); + } + }); } manifest_data.nodes.forEach((node, i) => { diff --git a/packages/kit/test/apps/options/package.json b/packages/kit/test/apps/options/package.json index c2df38711db6..6a2f5883f48f 100644 --- a/packages/kit/test/apps/options/package.json +++ b/packages/kit/test/apps/options/package.json @@ -13,6 +13,7 @@ "test:build": "playwright test" }, "devDependencies": { + "@fontsource/libre-barcode-128-text": "^5.1.0", "@sveltejs/kit": "workspace:^", "@sveltejs/vite-plugin-svelte": "^5.0.1", "cross-env": "^7.0.3", diff --git a/packages/kit/test/apps/options/source/pages/inline-assets/+page.svelte b/packages/kit/test/apps/options/source/pages/inline-assets/+page.svelte new file mode 100644 index 000000000000..8a017caa2622 --- /dev/null +++ b/packages/kit/test/apps/options/source/pages/inline-assets/+page.svelte @@ -0,0 +1,11 @@ + + +

Hello world!

+ + diff --git a/packages/kit/test/apps/options/test/test.js b/packages/kit/test/apps/options/test/test.js index 921c0ef913c1..3ce6b482e092 100644 --- a/packages/kit/test/apps/options/test/test.js +++ b/packages/kit/test/apps/options/test/test.js @@ -303,6 +303,22 @@ if (!process.env.DEV) { expect(await page.content()).not.toMatch('navigator.serviceWorker'); }); }); + + test.describe('inlineStyleThreshold', () => { + test('loads asset', async ({ page }) => { + let fontLoaded = false; + + page.on('response', (response) => { + if (response.url().endsWith('.woff2') || response.url().endsWith('.woff')) { + fontLoaded = response.ok(); + } + }); + + await page.goto('/path-base/inline-assets'); + + expect(fontLoaded).toBeTruthy(); + }); + }); } test.describe('Vite options', () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3988c1e69f71..aee018de1039 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -595,6 +595,9 @@ importers: packages/kit/test/apps/options: devDependencies: + '@fontsource/libre-barcode-128-text': + specifier: ^5.1.0 + version: 5.1.0 '@sveltejs/kit': specifier: workspace:^ version: link:../../.. @@ -1591,6 +1594,9 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + '@fontsource/libre-barcode-128-text@5.1.0': + resolution: {integrity: sha512-MC7foQFRT0NDcsqBWQua2T3gs/fh/uTowTxfoPqGQWjqroiMxRZhQh7jerjnpcI+Xi3yR5bwCo6W2uwCza1FRw==} + '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} @@ -4054,6 +4060,8 @@ snapshots: '@fastify/busboy@2.1.1': {} + '@fontsource/libre-barcode-128-text@5.1.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.3.0': {}