From ac639539c8860a797dfbba179ae49bb730b20f9a Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Mon, 12 Jan 2026 02:05:55 +0800 Subject: [PATCH 01/37] add fix and test format --- .../src/exports/vite/build/build_server.js | 81 ++++--------------- packages/kit/src/exports/vite/index.js | 4 +- .../kit/src/runtime/server/page/render.js | 8 +- packages/kit/src/utils/css.js | 11 +++ packages/kit/test/apps/options/package.json | 4 +- .../test/apps/options/playwright.config.js | 3 +- .../kit/test/apps/options/svelte.config.js | 3 +- packages/kit/test/apps/options/test/test.js | 80 +++++++++++------- 8 files changed, 91 insertions(+), 103 deletions(-) create mode 100644 packages/kit/src/utils/css.js diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 6a1e13fcc2b1..b282e09a82bc 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -5,6 +5,7 @@ import { s } from '../../../utils/misc.js'; import { normalizePath } from 'vite'; import { basename, join } from 'node:path'; import { create_node_analyser } from '../static_analysis/index.js'; +import { replace_css_relative_url } from '../../../utils/css.js'; /** * @param {string} out @@ -12,7 +13,7 @@ import { create_node_analyser } from '../static_analysis/index.js'; * @param {import('types').ManifestData} manifest_data * @param {import('vite').Manifest} server_manifest * @param {import('vite').Manifest | null} client_manifest - * @param {import('vite').Rollup.OutputBundle | null} server_bundle + * @param {string | null} assets_path * @param {import('vite').Rollup.RollupOutput['output'] | null} client_chunks * @param {import('types').RecursiveRequired} output_config * @param {Map | null, children: string[] }>} static_exports @@ -23,7 +24,7 @@ export async function build_server_nodes( manifest_data, server_manifest, client_manifest, - server_bundle, + assets_path, client_chunks, output_config, static_exports @@ -34,35 +35,16 @@ export async function build_server_nodes( /** @type {Map} */ const stylesheets_to_inline = new Map(); - if (server_bundle && client_chunks && kit.inlineStyleThreshold > 0) { - const client = get_stylesheets(client_chunks); - const server = get_stylesheets(Object.values(server_bundle)); - - // map server stylesheet name to the client stylesheet name - for (const [id, client_stylesheet] of client.stylesheets_used) { - const server_stylesheet = server.stylesheets_used.get(id); - if (!server_stylesheet) { + if (client_chunks && kit.inlineStyleThreshold > 0) { + for (const chunk of client_chunks) { + if (chunk.type !== 'asset' || !chunk.fileName.endsWith('.css')) { continue; } - client_stylesheet.forEach((file, i) => { - stylesheets_to_inline.set(file, server_stylesheet[i]); - }); - } - - // filter out stylesheets that should not be inlined - for (const [fileName, content] of client.stylesheet_content) { - if (content.length >= kit.inlineStyleThreshold) { - stylesheets_to_inline.delete(fileName); - } - } - // map server stylesheet source to the client stylesheet name - for (const [client_file, server_file] of stylesheets_to_inline) { - const source = server.stylesheet_content.get(server_file); - if (!source) { - throw new Error(`Server stylesheet source not found for client stylesheet ${client_file}`); + const source = chunk.source.toString(); + if (source.length < kit.inlineStyleThreshold) { + stylesheets_to_inline.set(chunk.fileName, source); } - stylesheets_to_inline.set(client_file, source); } } @@ -187,11 +169,14 @@ export async function build_server_nodes( if (stylesheets_to_inline.has(file)) { const filename = basename(file); const dest = `${out}/server/stylesheets/${filename}.js`; - const source = stylesheets_to_inline.get(file); - if (!source) { - throw new Error(`Server stylesheet source not found for client stylesheet ${file}`); + + let contents = /** @type {string} */ (stylesheets_to_inline.get(file)); + + if (kit.paths.assets) { + contents = replace_css_relative_url(contents, `${kit.paths.assets}/${assets_path}`); } - fs.writeFileSync(dest, `// ${filename}\nexport default ${s(source)};`); + + fs.writeFileSync(dest, `// ${filename}\nexport default ${s(contents)};`); const name = `stylesheet_${i}`; imports.push(`import ${name} from '../stylesheets/${filename}.js';`); @@ -209,37 +194,3 @@ export async function build_server_nodes( ); } } - -/** - * @param {(import('vite').Rollup.OutputAsset | import('vite').Rollup.OutputChunk)[]} chunks - */ -function get_stylesheets(chunks) { - /** - * A map of module IDs and the stylesheets they use. - * @type {Map} - */ - const stylesheets_used = new Map(); - - /** - * A map of stylesheet names and their content. - * @type {Map} - */ - const stylesheet_content = new Map(); - - for (const chunk of chunks) { - if (chunk.type === 'asset') { - if (chunk.fileName.endsWith('.css')) { - stylesheet_content.set(chunk.fileName, chunk.source.toString()); - } - continue; - } - - if (chunk.viteMetadata?.importedCss.size) { - const css = Array.from(chunk.viteMetadata.importedCss); - for (const id of chunk.moduleIds) { - stylesheets_used.set(id, css); - } - } - } - return { stylesheets_used, stylesheet_content }; -} diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 220942a4aba4..8783da4b2b1a 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -1021,7 +1021,7 @@ async function kit({ svelte_config }) { */ writeBundle: { sequential: true, - async handler(_options, bundle) { + async handler(_options) { if (secondary_build_started) return; // only run this once const verbose = vite_config.logLevel === 'info'; @@ -1261,7 +1261,7 @@ async function kit({ svelte_config }) { manifest_data, server_manifest, client_manifest, - bundle, + assets_path, client_chunks, svelte_config.kit.output, static_exports diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index 6163610a6a29..2f5946236de3 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -17,6 +17,7 @@ import { try_get_request_store, with_request_store } from '@sveltejs/kit/interna import { text_encoder } from '../../utils.js'; import { get_global_name } from '../utils.js'; import { create_remote_key } from '../../shared.js'; +import { replace_css_relative_url } from '../../../utils/css.js'; // TODO rename this function/module @@ -245,7 +246,12 @@ export async function render_response({ for (const url of node.fonts) fonts.add(url); if (node.inline_styles && !client.inline) { - Object.entries(await node.inline_styles()).forEach(([k, v]) => inline_styles.set(k, v)); + Object.entries(await node.inline_styles()).forEach(([k, v]) => { + if (paths.relative) { + v = replace_css_relative_url(v, `${assets}/${paths.app_dir}/immutable/assets`); + } + inline_styles.set(k, v); + }); } } } else { diff --git a/packages/kit/src/utils/css.js b/packages/kit/src/utils/css.js new file mode 100644 index 000000000000..8ccbcbd88340 --- /dev/null +++ b/packages/kit/src/utils/css.js @@ -0,0 +1,11 @@ +/** + * Vite's static asset handling for the client changes the asset URLs in a CSS + * file to start with `./`. This is incorrect if we're inlining the CSS or if + * `paths.assets` is set. This function helps us rewrite the URLs in the CSS. + * @param {string} contents + * @param {string} base + * @returns {string} + */ +export function replace_css_relative_url(contents, base) { + return contents.replaceAll(/url\((['"]?)\.\//g, `url($1${base}/`); +} diff --git a/packages/kit/test/apps/options/package.json b/packages/kit/test/apps/options/package.json index f522875e5a92..04ce65e2a148 100644 --- a/packages/kit/test/apps/options/package.json +++ b/packages/kit/test/apps/options/package.json @@ -9,8 +9,8 @@ "prepare": "svelte-kit sync", "check": "svelte-kit sync && tsc && svelte-check", "test": "pnpm test:dev && pnpm test:build", - "test:dev": "DEV=true playwright test", - "test:build": "playwright test", + "test:dev": "DEV=true playwright test && DEV=true PATHS_ASSETS=https://cdn.example.com/stuff playwright test", + "test:build": "playwright test && PATHS_ASSETS=https://cdn.example.com/stuff playwright test", "test:server-side-route-resolution:dev": "rm -rf test/errors.json && DEV=true ROUTER_RESOLUTION=server playwright test", "test:server-side-route-resolution:build": "rm -rf test/errors.json && ROUTER_RESOLUTION=server playwright test" }, diff --git a/packages/kit/test/apps/options/playwright.config.js b/packages/kit/test/apps/options/playwright.config.js index 2122f9ef8734..cdb691f211a8 100644 --- a/packages/kit/test/apps/options/playwright.config.js +++ b/packages/kit/test/apps/options/playwright.config.js @@ -8,7 +8,8 @@ export default defineConfig({ ...config.webServer, command: process.env.DEV ? `pnpm dev` : `pnpm build && pnpm preview`, env: { - ROUTER_RESOLUTION: process.env.ROUTER_RESOLUTION ?? 'client' + ROUTER_RESOLUTION: process.env.ROUTER_RESOLUTION ?? 'client', + PATHS_ASSETS: process.env.PATHS_ASSETS ?? '' } } }); diff --git a/packages/kit/test/apps/options/svelte.config.js b/packages/kit/test/apps/options/svelte.config.js index d2e4c2c452cf..1b9c193d6e0b 100644 --- a/packages/kit/test/apps/options/svelte.config.js +++ b/packages/kit/test/apps/options/svelte.config.js @@ -31,7 +31,8 @@ const config = { }, paths: { base: '/path-base', - assets: 'https://cdn.example.com/stuff' + // @ts-expect-error our env var string can't match the https template literal + assets: process.env.PATHS_ASSETS || '' }, env: { dir: './env-dir', diff --git a/packages/kit/test/apps/options/test/test.js b/packages/kit/test/apps/options/test/test.js index 8148bf7ed8f0..8bd69d2bd968 100644 --- a/packages/kit/test/apps/options/test/test.js +++ b/packages/kit/test/apps/options/test/test.js @@ -8,6 +8,8 @@ import { test } from '../../../utils.js'; test.describe.configure({ mode: 'parallel' }); test.describe('base path', () => { + test.skip(!!process.env.PATHS_ASSETS); + test('serves a useful 404 when visiting unprefixed path', async ({ request }) => { const html = await request.get('/slash/', { headers: { Accept: 'text/html' } }); expect(html.status()).toBe(404); @@ -103,6 +105,8 @@ test.describe('base path', () => { }); test.describe('assets path', () => { + test.skip(!process.env.PATHS_ASSETS); + test('serves static assets with correct prefix', async ({ page, request }) => { await page.goto('/path-base/'); const href = await page.locator('link[rel="icon"]').getAttribute('href'); @@ -113,6 +117,8 @@ test.describe('assets path', () => { }); test.describe('CSP', () => { + test.skip(!!process.env.PATHS_ASSETS); + test('blocks script from external site', async ({ page, start_server }) => { const { port } = await start_server((req, res) => { if (req.url === '/blocked.js') { @@ -148,6 +154,8 @@ test.describe('CSP', () => { }); test.describe('Custom extensions', () => { + test.skip(!!process.env.PATHS_ASSETS); + test('works with arbitrary extensions', async ({ page }) => { await page.goto('/path-base/custom-extensions/'); expect(await page.textContent('h2')).toBe('Great success!'); @@ -172,6 +180,8 @@ test.describe('Custom extensions', () => { }); test.describe('env', () => { + test.skip(!!process.env.PATHS_ASSETS); + test('resolves downwards', async ({ page }) => { await page.goto('/path-base/env'); expect(await page.textContent('#public')).toBe('and thank you'); @@ -184,6 +194,8 @@ test.describe('env', () => { }); test.describe('trailingSlash', () => { + test.skip(!!process.env.PATHS_ASSETS); + test('adds trailing slash', async ({ baseURL, page, clicknav }) => { // we can't use Playwright's `request` here, because it resolves redirects const status = await new Promise((fulfil, reject) => { @@ -296,45 +308,47 @@ test.describe('trailingSlash', () => { }); }); -if (!process.env.DEV) { - test.describe('serviceWorker', () => { - test('does not register service worker if none created', async ({ page }) => { - await page.goto('/path-base/'); - expect(await page.content()).not.toMatch('navigator.serviceWorker'); - }); +test.describe('serviceWorker', () => { + test.skip(!!process.env.PATHS_ASSETS || !!process.env.DEV); + + test('does not register service worker if none created', async ({ page }) => { + await page.goto('/path-base/'); + expect(await page.content()).not.toMatch('navigator.serviceWorker'); }); +}); - test.describe('inlineStyleThreshold', () => { - test('loads assets', 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('inlineStyleThreshold', () => { + test('loads assets', 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('includes components dynamically imported in universal load', async ({ - page, - get_computed_style - }) => { - let loaded_css = false; - page.on('response', (response) => { - if (response.url().endsWith('.css')) { - loaded_css = true; - } - }); - await page.goto('/path-base/inline-assets/dynamic-import'); - await expect(page.locator('p')).toHaveText("I'm dynamically imported"); - expect(loaded_css).toBe(false); - expect(await get_computed_style('p', 'color')).toEqual('rgb(0, 0, 255)'); + test('includes components dynamically imported in universal load', async ({ + page, + get_computed_style + }) => { + let loaded_css = false; + page.on('response', (response) => { + if (response.url().endsWith('.css')) { + loaded_css = true; + } }); + await page.goto('/path-base/inline-assets/dynamic-import'); + await expect(page.locator('p')).toHaveText("I'm dynamically imported"); + expect(loaded_css).toBe(false); + expect(await get_computed_style('p', 'color')).toEqual('rgb(0, 0, 255)'); }); -} +}); test.describe('Vite options', () => { + test.skip(!!process.env.PATHS_ASSETS); + test('Respects --mode', async ({ page }) => { await page.goto('/path-base/mode'); @@ -344,6 +358,8 @@ test.describe('Vite options', () => { }); test.describe('Routing', () => { + test.skip(!!process.env.PATHS_ASSETS); + test('ignores clicks outside the app target', async ({ page }) => { await page.goto('/path-base/routing/link-outside-app-target/source/'); @@ -353,6 +369,8 @@ test.describe('Routing', () => { }); test.describe('Async', () => { + test.skip(!!process.env.PATHS_ASSETS); + test("updates the DOM before onNavigate's promise is resolved", async ({ page, javaScriptEnabled From 2f60ab4e44301ce5a9e2aed4b77b93efce6dfd93 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Mon, 12 Jan 2026 02:18:55 +0800 Subject: [PATCH 02/37] add unit test --- packages/kit/src/utils/css.spec.js | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 packages/kit/src/utils/css.spec.js diff --git a/packages/kit/src/utils/css.spec.js b/packages/kit/src/utils/css.spec.js new file mode 100644 index 000000000000..eb529124df26 --- /dev/null +++ b/packages/kit/src/utils/css.spec.js @@ -0,0 +1,55 @@ +import { assert, describe, test } from 'vitest'; +import { replace_css_relative_url } from './css.js'; + +describe('replace_css_relative_url', () => { + test('replaces relative url with base path', () => { + assert.equal(replace_css_relative_url('url(./image.png)', '/assets'), 'url(/assets/image.png)'); + }); + + test('handles single-quoted urls', () => { + assert.equal( + replace_css_relative_url("url('./image.png')", '/assets'), + "url('/assets/image.png')" + ); + }); + + test('handles double-quoted urls', () => { + assert.equal( + replace_css_relative_url('url("./image.png")', '/assets'), + 'url("/assets/image.png")' + ); + }); + + test('replaces multiple relative urls', () => { + const input = ` + background: url(./bg.png); + border-image: url('./border.svg'); + mask: url("./mask.png"); + `; + const expected = ` + background: url(/assets/bg.png); + border-image: url('/assets/border.svg'); + mask: url("/assets/mask.png"); + `; + assert.equal(replace_css_relative_url(input, '/assets'), expected); + }); + + test('does not replace non-relative urls', () => { + assert.equal( + replace_css_relative_url('url(/absolute/image.png)', '/assets'), + 'url(/absolute/image.png)' + ); + assert.equal( + replace_css_relative_url('url(https://example.com/image.png)', '/assets'), + 'url(https://example.com/image.png)' + ); + assert.equal( + replace_css_relative_url('url(data:image/png;base64,abc)', '/assets'), + 'url(data:image/png;base64,abc)' + ); + }); + + test('does not replace parent directory urls', () => { + assert.equal(replace_css_relative_url('url(../image.png)', '/assets'), 'url(../image.png)'); + }); +}); From 251e4c8ebac14568af149e52d55fdce2d12511d8 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Mon, 12 Jan 2026 02:22:08 +0800 Subject: [PATCH 03/37] changeset --- .changeset/brave-guests-hope.md | 5 +++++ .changeset/shy-tables-shout.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/brave-guests-hope.md create mode 100644 .changeset/shy-tables-shout.md diff --git a/.changeset/brave-guests-hope.md b/.changeset/brave-guests-hope.md new file mode 100644 index 000000000000..d21af1c05f24 --- /dev/null +++ b/.changeset/brave-guests-hope.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: ensure inlined CSS follows `paths.assets` and `paths.relative` settings diff --git a/.changeset/shy-tables-shout.md b/.changeset/shy-tables-shout.md new file mode 100644 index 000000000000..ce5bc8a09e6d --- /dev/null +++ b/.changeset/shy-tables-shout.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: ensure CSS inlining includes components that are conditionally rendered From 885a5c80b6ef37fd8137c16b20eb74eb6ef880a0 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Mon, 12 Jan 2026 02:47:19 +0800 Subject: [PATCH 04/37] add test for inlining conditionally rendered component css --- .../conditional-rendering/+page.svelte | 19 +++++ .../conditional-rendering/Component.svelte | 7 ++ packages/kit/test/apps/options/test/test.js | 72 +++++++++++-------- 3 files changed, 69 insertions(+), 29 deletions(-) create mode 100644 packages/kit/test/apps/options/source/pages/inline-assets/conditional-rendering/+page.svelte create mode 100644 packages/kit/test/apps/options/source/pages/inline-assets/conditional-rendering/Component.svelte diff --git a/packages/kit/test/apps/options/source/pages/inline-assets/conditional-rendering/+page.svelte b/packages/kit/test/apps/options/source/pages/inline-assets/conditional-rendering/+page.svelte new file mode 100644 index 000000000000..5d6236bc267b --- /dev/null +++ b/packages/kit/test/apps/options/source/pages/inline-assets/conditional-rendering/+page.svelte @@ -0,0 +1,19 @@ + + +

This is always rendered

+ + + +{#if show} + +{/if} + + diff --git a/packages/kit/test/apps/options/source/pages/inline-assets/conditional-rendering/Component.svelte b/packages/kit/test/apps/options/source/pages/inline-assets/conditional-rendering/Component.svelte new file mode 100644 index 000000000000..4c4b86b21612 --- /dev/null +++ b/packages/kit/test/apps/options/source/pages/inline-assets/conditional-rendering/Component.svelte @@ -0,0 +1,7 @@ +

This is conditionally rendered

+ + diff --git a/packages/kit/test/apps/options/test/test.js b/packages/kit/test/apps/options/test/test.js index 8bd69d2bd968..e62c0f16e0d3 100644 --- a/packages/kit/test/apps/options/test/test.js +++ b/packages/kit/test/apps/options/test/test.js @@ -8,7 +8,7 @@ import { test } from '../../../utils.js'; test.describe.configure({ mode: 'parallel' }); test.describe('base path', () => { - test.skip(!!process.env.PATHS_ASSETS); + test.skip(!process.env.PATHS_ASSETS); test('serves a useful 404 when visiting unprefixed path', async ({ request }) => { const html = await request.get('/slash/', { headers: { Accept: 'text/html' } }); @@ -36,15 +36,13 @@ test.describe('base path', () => { ); }); - if (process.env.DEV) { - test('serves files in source directory', async ({ request, javaScriptEnabled }) => { - if (!javaScriptEnabled) return; + test('serves files in source directory', async ({ request, javaScriptEnabled }) => { + test.skip(!process.env.DEV || !javaScriptEnabled); - const response = await request.get('/path-base/source/pages/test.txt'); - expect(response.ok()).toBe(true); - expect(await response.text()).toBe('hello there world\n'); - }); - } + const response = await request.get('/path-base/source/pages/test.txt'); + expect(response.ok()).toBe(true); + expect(await response.text()).toBe('hello there world\n'); + }); test('paths available on server side', async ({ page }) => { await page.goto('/path-base/base/'); @@ -67,26 +65,6 @@ test.describe('base path', () => { expect(await get_computed_style('p', 'color')).toBe('rgb(255, 0, 0)'); }); - test('inlines CSS', async ({ page, javaScriptEnabled }) => { - await page.goto('/path-base/base/'); - if (process.env.DEV) { - const ssr_style = await page.$('style[data-sveltekit]'); - - if (javaScriptEnabled) { - // diff --git a/packages/kit/test/apps/options/test/test.js b/packages/kit/test/apps/options/test/test.js index 36d9e569c74b..07e036ba1aa5 100644 --- a/packages/kit/test/apps/options/test/test.js +++ b/packages/kit/test/apps/options/test/test.js @@ -316,17 +316,30 @@ test.describe('inlineStyleThreshold', () => { } }); - test('loads assets', async ({ page }) => { - test.skip(!!process.env.DEV); + test('loads assets', async ({ page, javaScriptEnabled }) => { + test.skip(!!process.env.DEV || javaScriptEnabled); - let fontLoaded = false; + let font_loaded = false; page.on('response', (response) => { if (response.url().endsWith('.woff2') || response.url().endsWith('.woff')) { - fontLoaded = response.ok(); + font_loaded = response.ok(); + } + }); + await page.goto('/path-base/inline-style'); + expect(font_loaded).toBeTruthy(); + }); + + test('loads assets located in static directory', async ({ page, javaScriptEnabled }) => { + test.skip(!!process.env.DEV || javaScriptEnabled); + + let image_loaded = false; + page.on('response', (response) => { + if (response.url().endsWith('favicon.png?v=1')) { + image_loaded = response.ok(); } }); - await page.goto('/path-base/inline-assets'); - expect(fontLoaded).toBeTruthy(); + await page.goto('/path-base/inline-style/static-dir'); + expect(image_loaded).toBeTruthy(); }); test('includes components dynamically imported in universal load', async ({ @@ -341,20 +354,20 @@ test.describe('inlineStyleThreshold', () => { loaded_css = true; } }); - await page.goto('/path-base/inline-assets/dynamic-import'); + await page.goto('/path-base/inline-style/dynamic-import'); await expect(page.locator('p')).toHaveText("I'm dynamically imported"); expect(loaded_css).toBe(false); expect(await get_computed_style('p', 'color')).toEqual('rgb(0, 0, 255)'); }); - test('inlines conditionally rendered component styles', async ({ + test('includes conditionally rendered component styles', async ({ page, get_computed_style, javaScriptEnabled }) => { test.skip(!!process.env.DEV || !javaScriptEnabled); - await page.goto('/path-base/inline-assets/conditional-rendering'); + await page.goto('/path-base/inline-style/conditional-rendering'); await expect(page.locator('#always')).toBeVisible(); expect(await get_computed_style('#always', 'color')).toBe('rgb(255, 0, 0)'); diff --git a/packages/kit/test/apps/options/vite.custom.config.js b/packages/kit/test/apps/options/vite.custom.config.js index 69200cdb7cd8..74a16f7f1ab2 100644 --- a/packages/kit/test/apps/options/vite.custom.config.js +++ b/packages/kit/test/apps/options/vite.custom.config.js @@ -4,7 +4,8 @@ import { sveltekit } from '@sveltejs/kit/vite'; /** @type {import('vite').UserConfig} */ const config = { build: { - minify: false + minify: false, + assetsInlineLimit: 0 }, clearScreen: false, plugins: [sveltekit()], From b457b970fcc57404e0386c2f74d8fbec7e370e74 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Thu, 22 Jan 2026 23:56:49 +0800 Subject: [PATCH 11/37] bump svelte --- pnpm-lock.yaml | 308 ++++++++++++++++++++++---------------------- pnpm-workspace.yaml | 2 +- 2 files changed, 155 insertions(+), 155 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82883c4d964b..be663be84c07 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -91,8 +91,8 @@ catalogs: specifier: ^3.0.0 version: 3.0.0 svelte: - specifier: ^5.46.4 - version: 5.46.4 + specifier: ^5.48.0 + version: 5.48.0 svelte-check: specifier: ^4.3.4 version: 4.3.4 @@ -127,7 +127,7 @@ importers: version: 1.56.0 '@sveltejs/eslint-config': specifier: 'catalog:' - version: 8.2.0(@stylistic/eslint-plugin-js@2.1.0(eslint@9.34.0(jiti@2.4.2)))(eslint-config-prettier@9.1.0(eslint@9.34.0(jiti@2.4.2)))(eslint-plugin-n@17.16.1(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3))(eslint-plugin-svelte@3.9.3(eslint@9.34.0(jiti@2.4.2))(svelte@5.46.4)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(eslint@9.34.0(jiti@2.4.2))(typescript-eslint@8.43.0(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3))(typescript@5.8.3) + version: 8.2.0(@stylistic/eslint-plugin-js@2.1.0(eslint@9.34.0(jiti@2.4.2)))(eslint-config-prettier@9.1.0(eslint@9.34.0(jiti@2.4.2)))(eslint-plugin-n@17.16.1(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3))(eslint-plugin-svelte@3.9.3(eslint@9.34.0(jiti@2.4.2))(svelte@5.48.0)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(eslint@9.34.0(jiti@2.4.2))(typescript-eslint@8.43.0(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3))(typescript@5.8.3) '@svitejs/changesets-changelog-github-compact': specifier: 'catalog:' version: 1.2.0 @@ -139,7 +139,7 @@ importers: version: 3.6.0 prettier-plugin-svelte: specifier: ^3.4.0 - version: 3.4.0(prettier@3.6.0)(svelte@5.46.4) + version: 3.4.0(prettier@3.6.0)(svelte@5.48.0) typescript-eslint: specifier: 'catalog:' version: 8.43.0(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3) @@ -151,7 +151,7 @@ importers: version: link:../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) '@types/node': specifier: 'catalog:' version: 18.19.119 @@ -200,13 +200,13 @@ importers: version: link:../../../../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) server-side-dep: specifier: file:server-side-dep version: file:packages/adapter-cloudflare/test/apps/pages/server-side-dep svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 vite: specifier: 'catalog:' version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) @@ -221,13 +221,13 @@ importers: version: link:../../../../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) server-side-dep: specifier: file:server-side-dep version: file:packages/adapter-cloudflare/test/apps/workers/server-side-dep svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 vite: specifier: 'catalog:' version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) @@ -276,7 +276,7 @@ importers: version: link:../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) '@types/node': specifier: 'catalog:' version: 18.19.119 @@ -300,10 +300,10 @@ importers: version: link:../../../../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 vite: specifier: 'catalog:' version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) @@ -315,10 +315,10 @@ importers: version: link:../../../../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 vite: specifier: 'catalog:' version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) @@ -346,7 +346,7 @@ importers: version: link:../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) '@types/node': specifier: 'catalog:' version: 18.19.119 @@ -373,7 +373,7 @@ importers: version: link:../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) '@types/node': specifier: 'catalog:' version: 18.19.119 @@ -382,7 +382,7 @@ importers: version: 3.0.2 svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 typescript: specifier: ^5.3.3 version: 5.8.3 @@ -397,13 +397,13 @@ importers: version: link:../../../../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) sirv-cli: specifier: 'catalog:' version: 3.0.0 svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 vite: specifier: 'catalog:' version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) @@ -415,13 +415,13 @@ importers: version: link:../../../../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) sirv-cli: specifier: 'catalog:' version: 3.0.0 svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 vite: specifier: 'catalog:' version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) @@ -440,7 +440,7 @@ importers: version: link:../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) '@types/node': specifier: 'catalog:' version: 18.19.119 @@ -470,7 +470,7 @@ importers: version: 0.34.4 svelte-parse-markup: specifier: ^0.1.5 - version: 0.1.5(svelte@5.46.4) + version: 0.1.5(svelte@5.48.0) vite-imagetools: specifier: ^9.0.2 version: 9.0.2(rollup@4.50.1) @@ -480,7 +480,7 @@ importers: devDependencies: '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) '@types/estree': specifier: 'catalog:' version: 1.0.8 @@ -492,7 +492,7 @@ importers: version: 4.50.1 svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 typescript: specifier: ^5.6.3 version: 5.8.3 @@ -513,10 +513,10 @@ importers: version: link:../../../../kit '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 vite: specifier: 'catalog:' version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) @@ -571,7 +571,7 @@ importers: version: 1.56.0 '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) '@types/connect': specifier: 'catalog:' version: 3.4.38 @@ -589,10 +589,10 @@ importers: version: 4.50.1 svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-preprocess: specifier: 'catalog:' - version: 6.0.0(postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(postcss@8.5.6)(svelte@5.46.4)(typescript@5.8.3) + version: 6.0.0(postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(postcss@8.5.6)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.3.3 version: 5.8.3 @@ -613,16 +613,16 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) dropcss: specifier: 'catalog:' version: 1.0.16 svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -637,13 +637,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -670,16 +670,16 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) '@vitest/browser-playwright': specifier: 'catalog:' version: 4.0.16(playwright@1.56.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))(vitest@4.0.16) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) test-redirect-importer: specifier: workspace:* version: link:../../../../test-redirect-importer @@ -703,7 +703,7 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) e2e-test-dep-error: specifier: file:./_test_dependencies/cjs-only version: e2e-test-dep-cjs-only@file:packages/kit/test/apps/dev-only/_test_dependencies/cjs-only @@ -736,10 +736,10 @@ importers: version: e2e-test-dep-cjs-only@file:packages/kit/test/apps/dev-only/_test_dependencies/cjs-only svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -754,13 +754,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -775,13 +775,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -796,13 +796,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -820,13 +820,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -844,13 +844,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -871,13 +871,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -892,13 +892,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -913,13 +913,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -943,13 +943,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -967,13 +967,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -991,13 +991,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1015,13 +1015,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1036,13 +1036,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1057,13 +1057,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1078,13 +1078,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1099,13 +1099,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1120,13 +1120,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1141,13 +1141,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1162,13 +1162,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1183,13 +1183,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1204,13 +1204,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1225,13 +1225,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1246,13 +1246,13 @@ importers: version: link:../../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1267,13 +1267,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1291,13 +1291,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1315,13 +1315,13 @@ importers: version: link:../../.. '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.4 version: 5.8.3 @@ -1348,11 +1348,11 @@ importers: version: 7.7.3 svelte2tsx: specifier: ~0.7.33 - version: 0.7.33(svelte@5.46.4)(typescript@5.8.3) + version: 0.7.33(svelte@5.48.0)(typescript@5.8.3) devDependencies: '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) '@types/node': specifier: 'catalog:' version: 18.19.119 @@ -1364,10 +1364,10 @@ importers: version: 3.6.0 svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-preprocess: specifier: 'catalog:' - version: 6.0.0(postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(postcss@8.5.6)(svelte@5.46.4)(typescript@5.8.3) + version: 6.0.0(postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(postcss@8.5.6)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.3.3 version: 5.8.3 @@ -1415,22 +1415,22 @@ importers: version: link:../../packages/package '@sveltejs/vite-plugin-svelte': specifier: 'catalog:' - version: 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) prettier: specifier: ^3.3.2 version: 3.6.0 prettier-plugin-svelte: specifier: ^3.2.6 - version: 3.4.0(prettier@3.6.0)(svelte@5.46.4) + version: 3.4.0(prettier@3.6.0)(svelte@5.48.0) publint: specifier: 'catalog:' version: 0.3.0 svelte: specifier: 'catalog:' - version: 5.46.4 + version: 5.48.0 svelte-check: specifier: 'catalog:' - version: 4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3) + version: 4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3) typescript: specifier: ^5.5.0 version: 5.8.3 @@ -5534,8 +5534,8 @@ packages: svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 typescript: ^4.9.4 || ^5.0.0 - svelte@5.46.4: - resolution: {integrity: sha512-VJwdXrmv9L8L7ZasJeWcCjoIuMRVbhuxbss0fpVnR8yorMmjNDwcjIH08vS6wmSzzzgAG5CADQ1JuXPS2nwt9w==} + svelte@5.48.0: + resolution: {integrity: sha512-+NUe82VoFP1RQViZI/esojx70eazGF4u0O/9ucqZ4rPcOZD+n5EVp17uYsqwdzjUjZyTpGKunHbDziW6AIAVkQ==} engines: {node: '>=18'} svgo@4.0.0: @@ -7671,34 +7671,34 @@ snapshots: dependencies: acorn: 8.15.0 - '@sveltejs/eslint-config@8.2.0(@stylistic/eslint-plugin-js@2.1.0(eslint@9.34.0(jiti@2.4.2)))(eslint-config-prettier@9.1.0(eslint@9.34.0(jiti@2.4.2)))(eslint-plugin-n@17.16.1(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3))(eslint-plugin-svelte@3.9.3(eslint@9.34.0(jiti@2.4.2))(svelte@5.46.4)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(eslint@9.34.0(jiti@2.4.2))(typescript-eslint@8.43.0(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3))(typescript@5.8.3)': + '@sveltejs/eslint-config@8.2.0(@stylistic/eslint-plugin-js@2.1.0(eslint@9.34.0(jiti@2.4.2)))(eslint-config-prettier@9.1.0(eslint@9.34.0(jiti@2.4.2)))(eslint-plugin-n@17.16.1(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3))(eslint-plugin-svelte@3.9.3(eslint@9.34.0(jiti@2.4.2))(svelte@5.48.0)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(eslint@9.34.0(jiti@2.4.2))(typescript-eslint@8.43.0(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3))(typescript@5.8.3)': dependencies: '@stylistic/eslint-plugin-js': 2.1.0(eslint@9.34.0(jiti@2.4.2)) eslint: 9.34.0(jiti@2.4.2) eslint-config-prettier: 9.1.0(eslint@9.34.0(jiti@2.4.2)) eslint-plugin-n: 17.16.1(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3) - eslint-plugin-svelte: 3.9.3(eslint@9.34.0(jiti@2.4.2))(svelte@5.46.4)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)) + eslint-plugin-svelte: 3.9.3(eslint@9.34.0(jiti@2.4.2))(svelte@5.48.0)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)) globals: 15.15.0 typescript: 5.8.3 typescript-eslint: 8.43.0(eslint@9.34.0(jiti@2.4.2))(typescript@5.8.3) - '@sveltejs/vite-plugin-svelte-inspector@5.0.0-next.0(@sveltejs/vite-plugin-svelte@6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)))(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))': + '@sveltejs/vite-plugin-svelte-inspector@5.0.0-next.0(@sveltejs/vite-plugin-svelte@6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)))(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte': 6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) debug: 4.4.3 - svelte: 5.46.4 + svelte: 5.48.0 vite: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))': + '@sveltejs/vite-plugin-svelte@6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.0-next.0(@sveltejs/vite-plugin-svelte@6.0.0-next.3(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)))(svelte@5.46.4)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte-inspector': 5.0.0-next.0(@sveltejs/vite-plugin-svelte@6.0.0-next.3(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)))(svelte@5.48.0)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) debug: 4.4.3 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.21 - svelte: 5.46.4 + svelte: 5.48.0 vite: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) vitefu: 1.1.1(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) transitivePeerDependencies: @@ -8725,7 +8725,7 @@ snapshots: - supports-color - typescript - eslint-plugin-svelte@3.9.3(eslint@9.34.0(jiti@2.4.2))(svelte@5.46.4)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)): + eslint-plugin-svelte@3.9.3(eslint@9.34.0(jiti@2.4.2))(svelte@5.48.0)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.34.0(jiti@2.4.2)) '@jridgewell/sourcemap-codec': 1.5.5 @@ -8737,9 +8737,9 @@ snapshots: postcss-load-config: 3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)) postcss-safe-parser: 7.0.1(postcss@8.5.6) semver: 7.7.3 - svelte-eslint-parser: 1.4.1(svelte@5.46.4) + svelte-eslint-parser: 1.4.1(svelte@5.48.0) optionalDependencies: - svelte: 5.46.4 + svelte: 5.48.0 transitivePeerDependencies: - ts-node @@ -9861,10 +9861,10 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-svelte@3.4.0(prettier@3.6.0)(svelte@5.46.4): + prettier-plugin-svelte@3.4.0(prettier@3.6.0)(svelte@5.48.0): dependencies: prettier: 3.6.0 - svelte: 5.46.4 + svelte: 5.48.0 prettier@2.8.8: {} @@ -10253,19 +10253,19 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@4.3.4(picomatch@4.0.3)(svelte@5.46.4)(typescript@5.8.3): + svelte-check@4.3.4(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.8.3): dependencies: '@jridgewell/trace-mapping': 0.3.25 chokidar: 4.0.3 fdir: 6.5.0(picomatch@4.0.3) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.46.4 + svelte: 5.48.0 typescript: 5.8.3 transitivePeerDependencies: - picomatch - svelte-eslint-parser@1.4.1(svelte@5.46.4): + svelte-eslint-parser@1.4.1(svelte@5.48.0): dependencies: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -10274,30 +10274,30 @@ snapshots: postcss-scss: 4.0.9(postcss@8.5.6) postcss-selector-parser: 7.1.1 optionalDependencies: - svelte: 5.46.4 + svelte: 5.48.0 - svelte-parse-markup@0.1.5(svelte@5.46.4): + svelte-parse-markup@0.1.5(svelte@5.48.0): dependencies: - svelte: 5.46.4 + svelte: 5.48.0 - svelte-preprocess@6.0.0(postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(postcss@8.5.6)(svelte@5.46.4)(typescript@5.8.3): + svelte-preprocess@6.0.0(postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)))(postcss@8.5.6)(svelte@5.48.0)(typescript@5.8.3): dependencies: detect-indent: 6.1.0 strip-indent: 3.0.0 - svelte: 5.46.4 + svelte: 5.48.0 optionalDependencies: postcss: 8.5.6 postcss-load-config: 3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@18.19.119)(typescript@5.8.3)) typescript: 5.8.3 - svelte2tsx@0.7.33(svelte@5.46.4)(typescript@5.8.3): + svelte2tsx@0.7.33(svelte@5.48.0)(typescript@5.8.3): dependencies: dedent-js: 1.0.1 pascal-case: 3.1.2 - svelte: 5.46.4 + svelte: 5.48.0 typescript: 5.8.3 - svelte@5.46.4: + svelte@5.48.0: dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d23f8142a83c..c29eb67a8021 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -40,7 +40,7 @@ catalog: publint: ^0.3.0 semver: ^7.5.4 sirv-cli: ^3.0.0 - svelte: ^5.46.4 + svelte: ^5.48.0 svelte-check: ^4.3.4 svelte-preprocess: ^6.0.0 typescript-eslint: ^8.43.0 From 88aa3436125cc252f5869e484999c7644ef324a8 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Fri, 23 Jan 2026 04:24:24 +0800 Subject: [PATCH 12/37] this should just work --- packages/enhanced-img/package.json | 2 +- packages/kit/package.json | 2 +- .../src/exports/vite/build/build_server.js | 74 ++++++++++++++++--- .../kit/src/runtime/server/page/render.js | 11 +-- packages/kit/src/types/internal.d.ts | 4 +- packages/kit/src/utils/css.js | 67 +++++++++++++++-- packages/kit/types/index.d.ts | 4 +- pnpm-lock.yaml | 5 +- pnpm-workspace.yaml | 1 + 9 files changed, 145 insertions(+), 25 deletions(-) diff --git a/packages/enhanced-img/package.json b/packages/enhanced-img/package.json index fca5b03830c7..b6c9c794beb8 100644 --- a/packages/enhanced-img/package.json +++ b/packages/enhanced-img/package.json @@ -38,7 +38,7 @@ }, "types": "types/index.d.ts", "dependencies": { - "magic-string": "^0.30.5", + "magic-string": "catalog:", "sharp": "^0.34.1", "svelte-parse-markup": "^0.1.5", "vite-imagetools": "^9.0.2", diff --git a/packages/kit/package.json b/packages/kit/package.json index ec49bb035b53..59a030f1acbc 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -26,7 +26,7 @@ "devalue": "^5.6.2", "esm-env": "^1.2.2", "kleur": "^4.1.5", - "magic-string": "^0.30.5", + "magic-string": "catalog:", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index b282e09a82bc..efa4f47b16d4 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -7,6 +7,34 @@ import { basename, join } from 'node:path'; import { create_node_analyser } from '../static_analysis/index.js'; import { replace_css_relative_url } from '../../../utils/css.js'; +/** + * Regenerate server nodes after acquiring client manifest + * @overload + * @param {string} out + * @param {import('types').ValidatedKitConfig} kit + * @param {import('types').ManifestData} manifest_data + * @param {import('vite').Manifest} server_manifest + * @param {import('vite').Manifest} client_manifest + * @param {string} assets_path + * @param {import('vite').Rollup.RollupOutput['output']} client_chunks + * @param {import('types').RecursiveRequired} output_config + * @param {Map | null, children: string[] }>} static_exports + * @returns {Promise} + */ +/** + * Build server nodes without client manifest for analysis phase + * @overload + * @param {string} out + * @param {import('types').ValidatedKitConfig} kit + * @param {import('types').ManifestData} manifest_data + * @param {import('vite').Manifest} server_manifest + * @param {null} client_manifest + * @param {null} assets_path + * @param {null} client_chunks + * @param {import('types').RecursiveRequired} output_config + * @param {Map | null, children: string[] }>} static_exports + * @returns {Promise} + */ /** * @param {string} out * @param {import('types').ValidatedKitConfig} kit @@ -58,6 +86,30 @@ export async function build_server_nodes( static_exports }); + /** + * For CSS inlining, we either store a string or a function that returns the + * styles with the correct asset base path + * @type {(css: string, eager_assets: Set) => string} + */ + let prepare_css_for_inlining = (css) => s(css); + + if (kit.paths.assets) { + prepare_css_for_inlining = (css, eager_assets) => { + css = replace_css_relative_url( + css, + eager_assets, + `${kit.paths.assets}/${assets_path}`, + kit.paths.assets + ); + return s(css); + }; + } else if (kit.paths.relative) { + prepare_css_for_inlining = (css, eager_assets) => { + css = replace_css_relative_url(css, eager_assets, '${assets}', '${base}'); + return `function css(assets, base) { return \`${s(css)}\`; }`; + }; + } + for (let i = 0; i < manifest_data.nodes.length; i++) { const node = manifest_data.nodes[i]; @@ -78,6 +130,9 @@ export async function build_server_nodes( /** @type {string[]} */ let fonts = []; + /** @type {Set} */ + const eager_assets = new Set(); + if (node.component && client_manifest) { exports.push( 'let component_cache;', @@ -135,8 +190,6 @@ export async function build_server_nodes( /** @type {Set} */ const eager_css = new Set(); - /** @type {Set} */ - const eager_assets = new Set(); entry.stylesheet_map.forEach((value, filepath) => { // pages and layouts are renamed to node indexes when optimised for the client @@ -162,6 +215,11 @@ export async function build_server_nodes( `export const fonts = ${s(fonts)};` ); + if (eager_assets.size) { + console.log(eager_assets); + // TODO: strip immutable path prefix from assets? + } + /** @type {string[]} */ const inline_styles = []; @@ -170,14 +228,12 @@ export async function build_server_nodes( const filename = basename(file); const dest = `${out}/server/stylesheets/${filename}.js`; - let contents = /** @type {string} */ (stylesheets_to_inline.get(file)); - - if (kit.paths.assets) { - contents = replace_css_relative_url(contents, `${kit.paths.assets}/${assets_path}`); - } - - fs.writeFileSync(dest, `// ${filename}\nexport default ${s(contents)};`); + let css = /** @type {string} */ (stylesheets_to_inline.get(file)); + fs.writeFileSync( + dest, + `// ${filename}\nexport default ${prepare_css_for_inlining(css, eager_assets)};` + ); const name = `stylesheet_${i}`; imports.push(`import ${name} from '../stylesheets/${filename}.js';`); inline_styles.push(`\t${s(file)}: ${name}`); diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index 2f5946236de3..04a07d4b56a9 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -17,7 +17,6 @@ import { try_get_request_store, with_request_store } from '@sveltejs/kit/interna import { text_encoder } from '../../utils.js'; import { get_global_name } from '../utils.js'; import { create_remote_key } from '../../shared.js'; -import { replace_css_relative_url } from '../../../utils/css.js'; // TODO rename this function/module @@ -246,11 +245,13 @@ export async function render_response({ for (const url of node.fonts) fonts.add(url); if (node.inline_styles && !client.inline) { - Object.entries(await node.inline_styles()).forEach(([k, v]) => { - if (paths.relative) { - v = replace_css_relative_url(v, `${assets}/${paths.app_dir}/immutable/assets`); + Object.entries(await node.inline_styles()).forEach(([filename, css]) => { + if (typeof css === 'string') { + inline_styles.set(filename, css); + return; } - inline_styles.set(k, v); + + inline_styles.set(filename, css(base, `${assets}/${paths.app_dir}/immutable/assets`)); }); } } diff --git a/packages/kit/src/types/internal.d.ts b/packages/kit/src/types/internal.d.ts index 6384201af551..096d9c214a63 100644 --- a/packages/kit/src/types/internal.d.ts +++ b/packages/kit/src/types/internal.d.ts @@ -431,7 +431,9 @@ export interface SSRNode { server_id?: string; /** inlined styles */ - inline_styles?(): MaybePromise>; + inline_styles?(): MaybePromise< + Record string)> + >; /** Svelte component */ component?: SSRComponentLoader; /** +page.js or +layout.js */ diff --git a/packages/kit/src/utils/css.js b/packages/kit/src/utils/css.js index ea4bd5ffc705..cf01304eabe1 100644 --- a/packages/kit/src/utils/css.js +++ b/packages/kit/src/utils/css.js @@ -1,11 +1,66 @@ +import MagicString from 'magic-string'; +import * as svelte from 'svelte/compiler'; + +/** @typedef {ReturnType['children']} StyleSheetChildren */ + +/** @typedef {{ property: string; value: string; start: number; end: number; type: 'Declaration' }} Declaration */ + /** * Vite's static asset handling for the client changes the asset URLs in a CSS - * file to start with `./`. This is incorrect if we're inlining the CSS or if - * `paths.assets` is set. This function helps us rewrite the URLs in the CSS. - * @param {string} contents - * @param {string} base + * file to start with `./` or `../../../`. This is incorrect if we're inlining + * the CSS or if `paths.assets` is set, so we need to fix them. + * @param {string} css + * @param {Set} known_assets + * @param {string} assets + * @param {string=} base * @returns {string} */ -export function replace_css_relative_url(contents, base) { - return contents.replaceAll(/url\(\s*(['"]?)\.\//gi, `url($1${base}/`); +export function replace_css_relative_url(css, known_assets, assets, base) { + const s = new MagicString(css); + + /** + * @param {StyleSheetChildren[0]} rule + * @param {(declaration: Declaration) => void} callback + */ + const find_declarations = (rule, callback) => { + // Vite already inlines relative @import rules, so we don't need to handle them here + if (!rule.block) return; + + for (const child of rule.block.children) { + if (child.type !== 'Declaration') { + find_declarations(child, callback); + continue; + } + callback(child); + } + }; + + const parsed = svelte.parseCss + ? svelte.parseCss(css) + : /** @type {{ css: { children: StyleSheetChildren } }} */ ( + svelte.parse(``) + ).css; + + for (const child of parsed.children) { + find_declarations(child, (declaration) => { + const match = /url\(\s*(['"]?)((?:\.\/)|(?:\.\.\/\.\.\/\.\.\/))([\w\S\s]+)(['"]?)\)/gi.exec( + declaration.value + ); + if (!match) return; + + const [, quote, prefix, filename] = match; + + if (!known_assets.has(filename)) return; + + if (prefix === './') { + declaration.value = `url(${quote}${assets}/${filename}${quote})`; + } else { + declaration.value = `url(${quote}${base}/${filename}${quote})`; + } + + s.update(declaration.start, declaration.end, `${declaration.property}:${declaration.value};`); + }); + } + + return s.toString(); } diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 30d5e82f91c8..eb520e0eac5c 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -2546,7 +2546,9 @@ declare module '@sveltejs/kit' { server_id?: string; /** inlined styles */ - inline_styles?(): MaybePromise>; + inline_styles?(): MaybePromise< + Record string)> + >; /** Svelte component */ component?: SSRComponentLoader; /** +page.js or +layout.js */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be663be84c07..867eecf44122 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,6 +81,9 @@ catalogs: eslint: specifier: ^9.34.0 version: 9.34.0 + magic-string: + specifier: ^0.30.21 + version: 0.30.21 polka: specifier: ^1.0.0-next.28 version: 1.0.0-next.28 @@ -548,7 +551,7 @@ importers: specifier: ^4.1.5 version: 4.1.5 magic-string: - specifier: ^0.30.5 + specifier: 'catalog:' version: 0.30.21 mrmime: specifier: ^2.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c29eb67a8021..b5cf57ed5bb9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -36,6 +36,7 @@ catalog: dts-buddy: ^0.6.2 esbuild: ^0.25.4 eslint: ^9.34.0 + magic-string: ^0.30.21 polka: ^1.0.0-next.28 publint: ^0.3.0 semver: ^7.5.4 From f9a3aa7fc2ed39c2032442a1b8f271bc570ec59c Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Fri, 23 Jan 2026 04:29:37 +0800 Subject: [PATCH 13/37] fix lockfile --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 867eecf44122..3bdd20417026 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -466,7 +466,7 @@ importers: packages/enhanced-img: dependencies: magic-string: - specifier: ^0.30.5 + specifier: 'catalog:' version: 0.30.21 sharp: specifier: ^0.34.1 From 9217194e8062785037010038e0915c94f2d94f9f Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Fri, 23 Jan 2026 05:44:14 +0800 Subject: [PATCH 14/37] ok its working now --- .../src/exports/vite/build/build_server.js | 32 ++++++++--------- .../kit/src/runtime/server/page/render.js | 2 +- packages/kit/src/utils/css.js | 35 ++++++++++++------- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index efa4f47b16d4..dbd6d8efc9ac 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -93,21 +93,17 @@ export async function build_server_nodes( */ let prepare_css_for_inlining = (css) => s(css); - if (kit.paths.assets) { + // when paths.assets is set we still need the paths to be dynamic because we + // set a fake path (/_svelte_kit_assets) at runtime when running `vite preview` + if (kit.paths.assets || kit.paths.relative) { prepare_css_for_inlining = (css, eager_assets) => { - css = replace_css_relative_url( - css, - eager_assets, - `${kit.paths.assets}/${assets_path}`, - kit.paths.assets - ); + const transformed_css = replace_css_relative_url(css, eager_assets, '${assets}', '${base}'); + // only convert to a function if there are URLs to replace + if (css !== transformed_css) { + return `function css(assets, base) { return \`${s(transformed_css).slice(1, -1)}\`; }`; + } return s(css); }; - } else if (kit.paths.relative) { - prepare_css_for_inlining = (css, eager_assets) => { - css = replace_css_relative_url(css, eager_assets, '${assets}', '${base}'); - return `function css(assets, base) { return \`${s(css)}\`; }`; - }; } for (let i = 0; i < manifest_data.nodes.length; i++) { @@ -131,7 +127,7 @@ export async function build_server_nodes( let fonts = []; /** @type {Set} */ - const eager_assets = new Set(); + let eager_assets = new Set(); if (node.component && client_manifest) { exports.push( @@ -215,9 +211,13 @@ export async function build_server_nodes( `export const fonts = ${s(fonts)};` ); - if (eager_assets.size) { - console.log(eager_assets); - // TODO: strip immutable path prefix from assets? + // assets that have been processed by Vite (with the asset path stripped) + if (assets_path && eager_assets.size) { + eager_assets = new Set( + Array.from(eager_assets).map((asset) => { + return asset.replace(`${assets_path}/`, ''); + }) + ); } /** @type {string[]} */ diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index 04a07d4b56a9..3ff1ce526ebd 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -251,7 +251,7 @@ export async function render_response({ return; } - inline_styles.set(filename, css(base, `${assets}/${paths.app_dir}/immutable/assets`)); + inline_styles.set(filename, css(`${assets}/${paths.app_dir}/immutable/assets`, base)); }); } } diff --git a/packages/kit/src/utils/css.js b/packages/kit/src/utils/css.js index cf01304eabe1..6346a16b5e74 100644 --- a/packages/kit/src/utils/css.js +++ b/packages/kit/src/utils/css.js @@ -12,7 +12,7 @@ import * as svelte from 'svelte/compiler'; * @param {string} css * @param {Set} known_assets * @param {string} assets - * @param {string=} base + * @param {string} base * @returns {string} */ export function replace_css_relative_url(css, known_assets, assets, base) { @@ -43,22 +43,31 @@ export function replace_css_relative_url(css, known_assets, assets, base) { for (const child of parsed.children) { find_declarations(child, (declaration) => { - const match = /url\(\s*(['"]?)((?:\.\/)|(?:\.\.\/\.\.\/\.\.\/))([\w\S\s]+)(['"]?)\)/gi.exec( - declaration.value - ); - if (!match) return; + /** @type {string} */ + let new_value = declaration.value; - const [, quote, prefix, filename] = match; + let match; + while ( + (match = /url\(\s*(['"]?)((?:\.\/)|(?:\.\.\/\.\.\/\.\.\/))([\w\S]+)(['"]?)\)/gi.exec( + new_value + )) + ) { + const [matched, quote, prefix, filename] = match; - if (!known_assets.has(filename)) return; - - if (prefix === './') { - declaration.value = `url(${quote}${assets}/${filename}${quote})`; - } else { - declaration.value = `url(${quote}${base}/${filename}${quote})`; + // assets processed by Vite + if (prefix === './' && known_assets.has(filename)) { + new_value = new_value.replace(matched, `url(${quote}${assets}/${filename}${quote})`); + } + // unprocessed assets from the `static` directory + // TODO: there should be a better way to confirm it's from the static directory + else if (prefix === '../../../') { + new_value = new_value.replace(matched, `url(${quote}${base}/${filename}${quote})`); + } } - s.update(declaration.start, declaration.end, `${declaration.property}:${declaration.value};`); + if (declaration.value !== new_value) { + s.update(declaration.start, declaration.end, `${declaration.property}: ${new_value}`); + } }); } From 390b892ee8a19b08f6b18b367f0171e81fd1d258 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Fri, 23 Jan 2026 05:49:44 +0800 Subject: [PATCH 15/37] last fix --- packages/kit/src/runtime/server/page/render.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index 3ff1ce526ebd..0c39c90d484e 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -251,7 +251,7 @@ export async function render_response({ return; } - inline_styles.set(filename, css(`${assets}/${paths.app_dir}/immutable/assets`, base)); + inline_styles.set(filename, css(`${assets}/${paths.app_dir}/immutable/assets`, assets)); }); } } From 40d1e4fe6ed9fce9c4c59cb79858bb25a7bd6dc2 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Fri, 23 Jan 2026 05:53:38 +0800 Subject: [PATCH 16/37] format --- 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 dbd6d8efc9ac..958f0058327f 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -93,7 +93,7 @@ export async function build_server_nodes( */ let prepare_css_for_inlining = (css) => s(css); - // when paths.assets is set we still need the paths to be dynamic because we + // when paths.assets is set we still need the paths to be dynamic because we // set a fake path (/_svelte_kit_assets) at runtime when running `vite preview` if (kit.paths.assets || kit.paths.relative) { prepare_css_for_inlining = (css, eager_assets) => { From fe704f81737cf584673869b75a581d570ae556c7 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Fri, 23 Jan 2026 07:24:11 +0800 Subject: [PATCH 17/37] push wip --- packages/kit/src/utils/css.js | 67 +++++--- packages/kit/src/utils/css.spec.js | 245 ++++++++++++++++++++++------- 2 files changed, 229 insertions(+), 83 deletions(-) diff --git a/packages/kit/src/utils/css.js b/packages/kit/src/utils/css.js index 6346a16b5e74..80284c5d59cb 100644 --- a/packages/kit/src/utils/css.js +++ b/packages/kit/src/utils/css.js @@ -5,6 +5,8 @@ import * as svelte from 'svelte/compiler'; /** @typedef {{ property: string; value: string; start: number; end: number; type: 'Declaration' }} Declaration */ +const OFFSET = '`) ).css; + const s = new MagicString(css); + for (const child of parsed.children) { find_declarations(child, (declaration) => { /** @type {string} */ let new_value = declaration.value; + /** @type {RegExpExecArray | null} */ let match; - while ( - (match = /url\(\s*(['"]?)((?:\.\/)|(?:\.\.\/\.\.\/\.\.\/))([\w\S]+)(['"]?)\)/gi.exec( - new_value - )) - ) { + // TODO: this is matching the closing quote too early + const regex = /url\(\s*(['"]?)((?:\.\/)|(?:\.\.\/\.\.\/\.\.\/))([\w\S]+)(?:['"]?)\)/gi; + while ((match = regex.exec(declaration.value))) { const [matched, quote, prefix, filename] = match; // assets processed by Vite + // TODO: do we need to remove ? and # from filename before checking against the known asset list? if (prefix === './' && known_assets.has(filename)) { new_value = new_value.replace(matched, `url(${quote}${assets}/${filename}${quote})`); } @@ -62,10 +52,24 @@ export function replace_css_relative_url(css, known_assets, assets, base) { // TODO: there should be a better way to confirm it's from the static directory else if (prefix === '../../../') { new_value = new_value.replace(matched, `url(${quote}${base}/${filename}${quote})`); + } else { + console.log({ + matched, + quote, + prefix, + filename, + known_assets, + prefix_check: prefix === './', + known_check: known_assets.has(filename) + }); } } if (declaration.value !== new_value) { + if (!svelte.parseCss) { + declaration.start = declaration.start - OFFSET; + declaration.end = declaration.end - OFFSET; + } s.update(declaration.start, declaration.end, `${declaration.property}: ${new_value}`); } }); @@ -73,3 +77,20 @@ export function replace_css_relative_url(css, known_assets, assets, base) { return s.toString(); } + +/** + * @param {StyleSheetChildren[0]} rule + * @param {(declaration: Declaration) => void} callback + */ +function find_declarations(rule, callback) { + // Vite already inlines relative @import rules, so we don't need to handle them here + if (!rule.block) return; + + for (const child of rule.block.children) { + if (child.type !== 'Declaration') { + find_declarations(child, callback); + continue; + } + callback(child); + } +} diff --git a/packages/kit/src/utils/css.spec.js b/packages/kit/src/utils/css.spec.js index 08b58fdebfb3..ccb83b9c32b7 100644 --- a/packages/kit/src/utils/css.spec.js +++ b/packages/kit/src/utils/css.spec.js @@ -2,143 +2,268 @@ import { assert, describe, test } from 'vitest'; import { replace_css_relative_url } from './css.js'; describe('replace_css_relative_url', () => { - test('replaces relative url with base path', () => { - assert.equal(replace_css_relative_url('url(./image.png)', '/assets'), 'url(/assets/image.png)'); + test('replaces relative url with assets path', () => { + assert.equal( + replace_css_relative_url( + 'div { background: url(./image.png); }', + new Set(['image.png']), + 'https://cdn.example.com/_app/immutable/assets', + 'https://cdn.example.com' + ), + 'div { background: url(https://cdn.example.com/_app/immutable/assets/image.png); }' + ); }); test('handles single-quoted urls', () => { assert.equal( - replace_css_relative_url("url('./image.png')", '/assets'), - "url('/assets/image.png')" + replace_css_relative_url( + "div { background: url('./image.png'); }", + new Set(['image.png']), + 'https://cdn.example.com/_app/immutable/assets', + 'https://cdn.example.com' + ), + "div { background: url('https://cdn.example.com/_app/immutable/assets/image.png'); }" ); }); test('handles double-quoted urls', () => { assert.equal( - replace_css_relative_url('url("./image.png")', '/assets'), - 'url("/assets/image.png")' + replace_css_relative_url( + 'div { background: url("./image.png"); }', + new Set(['image.png']), + 'https://cdn.example.com/_app/immutable/assets', + 'https://cdn.example.com' + ), + 'div { background: url("https://cdn.example.com/_app/immutable/assets/image.png"); }' ); }); - test('case-insensitive urls', () => { + test('case-insensitive URL function', () => { assert.equal( - replace_css_relative_url('uRl("./image.png")', '/assets'), - 'url("/assets/image.png")' + replace_css_relative_url( + 'div { background: uRl(./image.png); }', + new Set(['image.png']), + 'https://cdn.example.com/_app/immutable/assets', + 'https://cdn.example.com' + ), + 'div { background: url(https://cdn.example.com/_app/immutable/assets/image.png); }' ); }); - test('replaces multiple relative urls', () => { + test('replaces multiple declarations', () => { const input = ` + div { background: url(./bg.png); - border-image: url('./border.svg'); - mask: url("./mask.png"); + border-image: url(./border.svg); + mask: url(./mask.png); + } `; const expected = ` - background: url(/assets/bg.png); - border-image: url('/assets/border.svg'); - mask: url("/assets/mask.png"); + div { + background: url(./_app/immutable/assets/bg.png); + border-image: url(./_app/immutable/assets/border.svg); + mask: url(./_app/immutable/assets/mask.png); + } `; - assert.equal(replace_css_relative_url(input, '/assets'), expected); + assert.equal( + replace_css_relative_url( + input, + new Set(['bg.png', 'border.svg', 'mask.png']), + './_app/immutable/assets', + '.' + ), + expected + ); }); test('does not replace non-relative urls', () => { assert.equal( - replace_css_relative_url('url(/absolute/image.png)', '/assets'), - 'url(/absolute/image.png)' + replace_css_relative_url( + 'div { background: url(/absolute/image.png); }', + new Set(), + './_app/immutable/assets', + '.' + ), + 'div { background: url(/absolute/image.png); }' ); assert.equal( - replace_css_relative_url('url(https://example.com/image.png)', '/assets'), - 'url(https://example.com/image.png)' + replace_css_relative_url( + 'div { background: url(https://example.com/image.png); }', + new Set(), + './_app/immutable/assets', + '.' + ), + 'div { background: url(https://example.com/image.png); }' ); assert.equal( - replace_css_relative_url('url(data:image/png;base64,abc)', '/assets'), - 'url(data:image/png;base64,abc)' + replace_css_relative_url( + 'div { background: url(data:image/png;base64,abc); }', + new Set(), + './_app/immutable/assets', + '.' + ), + 'div { background: url(data:image/png;base64,abc); }' ); }); test('does not replace parent directory urls', () => { - assert.equal(replace_css_relative_url('url(../image.png)', '/assets'), 'url(../image.png)'); + assert.equal( + replace_css_relative_url( + 'div { background: url(../image.png); }', + new Set(), + './_app/immutable/assets', + '.' + ), + 'div { background: url(../image.png); }' + ); + + assert.equal( + replace_css_relative_url( + 'div { background: url(../../../image.png); }', + new Set(), + './_app/immutable/assets', + '.' + ), + 'div { background: url(../../../image.png); }' + ); + + assert.equal( + replace_css_relative_url( + 'div { background: url(../../../../image.png); }', + new Set(), + './_app/immutable/assets', + '.' + ), + 'div { background: url(../../../../image.png); }' + ); }); test('handles whitespace after opening parenthesis', () => { assert.equal( - replace_css_relative_url('url( ./image.png)', '/assets'), - 'url(/assets/image.png)' + replace_css_relative_url( + 'div { background: url( ./image.png); }', + new Set(['image.png']), + './_app/immutable/assets', + '.' + ), + 'div { background: url(./_app/immutable/assets/image.png); }' ); }); test('handles multiple spaces before quoted path', () => { assert.equal( - replace_css_relative_url('url( "./image.png")', '/assets'), - 'url("/assets/image.png")' + replace_css_relative_url( + 'div { background: url( "./image.png"); }', + new Set(['image.png']), + './_app/immutable/assets', + '.' + ), + 'div { background: url("./_app/immutable/assets/image.png"); }' ); }); test('handles tab before single-quoted path', () => { assert.equal( - replace_css_relative_url("url(\t'./image.png')", '/assets'), - "url('/assets/image.png')" + replace_css_relative_url( + "div { background: url(\t'./image.png'); }", + new Set(['image.png']), + './_app/immutable/assets', + '.' + ), + "div { background: url('./_app/immutable/assets/image.png'); }" ); }); test('handles url with query string', () => { assert.equal( - replace_css_relative_url('url(./image.png?v=123)', '/assets'), - 'url(/assets/image.png?v=123)' + replace_css_relative_url( + 'div { background: url(./image.png?v=123); }', + new Set(['image.png']), + './_app/immutable/assets', + '.' + ), + 'div { background: url(./_app/immutable/assets/image.png?v=123); }' ); }); test('handles url with hash fragment', () => { assert.equal( - replace_css_relative_url("url('./image.png#section')", '/assets'), - "url('/assets/image.png#section')" + replace_css_relative_url( + "div { background: url('./image.png#section'); }", + new Set(['image.png']), + './_app/immutable/assets', + '.' + ), + "div { background: url('./_app/immutable/assets/image.png#section'); }" ); }); - test('handles url with hash fragment without extension', () => { - assert.equal(replace_css_relative_url('url(./foo#bar)', '/assets'), 'url(/assets/foo#bar)'); - }); - test('handles url with both query string and fragment', () => { assert.equal( - replace_css_relative_url('url("./image.png?a=1&b=2#anchor")', '/assets'), - 'url("/assets/image.png?a=1&b=2#anchor")' + replace_css_relative_url( + 'div { background: url("./image.png?a=1&b=2#anchor"); }', + new Set(['image.png']), + './_app/immutable/assets', + '.' + ), + 'div { background: url("./_app/immutable/assets/image.png?a=1&b=2#anchor"); }' ); }); - test('handles deeply nested paths', () => { + test('handles multiple URLs in a single declaration', () => { + const input = 'div { background: image-set(url(./a.png) 1x, url(./b.png) 2x); }'; + const expected = + 'div { background: image-set(url(./_app/immutable/assets/a.png) 1x, url(./_app/immutable/assets/b.png) 2x); }'; + assert.equal( - replace_css_relative_url('url(./path/to/deep/nested/image.png)', '/assets'), - 'url(/assets/path/to/deep/nested/image.png)' + replace_css_relative_url(input, new Set(['a.png', 'b.png']), './_app/immutable/assets', '.'), + expected ); }); - test('handles urls inside image-set()', () => { - const input = 'background: image-set(url(./a.png) 1x, url(./b.png) 2x)'; - const expected = 'background: image-set(url(/assets/a.png) 1x, url(/assets/b.png) 2x)'; - assert.equal(replace_css_relative_url(input, '/assets'), expected); - }); - test('does not replace relative url without ./ prefix', () => { - assert.equal(replace_css_relative_url('url(image.png)', '/assets'), 'url(image.png)'); - }); - - test('does not replace svg fragment reference', () => { - assert.equal(replace_css_relative_url('url(#svg-filter)', '/assets'), 'url(#svg-filter)'); + assert.equal( + replace_css_relative_url( + 'div { background: url(image.png); }', + new Set(['image.png']), + './_app/immutable/assets', + '.' + ), + 'div { background: url(image.png); }' + ); }); - test('does not replace empty url', () => { - assert.equal(replace_css_relative_url('url()', '/assets'), 'url()'); + test('replaces ../../../ urls with base', () => { + assert.equal( + replace_css_relative_url( + 'div { background: url(../../../image.png); }', + new Set(), + './_app/immutable', + '.' + ), + 'div { background: url(./image.png); }' + ); }); - test('handles empty base parameter', () => { - assert.equal(replace_css_relative_url('url(./image.png)', ''), 'url(/image.png)'); + test('replaces ../../../ urls with base and quotes', () => { + assert.equal( + replace_css_relative_url( + "div { background: url('../../../image.png'); }", + new Set(), + './_app/immutable/assets', + '.' + ), + "div { background: url('./image.png'); }" + ); }); - test('handles full CDN url as base', () => { + test('only replaces known assets', () => { + const input = 'div { background: url(./known.png), url(./unknown.png); }'; + const expected = + 'div { background: url(./_app/immutable/assets/known.png), url(./unknown.png); }'; assert.equal( - replace_css_relative_url('url(./image.png)', 'https://cdn.example.com/stuff'), - 'url(https://cdn.example.com/stuff/image.png)' + replace_css_relative_url(input, new Set(['known.png']), './_app/immutable/assets', '.'), + expected ); }); }); From 16c66b9d964926373431e3b0e26b341790467965 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Fri, 23 Jan 2026 22:49:42 +0800 Subject: [PATCH 18/37] tests are passing --- .../src/exports/vite/build/build_server.js | 12 +- packages/kit/src/utils/css.js | 105 +++--- packages/kit/src/utils/css.spec.js | 317 +++++++++--------- 3 files changed, 233 insertions(+), 201 deletions(-) diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 958f0058327f..92249727c7d8 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -5,7 +5,7 @@ import { s } from '../../../utils/misc.js'; import { normalizePath } from 'vite'; import { basename, join } from 'node:path'; import { create_node_analyser } from '../static_analysis/index.js'; -import { replace_css_relative_url } from '../../../utils/css.js'; +import { fix_css_urls } from '../../../utils/css.js'; /** * Regenerate server nodes after acquiring client manifest @@ -96,8 +96,16 @@ export async function build_server_nodes( // when paths.assets is set we still need the paths to be dynamic because we // set a fake path (/_svelte_kit_assets) at runtime when running `vite preview` if (kit.paths.assets || kit.paths.relative) { + const static_assets = new Set(manifest_data.assets.map((a) => a.file)); prepare_css_for_inlining = (css, eager_assets) => { - const transformed_css = replace_css_relative_url(css, eager_assets, '${assets}', '${base}'); + // TODO: pass in manifest_data.assets + const transformed_css = fix_css_urls({ + css, + vite_assets: eager_assets, + static_assets, + assets: '${assets}', + base: '${base}' + }); // only convert to a function if there are URLs to replace if (css !== transformed_css) { return `function css(assets, base) { return \`${s(transformed_css).slice(1, -1)}\`; }`; diff --git a/packages/kit/src/utils/css.js b/packages/kit/src/utils/css.js index 80284c5d59cb..0cade384dab4 100644 --- a/packages/kit/src/utils/css.js +++ b/packages/kit/src/utils/css.js @@ -5,73 +5,94 @@ import * as svelte from 'svelte/compiler'; /** @typedef {{ property: string; value: string; start: number; end: number; type: 'Declaration' }} Declaration */ -const OFFSET = '`) + ).css; + }; + +const AST_OFFSET = '`) - ).css; - const s = new MagicString(css); + const parsed = parser(css); + for (const child of parsed.children) { find_declarations(child, (declaration) => { /** @type {string} */ let new_value = declaration.value; /** @type {RegExpExecArray | null} */ - let match; - // TODO: this is matching the closing quote too early - const regex = /url\(\s*(['"]?)((?:\.\/)|(?:\.\.\/\.\.\/\.\.\/))([\w\S]+)(?:['"]?)\)/gi; - while ((match = regex.exec(declaration.value))) { - const [matched, quote, prefix, filename] = match; - - // assets processed by Vite - // TODO: do we need to remove ? and # from filename before checking against the known asset list? - if (prefix === './' && known_assets.has(filename)) { - new_value = new_value.replace(matched, `url(${quote}${assets}/${filename}${quote})`); + let url_declaration_match; + const url_declaration_regex = /url\(\s*[^)]*\)/gi; + while ((url_declaration_match = url_declaration_regex.exec(declaration.value))) { + const [url_declaration] = url_declaration_match; + + const url_value_match = /url\(\s*(['"]?)(.*?)\1\s*\)/i.exec(url_declaration); + if (!url_value_match) continue; + + const [, , url] = url_value_match; + + /** @type {string | undefined} */ + let new_prefix; + + let current_prefix = url.slice(0, VITE_ASSET_PREFIX.length); + let [filename] = url.slice(VITE_ASSET_PREFIX.length).split(FRAGMENT_OR_QUERY_REGEX); + + // Vite assets + if (current_prefix === VITE_ASSET_PREFIX && vite_assets.has(filename)) { + new_prefix = assets; } - // unprocessed assets from the `static` directory - // TODO: there should be a better way to confirm it's from the static directory - else if (prefix === '../../../') { - new_value = new_value.replace(matched, `url(${quote}${base}/${filename}${quote})`); - } else { - console.log({ - matched, - quote, - prefix, - filename, - known_assets, - prefix_check: prefix === './', - known_check: known_assets.has(filename) - }); + // Static assets + else { + current_prefix = url.slice(0, STATIC_ASSET_PREFIX.length); + [filename] = url.slice(STATIC_ASSET_PREFIX.length).split(FRAGMENT_OR_QUERY_REGEX); + + if (current_prefix === STATIC_ASSET_PREFIX && static_assets.has(filename)) { + new_prefix = base; + } } + + if (!new_prefix) continue; + + new_value = new_value.replace(`${current_prefix}${filename}`, `${new_prefix}/${filename}`); } - if (declaration.value !== new_value) { - if (!svelte.parseCss) { - declaration.start = declaration.start - OFFSET; - declaration.end = declaration.end - OFFSET; - } - s.update(declaration.start, declaration.end, `${declaration.property}: ${new_value}`); + if (declaration.value === new_value) return; + + if (!svelte.parseCss) { + declaration.start = declaration.start - AST_OFFSET; + declaration.end = declaration.end - AST_OFFSET; } + s.update(declaration.start, declaration.end, `${declaration.property}: ${new_value}`); }); } diff --git a/packages/kit/src/utils/css.spec.js b/packages/kit/src/utils/css.spec.js index ccb83b9c32b7..65c373a99525 100644 --- a/packages/kit/src/utils/css.spec.js +++ b/packages/kit/src/utils/css.spec.js @@ -1,56 +1,73 @@ import { assert, describe, test } from 'vitest'; -import { replace_css_relative_url } from './css.js'; +import { fix_css_urls } from './css.js'; -describe('replace_css_relative_url', () => { - test('replaces relative url with assets path', () => { +describe('fix_css_urls', () => { + test('fixes Vite asset URL', () => { assert.equal( - replace_css_relative_url( - 'div { background: url(./image.png); }', - new Set(['image.png']), - 'https://cdn.example.com/_app/immutable/assets', - 'https://cdn.example.com' - ), + fix_css_urls({ + css: 'div { background: url(./image.png); }', + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: 'https://cdn.example.com/_app/immutable/assets', + base: 'https://cdn.example.com' + }), 'div { background: url(https://cdn.example.com/_app/immutable/assets/image.png); }' ); }); - test('handles single-quoted urls', () => { + test('fixes static asset URL', () => { assert.equal( - replace_css_relative_url( - "div { background: url('./image.png'); }", - new Set(['image.png']), - 'https://cdn.example.com/_app/immutable/assets', - 'https://cdn.example.com' - ), - "div { background: url('https://cdn.example.com/_app/immutable/assets/image.png'); }" + fix_css_urls({ + css: 'div { background: url(../../../image.png); }', + vite_assets: new Set(), + static_assets: new Set(['image.png']), + assets: 'https://cdn.example.com/_app/immutable/assets', + base: 'https://cdn.example.com' + }), + 'div { background: url(https://cdn.example.com/image.png); }' ); }); - test('handles double-quoted urls', () => { + test('keeps single quotes', () => { assert.equal( - replace_css_relative_url( - 'div { background: url("./image.png"); }', - new Set(['image.png']), - 'https://cdn.example.com/_app/immutable/assets', - 'https://cdn.example.com' - ), + fix_css_urls({ + css: "div { background: url('../../../image.png'); }", + vite_assets: new Set(), + static_assets: new Set(['image.png']), + assets: 'https://cdn.example.com/_app/immutable/assets', + base: 'https://cdn.example.com' + }), + "div { background: url('https://cdn.example.com/image.png'); }" + ); + }); + + test('keeps double-quotes', () => { + assert.equal( + fix_css_urls({ + css: 'div { background: url("./image.png"); }', + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: 'https://cdn.example.com/_app/immutable/assets', + base: 'https://cdn.example.com' + }), 'div { background: url("https://cdn.example.com/_app/immutable/assets/image.png"); }' ); }); - test('case-insensitive URL function', () => { + test('works with case-insensitive URL function', () => { assert.equal( - replace_css_relative_url( - 'div { background: uRl(./image.png); }', - new Set(['image.png']), - 'https://cdn.example.com/_app/immutable/assets', - 'https://cdn.example.com' - ), - 'div { background: url(https://cdn.example.com/_app/immutable/assets/image.png); }' + fix_css_urls({ + css: 'div { background: uRl(./image.png); }', + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: 'https://cdn.example.com/_app/immutable/assets', + base: 'https://cdn.example.com' + }), + 'div { background: uRl(https://cdn.example.com/_app/immutable/assets/image.png); }' ); }); - test('replaces multiple declarations', () => { + test('works with multiple declarations', () => { const input = ` div { background: url(./bg.png); @@ -66,146 +83,159 @@ describe('replace_css_relative_url', () => { } `; assert.equal( - replace_css_relative_url( - input, - new Set(['bg.png', 'border.svg', 'mask.png']), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: input, + vite_assets: new Set(['bg.png', 'border.svg', 'mask.png']), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), expected ); }); test('does not replace non-relative urls', () => { assert.equal( - replace_css_relative_url( - 'div { background: url(/absolute/image.png); }', - new Set(), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: 'div { background: url(/absolute/image.png); }', + vite_assets: new Set(), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), 'div { background: url(/absolute/image.png); }' ); assert.equal( - replace_css_relative_url( - 'div { background: url(https://example.com/image.png); }', - new Set(), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: 'div { background: url(https://example.com/image.png); }', + vite_assets: new Set(), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), 'div { background: url(https://example.com/image.png); }' ); assert.equal( - replace_css_relative_url( - 'div { background: url(data:image/png;base64,abc); }', - new Set(), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: 'div { background: url(data:image/png;base64,abc); }', + vite_assets: new Set(), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), 'div { background: url(data:image/png;base64,abc); }' ); }); - test('does not replace parent directory urls', () => { + test('does not replace unrelated URLs', () => { assert.equal( - replace_css_relative_url( - 'div { background: url(../image.png); }', - new Set(), - './_app/immutable/assets', - '.' - ), - 'div { background: url(../image.png); }' + fix_css_urls({ + css: 'div { background: url(./image.png); }', + vite_assets: new Set(), + static_assets: new Set(['image.png']), + assets: './_app/immutable/assets', + base: '.' + }), + 'div { background: url(./image.png); }' ); assert.equal( - replace_css_relative_url( - 'div { background: url(../../../image.png); }', - new Set(), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: 'div { background: url(../../../image.png); }', + vite_assets: new Set(), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), 'div { background: url(../../../image.png); }' ); assert.equal( - replace_css_relative_url( - 'div { background: url(../../../../image.png); }', - new Set(), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: 'div { background: url(../../../../image.png); }', + vite_assets: new Set(), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), 'div { background: url(../../../../image.png); }' ); }); test('handles whitespace after opening parenthesis', () => { assert.equal( - replace_css_relative_url( - 'div { background: url( ./image.png); }', - new Set(['image.png']), - './_app/immutable/assets', - '.' - ), - 'div { background: url(./_app/immutable/assets/image.png); }' + fix_css_urls({ + css: 'div { background: url( ./image.png); }', + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), + 'div { background: url( ./_app/immutable/assets/image.png); }' ); }); test('handles multiple spaces before quoted path', () => { assert.equal( - replace_css_relative_url( - 'div { background: url( "./image.png"); }', - new Set(['image.png']), - './_app/immutable/assets', - '.' - ), - 'div { background: url("./_app/immutable/assets/image.png"); }' + fix_css_urls({ + css: 'div { background: url( "./image.png"); }', + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), + 'div { background: url( "./_app/immutable/assets/image.png"); }' ); }); test('handles tab before single-quoted path', () => { assert.equal( - replace_css_relative_url( - "div { background: url(\t'./image.png'); }", - new Set(['image.png']), - './_app/immutable/assets', - '.' - ), - "div { background: url('./_app/immutable/assets/image.png'); }" + fix_css_urls({ + css: "div { background: url(\t'./image.png'); }", + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), + "div { background: url(\t'./_app/immutable/assets/image.png'); }" ); }); test('handles url with query string', () => { assert.equal( - replace_css_relative_url( - 'div { background: url(./image.png?v=123); }', - new Set(['image.png']), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: 'div { background: url(./image.png?v=123); }', + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), 'div { background: url(./_app/immutable/assets/image.png?v=123); }' ); }); test('handles url with hash fragment', () => { assert.equal( - replace_css_relative_url( - "div { background: url('./image.png#section'); }", - new Set(['image.png']), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: "div { background: url('./image.png#section'); }", + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), "div { background: url('./_app/immutable/assets/image.png#section'); }" ); }); test('handles url with both query string and fragment', () => { assert.equal( - replace_css_relative_url( - 'div { background: url("./image.png?a=1&b=2#anchor"); }', - new Set(['image.png']), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: 'div { background: url("./image.png?a=1&b=2#anchor"); }', + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), 'div { background: url("./_app/immutable/assets/image.png?a=1&b=2#anchor"); }' ); }); @@ -216,54 +246,27 @@ describe('replace_css_relative_url', () => { 'div { background: image-set(url(./_app/immutable/assets/a.png) 1x, url(./_app/immutable/assets/b.png) 2x); }'; assert.equal( - replace_css_relative_url(input, new Set(['a.png', 'b.png']), './_app/immutable/assets', '.'), + fix_css_urls({ + css: input, + vite_assets: new Set(['a.png', 'b.png']), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), expected ); }); test('does not replace relative url without ./ prefix', () => { assert.equal( - replace_css_relative_url( - 'div { background: url(image.png); }', - new Set(['image.png']), - './_app/immutable/assets', - '.' - ), + fix_css_urls({ + css: 'div { background: url(image.png); }', + vite_assets: new Set(['image.png']), + static_assets: new Set(), + assets: './_app/immutable/assets', + base: '.' + }), 'div { background: url(image.png); }' ); }); - - test('replaces ../../../ urls with base', () => { - assert.equal( - replace_css_relative_url( - 'div { background: url(../../../image.png); }', - new Set(), - './_app/immutable', - '.' - ), - 'div { background: url(./image.png); }' - ); - }); - - test('replaces ../../../ urls with base and quotes', () => { - assert.equal( - replace_css_relative_url( - "div { background: url('../../../image.png'); }", - new Set(), - './_app/immutable/assets', - '.' - ), - "div { background: url('./image.png'); }" - ); - }); - - test('only replaces known assets', () => { - const input = 'div { background: url(./known.png), url(./unknown.png); }'; - const expected = - 'div { background: url(./_app/immutable/assets/known.png), url(./unknown.png); }'; - assert.equal( - replace_css_relative_url(input, new Set(['known.png']), './_app/immutable/assets', '.'), - expected - ); - }); }); From 4e665a2f4c34d9abd3a22e278adae448a308190e Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Tue, 27 Jan 2026 11:24:45 +0800 Subject: [PATCH 19/37] split tests --- .../apps/options/test/paths-assets.test.js | 174 ++++++++++++++++ packages/kit/test/apps/options/test/test.js | 187 +----------------- 2 files changed, 176 insertions(+), 185 deletions(-) create mode 100644 packages/kit/test/apps/options/test/paths-assets.test.js diff --git a/packages/kit/test/apps/options/test/paths-assets.test.js b/packages/kit/test/apps/options/test/paths-assets.test.js new file mode 100644 index 000000000000..94c8fb685c02 --- /dev/null +++ b/packages/kit/test/apps/options/test/paths-assets.test.js @@ -0,0 +1,174 @@ +import process from 'node:process'; +import { expect } from '@playwright/test'; +import { test } from '../../../utils.js'; + +test.describe.configure({ mode: 'parallel' }); + +test.describe('base path', () => { + test.skip(!process.env.PATHS_ASSETS); + + test('serves a useful 404 when visiting unprefixed path', async ({ request }) => { + const html = await request.get('/slash/', { headers: { Accept: 'text/html' } }); + expect(html.status()).toBe(404); + expect(await html.text()).toBe( + 'The server is configured with a public base URL of /path-base - did you mean to visit /path-base/slash/ instead?' + ); + + const plain = await request.get('/slash/'); + expect(plain.status()).toBe(404); + expect(await plain.text()).toBe( + 'The server is configured with a public base URL of /path-base - did you mean to visit /path-base/slash/ instead?' + ); + }); + + test('serves /', async ({ page, javaScriptEnabled }) => { + await page.goto('/path-base/'); + + expect(await page.textContent('h1')).toBe('I am in the template'); + expect(await page.textContent('h2')).toBe("We're on index.svelte"); + + const mode = process.env.DEV ? 'dev' : 'prod'; + expect(await page.textContent('p')).toBe( + `Hello from the ${javaScriptEnabled ? 'client' : 'server'} in ${mode} mode!` + ); + }); + + test('serves files in source directory', async ({ request, javaScriptEnabled }) => { + test.skip(!process.env.DEV || !javaScriptEnabled); + + const response = await request.get('/path-base/source/pages/test.txt'); + expect(response.ok()).toBe(true); + expect(await response.text()).toBe('hello there world\n'); + }); + + test('paths available on server side', async ({ page }) => { + await page.goto('/path-base/base/'); + expect(await page.textContent('[data-source="base"]')).toBe('/path-base'); + expect(await page.textContent('[data-source="assets"]')).toBe('/_svelte_kit_assets'); + }); + + test('loads javascript', async ({ page, javaScriptEnabled }) => { + await page.goto('/path-base/base/'); + expect(await page.textContent('button')).toBe('clicks: 0'); + + if (javaScriptEnabled) { + await page.click('button'); + expect(await page.innerHTML('h2')).toBe('button has been clicked 1 time'); + } + }); + + test('loads CSS', async ({ page, get_computed_style }) => { + await page.goto('/path-base/base/'); + expect(await get_computed_style('p', 'color')).toBe('rgb(255, 0, 0)'); + }); + + test('sets params correctly', async ({ page, clicknav }) => { + await page.goto('/path-base/base/one'); + + expect(await page.textContent('h2')).toBe('one'); + + await clicknav('[href="/path-base/base/two"]'); + expect(await page.textContent('h2')).toBe('two'); + }); + + test('resolveRoute accounts for base path', async ({ baseURL, page, clicknav }) => { + await page.goto('/path-base/resolve-route'); + await clicknav('[data-id=target]'); + expect(page.url()).toBe(`${baseURL}/path-base/resolve-route/resolved/`); + expect(await page.textContent('h2')).toBe('resolved'); + }); +}); + +test.describe('assets path', () => { + test.skip(!process.env.PATHS_ASSETS); + + test('serves static assets with correct prefix', async ({ page, request }) => { + await page.goto('/path-base/'); + const href = await page.locator('link[rel="icon"]').getAttribute('href'); + + const response = await request.get(href ?? ''); + expect(response.status()).toBe(200); + }); +}); + +test.describe('inlineStyleThreshold', () => { + test('inlines CSS', async ({ page, javaScriptEnabled }) => { + await page.goto('/path-base/base/'); + if (process.env.DEV) { + const ssr_style = await page.$('style[data-sveltekit]'); + + if (javaScriptEnabled) { + // diff --git "a/packages/kit/test/apps/options/source/pages/inline-style/url-encoded/\346\204\233.png" "b/packages/kit/test/apps/options/source/pages/inline-style/url-encoded/\346\204\233.png" new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH { - test.skip(!process.env.PATHS_ASSETS); + test.skip(!process.env.PATHS_ASSETS); test('serves a useful 404 when visiting unprefixed path', async ({ request }) => { const html = await request.get('/slash/', { headers: { Accept: 'text/html' } }); @@ -80,7 +80,7 @@ test.describe('base path', () => { }); test.describe('assets path', () => { - test.skip(!process.env.PATHS_ASSETS); + test.skip(!process.env.PATHS_ASSETS); test('serves static assets with correct prefix', async ({ page, request }) => { await page.goto('/path-base/'); @@ -138,6 +138,20 @@ test.describe('inlineStyleThreshold', () => { expect(image_loaded).toBeTruthy(); }); + test('loads assets with URL encoded characters', async ({ page, javaScriptEnabled }) => { + test.skip(!!process.env.DEV || javaScriptEnabled); + + let image_loaded = false; + page.on('response', (response) => { + console.log(response.url()); + if (response.url().match(/%E6%84%9B.C8ge1hZN\.\w+\.png$/)) { + image_loaded = response.ok(); + } + }); + await page.goto('/path-base/inline-style/url-encoded'); + expect(image_loaded).toBeTruthy(); + }); + test('includes components dynamically imported in universal load', async ({ page, get_computed_style From abc4c64258b1938736e2cb4dfafbe13f02dc3346 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Tue, 27 Jan 2026 16:47:20 +0800 Subject: [PATCH 27/37] safeguard against trailing slashes --- packages/kit/src/utils/css.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/kit/src/utils/css.js b/packages/kit/src/utils/css.js index 0ddc9715d5b7..715efd854815 100644 --- a/packages/kit/src/utils/css.js +++ b/packages/kit/src/utils/css.js @@ -48,6 +48,15 @@ export function fix_css_urls({ css, vite_assets, static_assets, paths_assets, ba return css; } + // safe guard in case of trailing slashes (but this should never happen) + if (paths_assets.endsWith('/')) { + paths_assets = paths_assets.slice(0, -1); + } + + if (base.endsWith('/')) { + base = base.slice(0, -1); + } + const s = new MagicString(css); const parsed = parse(css); From 49029917b1c5d5b86debadd90081819bce8fbfe8 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Tue, 27 Jan 2026 17:26:23 +0800 Subject: [PATCH 28/37] decode vite asset filenames --- .../src/exports/vite/build/build_server.js | 121 ++++++++++-------- packages/kit/src/utils/css.js | 6 +- .../apps/options/test/paths-assets.test.js | 3 +- 3 files changed, 73 insertions(+), 57 deletions(-) diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 01360d44f89f..39d92498347e 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -60,10 +60,20 @@ export async function build_server_nodes( mkdirp(`${out}/server/nodes`); mkdirp(`${out}/server/stylesheets`); - /** @type {Map} */ + /** + * Stylesheet names and their contents which are below the inline threshold + * @type {Map} + */ const stylesheets_to_inline = new Map(); - if (client_chunks && kit.inlineStyleThreshold > 0) { + /** + * For CSS inlining, we either store a string or a function that returns the + * styles with the correct relative URLs + * @type {(css: string, eager_assets: Set) => string} + */ + let prepare_css_for_inlining = (css) => s(css); + + if (client_chunks && kit.inlineStyleThreshold > 0 && output_config.bundleStrategy === 'split') { for (const chunk of client_chunks) { if (chunk.type !== 'asset' || !chunk.fileName.endsWith('.css')) { continue; @@ -74,6 +84,30 @@ export async function build_server_nodes( stylesheets_to_inline.set(chunk.fileName, source); } } + + // If the client CSS has URL references to assets, we need to adjust the + // relative path so that they are correct when inlined into the document. + // Although `paths.assets` is static, we need to pass in a fake path + // `/_svelte_kit_assets` at runtime when running `vite preview` + if (kit.paths.assets || kit.paths.relative) { + const static_assets = new Set(manifest_data.assets.map((a) => a.file)); + + prepare_css_for_inlining = (css, eager_assets) => { + const transformed_css = fix_css_urls({ + css, + vite_assets: eager_assets, + static_assets, + paths_assets: '${assets}', + base: '${base}' + }); + + // only convert to a function if we have adjusted any URLs + if (css !== transformed_css) { + return `function css(assets, base) { return \`${s(transformed_css).slice(1, -1)}\`; }`; + } + return s(css); + }; + } } const { get_page_options } = create_node_analyser({ @@ -86,34 +120,6 @@ export async function build_server_nodes( static_exports }); - /** - * For CSS inlining, we either store a string or a function that returns the - * styles with the correct asset base path - * @type {(css: string, eager_assets: Set) => string} - */ - let prepare_css_for_inlining = (css) => s(css); - - // when paths.assets is set we still need the paths to be dynamic because we - // set a fake path (/_svelte_kit_assets) at runtime when running `vite preview` - if (kit.paths.assets || kit.paths.relative) { - const static_assets = new Set(manifest_data.assets.map((a) => a.file)); - prepare_css_for_inlining = (css, eager_assets) => { - // TODO: pass in manifest_data.assets - const transformed_css = fix_css_urls({ - css, - vite_assets: eager_assets, - static_assets, - paths_assets: '${assets}', - base: '${base}' - }); - // only convert to a function if there are URLs to replace - if (css !== transformed_css) { - return `function css(assets, base) { return \`${s(transformed_css).slice(1, -1)}\`; }`; - } - return s(css); - }; - } - for (let i = 0; i < manifest_data.nodes.length; i++) { const node = manifest_data.nodes[i]; @@ -176,7 +182,7 @@ export async function build_server_nodes( const entry_path = `${normalizePath(kit.outDir)}/generated/client-optimized/nodes/${i}.js`; const entry = find_deps(client_manifest, entry_path, true); - // eagerly load client stylesheets and fonts imported by the SSR-ed page to avoid FOUC. + // Eagerly load client stylesheets and fonts imported by the SSR-ed page to avoid FOUC. // However, if it is not used during SSR (not present in the server manifest), // then it can be lazily loaded in the browser. @@ -219,37 +225,46 @@ export async function build_server_nodes( `export const fonts = ${s(fonts)};` ); - // assets that have been processed by Vite (with the asset path stripped) - if (assets_path && eager_assets.size) { - eager_assets = new Set( + /** + * Assets that have been processed by Vite (decoded and with the asset path stripped) + * @type {Set} + */ + let vite_assets = new Set(); + + // Keep track of Vite asset filenames so that we avoid touching unrelated ones + // when adjusting the inlined CSS + if (stylesheets_to_inline.size && assets_path && eager_assets.size) { + vite_assets = new Set( Array.from(eager_assets).map((asset) => { - return asset.replace(`${assets_path}/`, ''); + return decodeURIComponent(asset.replace(`${assets_path}/`, '')); }) ); } - /** @type {string[]} */ - const inline_styles = []; + if (stylesheets_to_inline.size) { + /** @type {string[]} */ + const inline_styles = []; - stylesheets.forEach((file, i) => { - if (stylesheets_to_inline.has(file)) { - const filename = basename(file); - const dest = `${out}/server/stylesheets/${filename}.js`; + stylesheets.forEach((file, i) => { + if (stylesheets_to_inline.has(file)) { + const filename = basename(file); + const dest = `${out}/server/stylesheets/${filename}.js`; - let css = /** @type {string} */ (stylesheets_to_inline.get(file)); + let css = /** @type {string} */ (stylesheets_to_inline.get(file)); - fs.writeFileSync( - dest, - `// ${filename}\nexport default ${prepare_css_for_inlining(css, eager_assets)};` - ); - const name = `stylesheet_${i}`; - imports.push(`import ${name} from '../stylesheets/${filename}.js';`); - inline_styles.push(`\t${s(file)}: ${name}`); - } - }); + fs.writeFileSync( + dest, + `// ${filename}\nexport default ${prepare_css_for_inlining(css, vite_assets)};` + ); + const name = `stylesheet_${i}`; + imports.push(`import ${name} from '../stylesheets/${filename}.js';`); + inline_styles.push(`\t${s(file)}: ${name}`); + } + }); - if (inline_styles.length > 0) { - exports.push(`export const inline_styles = () => ({\n${inline_styles.join(',\n')}\n});`); + if (inline_styles.length > 0) { + exports.push(`export const inline_styles = () => ({\n${inline_styles.join(',\n')}\n});`); + } } fs.writeFileSync( diff --git a/packages/kit/src/utils/css.js b/packages/kit/src/utils/css.js index 715efd854815..5d02b2a99307 100644 --- a/packages/kit/src/utils/css.js +++ b/packages/kit/src/utils/css.js @@ -82,17 +82,19 @@ export function fix_css_urls({ css, vite_assets, static_assets, paths_assets, ba let current_prefix = url.slice(0, VITE_ASSET_PREFIX.length); let [filename] = url.slice(VITE_ASSET_PREFIX.length).split(HASH_OR_QUERY_REGEX); + const decoded = decodeURIComponent(filename); // Vite assets - if (current_prefix === VITE_ASSET_PREFIX && vite_assets.has(filename)) { + if (current_prefix === VITE_ASSET_PREFIX && vite_assets.has(decoded)) { new_prefix = paths_assets; } // Static assets else { current_prefix = url.slice(0, STATIC_ASSET_PREFIX.length); [filename] = url.slice(STATIC_ASSET_PREFIX.length).split(HASH_OR_QUERY_REGEX); + const decoded = decodeURIComponent(filename); - if (current_prefix === STATIC_ASSET_PREFIX && static_assets.has(filename)) { + if (current_prefix === STATIC_ASSET_PREFIX && static_assets.has(decoded)) { new_prefix = base; } } diff --git a/packages/kit/test/apps/options/test/paths-assets.test.js b/packages/kit/test/apps/options/test/paths-assets.test.js index 282a9838dd29..91d3045fa437 100644 --- a/packages/kit/test/apps/options/test/paths-assets.test.js +++ b/packages/kit/test/apps/options/test/paths-assets.test.js @@ -143,8 +143,7 @@ test.describe('inlineStyleThreshold', () => { let image_loaded = false; page.on('response', (response) => { - console.log(response.url()); - if (response.url().match(/%E6%84%9B.C8ge1hZN\.\w+\.png$/)) { + if (response.url().match(/%E6%84%9B\.\w+\.png$/)) { image_loaded = response.ok(); } }); From 5a6e24ef8ae58dbefd6335871a7070066f083ded Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Tue, 27 Jan 2026 17:41:08 +0800 Subject: [PATCH 29/37] a bit of clean up --- packages/kit/src/utils/css.js | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/kit/src/utils/css.js b/packages/kit/src/utils/css.js index 5d02b2a99307..18d5eddcd36e 100644 --- a/packages/kit/src/utils/css.js +++ b/packages/kit/src/utils/css.js @@ -14,20 +14,20 @@ const parse = svelte.parseCss ).css; }; -const AST_OFFSET = '