From df7806210ac13af205491eedc4bf4d12ae93861c Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 28 Nov 2024 14:11:54 +0800 Subject: [PATCH 1/8] inline server stylesheets instead --- .../src/exports/vite/build/build_server.js | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index f13c29872e38..9f8bf9761103 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -19,12 +19,30 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli const stylesheet_lookup = new Map(); if (css) { - css.forEach((asset) => { - if (asset.source.length < kit.inlineStyleThreshold) { + /** @type {string[]} */ + const server_stylesheets = []; + for (const key in server_manifest) { + const file = server_manifest[key]; + if (file.css) { + server_stylesheets.push(...file.css); + } + } + + // sort the client stylesheets so they can be mapped to the server stylesheets + css.sort((a, b) => { + return a.originalFileNames[0].localeCompare(b.originalFileNames[0]); + }); + + css.forEach((asset, i) => { + if (server_stylesheets[i] && asset.source.length < kit.inlineStyleThreshold) { const index = stylesheet_lookup.size; const file = `${out}/server/stylesheets/${index}.js`; - fs.writeFileSync(file, `// ${asset.fileName}\nexport default ${s(asset.source)};`); + // 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_stylesheets[i]}`, 'utf-8'); + + fs.writeFileSync(file, `// ${asset.fileName}\nexport default ${s(source)};`); stylesheet_lookup.set(asset.fileName, index); } }); From 1153ebec47c526ebbf7c47174b26b0b196978051 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 28 Nov 2024 14:13:15 +0800 Subject: [PATCH 2/8] add changeset --- .changeset/sixty-days-think.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sixty-days-think.md 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 From 35305e63196ac92cf9b5d016b5c062c926b4b15d Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 28 Nov 2024 14:19:50 +0800 Subject: [PATCH 3/8] add optional chaining --- packages/kit/src/exports/vite/build/build_server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 9f8bf9761103..3b74d6326c33 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -30,7 +30,7 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli // sort the client stylesheets so they can be mapped to the server stylesheets css.sort((a, b) => { - return a.originalFileNames[0].localeCompare(b.originalFileNames[0]); + return a.originalFileNames[0]?.localeCompare(b.originalFileNames[0]); }); css.forEach((asset, i) => { From 6f565ffb4033178671384deffa45112554839f39 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 28 Nov 2024 14:41:15 +0800 Subject: [PATCH 4/8] add test --- 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 ++++++++ 4 files changed, 36 insertions(+) create mode 100644 packages/kit/test/apps/options/source/pages/inline-assets/+page.svelte diff --git a/packages/kit/test/apps/options/package.json b/packages/kit/test/apps/options/package.json index 2d13c0c82cce..430dcb1f1623 100644 --- a/packages/kit/test/apps/options/package.json +++ b/packages/kit/test/apps/options/package.json @@ -12,6 +12,7 @@ "test:build": "playwright test" }, "devDependencies": { + "@fontsource/libre-barcode-128-text": "^5.1.0", "@sveltejs/kit": "workspace:^", "@sveltejs/vite-plugin-svelte": "^3.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 0c80878cb9d1..7b09fff9510b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -568,6 +568,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:../../.. @@ -1551,6 +1554,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'} @@ -4232,6 +4238,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': {} From 1e238b7b8defc4f1aef81be03266226166de27ae Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 28 Nov 2024 14:57:12 +0800 Subject: [PATCH 5/8] fix sorting --- packages/kit/src/exports/vite/build/build_server.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 3b74d6326c33..833f549eac74 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -30,7 +30,10 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli // sort the client stylesheets so they can be mapped to the server stylesheets css.sort((a, b) => { - return a.originalFileNames[0]?.localeCompare(b.originalFileNames[0]); + if (a.originalFileNames[0] && b.originalFileNames[0]) { + return a.originalFileNames[0].localeCompare(b.originalFileNames[0]); + } + return a.fileName.localeCompare(b.fileName); }); css.forEach((asset, i) => { From d07651446964326b46b1b97df22abb45a457f43b Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 28 Nov 2024 15:45:37 +0800 Subject: [PATCH 6/8] more reliable mapping --- .../src/exports/vite/build/build_server.js | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 833f549eac74..917bec73f162 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -19,25 +19,31 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli const stylesheet_lookup = new Map(); if (css) { + /** @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 {string[]} */ const server_stylesheets = []; for (const key in server_manifest) { const file = server_manifest[key]; - if (file.css) { - server_stylesheets.push(...file.css); + if (file.css?.[0]) { + server_stylesheets.push(file.css[0]); } } + // we only inline stylesheets statically imported on pages and layouts + css.filter(asset => client_stylesheets.has(asset.fileName)) // sort the client stylesheets so they can be mapped to the server stylesheets - css.sort((a, b) => { - if (a.originalFileNames[0] && b.originalFileNames[0]) { - return a.originalFileNames[0].localeCompare(b.originalFileNames[0]); - } + .sort((a, b) => { return a.fileName.localeCompare(b.fileName); - }); - - css.forEach((asset, i) => { - if (server_stylesheets[i] && asset.source.length < kit.inlineStyleThreshold) { + }).forEach((asset, i) => { + if (asset.source.length < kit.inlineStyleThreshold) { const index = stylesheet_lookup.size; const file = `${out}/server/stylesheets/${index}.js`; From a9ba6454ed52eebd027a633aaea70211fbfce929 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 28 Nov 2024 15:46:50 +0800 Subject: [PATCH 7/8] comment --- packages/kit/src/exports/vite/build/build_server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 917bec73f162..5ac1f96d422d 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -37,7 +37,7 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli } } - // we only inline stylesheets statically imported on pages and layouts + // ignore dynamically imported stylesheets since we can't inline those css.filter(asset => client_stylesheets.has(asset.fileName)) // sort the client stylesheets so they can be mapped to the server stylesheets .sort((a, b) => { From 3b44f227d843999d62798eb4d994606484076917 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Tue, 24 Dec 2024 17:00:09 +0800 Subject: [PATCH 8/8] map server stylesheet to node index --- .../src/exports/vite/build/build_server.js | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 5068823b6e7c..c52d397b1e1d 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,11 +18,12 @@ 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) { /** @type {Set} */ - const client_stylesheets = new Set([]); + const client_stylesheets = new Set(); for (const key in client_manifest) { const file = client_manifest[key]; if (file.css?.[0]) { @@ -29,33 +31,34 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli } } - /** @type {string[]} */ - const server_stylesheets = []; - for (const key in server_manifest) { - const file = server_manifest[key]; - if (file.css?.[0]) { - server_stylesheets.push(file.css[0]); + /** @type {Map} */ + const server_stylesheets = new Map(); + + 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)) - // sort the client stylesheets so they can be mapped to the server stylesheets - .sort((a, b) => { - return a.fileName.localeCompare(b.fileName); - }).forEach((asset, i) => { - if (asset.source.length < kit.inlineStyleThreshold) { - const index = stylesheet_lookup.size; - 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_stylesheets[i]}`, 'utf-8'); - - fs.writeFileSync(file, `// ${asset.fileName}\nexport default ${s(source)};`); - stylesheet_lookup.set(asset.fileName, index); - } - }); + .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) => {