diff --git a/.changeset/fuzzy-hairs-obey.md b/.changeset/fuzzy-hairs-obey.md
new file mode 100644
index 000000000..e3f263a51
--- /dev/null
+++ b/.changeset/fuzzy-hairs-obey.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/vite-plugin-svelte': patch
+---
+
+fix: ensure compiled css is returned when reloading during dev with ssr (e.g. SvelteKit)
diff --git a/packages/e2e-tests/build-watch/__tests__/build-watch.spec.ts b/packages/e2e-tests/build-watch/__tests__/build-watch.spec.ts
index c99b5b8af..cf5cb0e6d 100644
--- a/packages/e2e-tests/build-watch/__tests__/build-watch.spec.ts
+++ b/packages/e2e-tests/build-watch/__tests__/build-watch.spec.ts
@@ -8,7 +8,8 @@ import {
sleep,
getColor,
browserLogs,
- e2eServer
+ e2eServer,
+ getWatchErrors
} from '~utils';
import * as vite from 'vite';
@@ -63,17 +64,6 @@ describe.runIf(isBuildWatch)('build-watch', () => {
const updateApp = editFileAndWaitForBuildWatchComplete.bind(null, 'src/App.svelte');
const updateStore = editFileAndWaitForBuildWatchComplete.bind(null, 'src/stores/hmr-stores.js');
- const getWatchErrors = () =>
- isRolldownVite
- ? e2eServer.logs.watch.err.filter(
- (m) =>
- ![
- 'Support for rolldown-vite in vite-plugin-svelte is experimental',
- 'See https://github.com/sveltejs/vite-plugin-svelte/issues/1143'
- ].some((s) => m.includes(s))
- )
- : e2eServer.logs.watch.err;
-
test('should have expected initial state', async () => {
// initial state, both counters 0, both labels red
expect(await getText('#hmr-test-1 .counter')).toBe('0');
diff --git a/packages/e2e-tests/kit-node/__tests__/kit.spec.ts b/packages/e2e-tests/kit-node/__tests__/kit.spec.ts
index b33ea7914..6da8fffa2 100644
--- a/packages/e2e-tests/kit-node/__tests__/kit.spec.ts
+++ b/packages/e2e-tests/kit-node/__tests__/kit.spec.ts
@@ -12,7 +12,8 @@ import {
fetchPageText,
reloadPage,
readFileContent,
- IS_SVELTE_BASELINE
+ IS_SVELTE_BASELINE,
+ getServerErrors
} from '~utils';
import glob from 'tiny-glob';
@@ -95,6 +96,11 @@ describe('kit-node', () => {
expect(browserLogs.some((x) => x === 'onMount dynamic imported isSSR: false')).toBe(true);
});
+ it('should load dynamic import with css', async () => {
+ expect(await getText('#dynamic-imported')).toBe("i'm blue");
+ expect(await getColor('#dynamic-imported')).toBe('blue');
+ });
+
it('should respect transforms', async () => {
expect(await getText('#js-transform')).toBe('Hello world');
expect(await getColor('#css-transform')).toBe('red');
@@ -192,9 +198,15 @@ describe('kit-node', () => {
it('should serve changes even after page reload', async () => {
expect(await getColor('h1')).toBe('green');
expect(await getText('#hmr-test2')).toBe('bar');
+ expect(await getText('#dynamic-imported')).toBe("i'm blue");
+ expect(await getColor('#dynamic-imported')).toBe('blue');
await reloadPage();
expect(await getColor('h1')).toBe('green');
expect(await getText('#hmr-test2')).toBe('bar');
+ await page.waitForSelector('#dynamic-imported', { strict: true });
+ expect(await getText('#dynamic-imported')).toBe("i'm blue");
+ expect(await getColor('#dynamic-imported')).toBe('blue');
+ expect(getServerErrors(), 'error log of `vite dev` is not empty after reload').toEqual([]);
});
describe('child component update', () => {
diff --git a/packages/e2e-tests/kit-node/package.json b/packages/e2e-tests/kit-node/package.json
index 18b31ffa8..ae6304d18 100644
--- a/packages/e2e-tests/kit-node/package.json
+++ b/packages/e2e-tests/kit-node/package.json
@@ -3,8 +3,8 @@
"version": "0.0.0",
"private": true,
"scripts": {
- "dev": "vite dev",
- "build": "vite build",
+ "dev": "svelte-kit sync && vite dev",
+ "build": "svelte-kit sync && vite build",
"preview": "vite preview",
"prepare": "svelte-kit sync || echo ''",
"sync": "svelte-kit sync || echo ''",
@@ -18,8 +18,9 @@
"@sveltejs/package": "^2.4.1",
"@sveltejs/vite-plugin-svelte": "workspace:^",
"e2e-test-dep-svelte-api-only": "file:../_test_dependencies/svelte-api-only",
- "e2e-test-dep-vite-plugins": "file:../_test_dependencies/vite-plugins",
"e2e-test-dep-svelte-nested-workspace-devdep": "../_test_dependencies/svelte-nested-workspace-devdep",
+ "e2e-test-dep-vite-plugins": "file:../_test_dependencies/vite-plugins",
+ "sass": "^1.90.0",
"svelte": "^5.38.0",
"svelte-check": "^4.3.1",
"svelte-i18n": "^4.0.1",
diff --git a/packages/e2e-tests/kit-node/src/routes/+page.svelte b/packages/e2e-tests/kit-node/src/routes/+page.svelte
index 0b58211e2..339a1232f 100644
--- a/packages/e2e-tests/kit-node/src/routes/+page.svelte
+++ b/packages/e2e-tests/kit-node/src/routes/+page.svelte
@@ -4,6 +4,8 @@
import Counter from '$lib/Counter.svelte';
import Child from '$lib/Child.svelte';
import { setSomeContext } from 'e2e-test-dep-svelte-api-only';
+ import { browser } from '$app/environment';
+
export let data = {};
$: load_status = data?.load_status ?? 'NOT_LOADED';
const jsTransform = '__JS_TRANSFORM_1__';
@@ -38,6 +40,13 @@
{jsTransform}
Hello world
+ {#if browser}
+ {#await import('./DynamicImported.svelte').then((m) => m.default)}
+ loading...
+ {:then DynamicImported}
+
+ {/await}
+ {/if}
diff --git a/packages/e2e-tests/kit-node/src/routes/DynamicImported.svelte b/packages/e2e-tests/kit-node/src/routes/DynamicImported.svelte
new file mode 100644
index 000000000..8dd31c28a
--- /dev/null
+++ b/packages/e2e-tests/kit-node/src/routes/DynamicImported.svelte
@@ -0,0 +1,7 @@
+i'm blue
+
+
diff --git a/packages/e2e-tests/kit-node/svelte.config.js b/packages/e2e-tests/kit-node/svelte.config.js
index 17c5095f0..67b6c8747 100644
--- a/packages/e2e-tests/kit-node/svelte.config.js
+++ b/packages/e2e-tests/kit-node/svelte.config.js
@@ -1,6 +1,9 @@
import node from '@sveltejs/adapter-node';
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
+
/** @type {import('@sveltejs/kit').Config} */
const config = {
+ preprocess: vitePreprocess(),
kit: {
adapter: node()
}
diff --git a/packages/e2e-tests/kit-node/vite.config.js b/packages/e2e-tests/kit-node/vite.config.js
index c3d4fca29..4df72608e 100644
--- a/packages/e2e-tests/kit-node/vite.config.js
+++ b/packages/e2e-tests/kit-node/vite.config.js
@@ -19,5 +19,10 @@ export default {
optimizeDeps: {
// eagerly include these, otherwise vite optimizer might interfere with restarting while the test is running
include: ['svelte-i18n', 'e2e-test-dep-svelte-api-only']
+ },
+ css: {
+ postcss: {
+ plugins: [{ postcssPlugin: 'noop' }]
+ }
}
};
diff --git a/packages/e2e-tests/testUtils.ts b/packages/e2e-tests/testUtils.ts
index b749ee3d7..349376110 100644
--- a/packages/e2e-tests/testUtils.ts
+++ b/packages/e2e-tests/testUtils.ts
@@ -18,6 +18,10 @@ import {
waitForViteConnect
} from './vitestSetup.js';
+import * as vite from 'vite';
+//@ts-ignore
+const isRolldownVite = !!vite.rolldownVersion;
+
import { VERSION } from 'svelte/compiler';
export const IS_SVELTE_BASELINE = VERSION === '5.0.0';
@@ -354,3 +358,28 @@ export function readVitePrebundleMetadata() {
}
throw new Error('Unable to find vite prebundle metadata');
}
+
+export function getServerErrors() {
+ return filterMessages(e2eServer.logs.server.err);
+}
+
+export function getWatchErrors() {
+ return filterMessages(e2eServer.logs.watch.err);
+}
+function filterMessages(arr) {
+ if (arr.length === 0) {
+ return arr;
+ }
+ const excludes = [];
+ if (isRolldownVite) {
+ excludes.push(
+ 'Support for rolldown-vite in vite-plugin-svelte is experimental',
+ 'See https://github.com/sveltejs/vite-plugin-svelte/issues/1143'
+ );
+ }
+ if (excludes.length > 0) {
+ return arr.filter((m) => !excludes.some((e) => m.includes(e)));
+ } else {
+ return arr;
+ }
+}
diff --git a/packages/vite-plugin-svelte/src/plugins/load-compiled-css.js b/packages/vite-plugin-svelte/src/plugins/load-compiled-css.js
index b2616b198..0a9e9c233 100644
--- a/packages/vite-plugin-svelte/src/plugins/load-compiled-css.js
+++ b/packages/vite-plugin-svelte/src/plugins/load-compiled-css.js
@@ -8,14 +8,17 @@ const filter = { id: SVELTE_VIRTUAL_STYLE_ID_REGEX };
* @returns {import('vite').Plugin}
*/
export function loadCompiledCss(api) {
- let isBuildWatch = false;
+ let useLocalCache = false;
+
/** @type{Map} */
const buildWatchCssCache = new Map();
return {
name: 'vite-plugin-svelte:load-compiled-css',
configResolved(c) {
- isBuildWatch = !!c.build?.watch;
+ const isDev = c.command === 'serve';
+ const isBuildWatch = !!c.build?.watch;
+ useLocalCache = isDev || isBuildWatch;
},
resolveId: {
@@ -34,9 +37,9 @@ export function loadCompiledCss(api) {
return;
}
let cachedCss = this.getModuleInfo(svelteRequest.filename)?.meta.svelte?.css;
- // in build --watch getModuleInfo only returns changed module data.
+ // in `build --watch` or dev ssr reloads getModuleInfo only returns changed module data.
// To ensure virtual css is loaded unchanged, we cache it here separately
- if (isBuildWatch) {
+ if (useLocalCache) {
if (cachedCss) {
buildWatchCssCache.set(svelteRequest.filename, cachedCss);
} else {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2ba96eac8..5a3872d63 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -257,7 +257,7 @@ importers:
version: 7.1.1(@types/node@22.17.0)(sass@1.90.0)(stylus@0.64.0)(yaml@2.8.0)
vite-plugin-inspect:
specifier: /home/dominikg/develop/vite-plugin-inspect
- version: link:../../../../../../../../../home/dominikg/develop/vite-plugin-inspect
+ version: link:../../../../../vite-plugin-inspect
packages/e2e-tests/configfile-custom:
dependencies:
@@ -489,6 +489,9 @@ importers:
e2e-test-dep-vite-plugins:
specifier: file:../_test_dependencies/vite-plugins
version: file:packages/e2e-tests/_test_dependencies/vite-plugins
+ sass:
+ specifier: ^1.90.0
+ version: 1.90.0
svelte:
specifier: ^5.38.0
version: 5.38.0
@@ -4579,14 +4582,6 @@ snapshots:
chai: 5.2.0
tinyrainbow: 2.0.0
- '@vitest/mocker@3.2.4(vite@7.1.1(@types/node@20.19.9)(sass@1.90.0)(stylus@0.64.0)(yaml@2.8.0))':
- dependencies:
- '@vitest/spy': 3.2.4
- estree-walker: 3.0.3
- magic-string: 0.30.17
- optionalDependencies:
- vite: 7.1.1(@types/node@20.19.9)(sass@1.90.0)(stylus@0.64.0)(yaml@2.8.0)
-
'@vitest/mocker@3.2.4(vite@7.1.1(@types/node@22.17.0)(sass@1.90.0)(stylus@0.64.0)(yaml@2.8.0))':
dependencies:
'@vitest/spy': 3.2.4
@@ -6410,7 +6405,7 @@ snapshots:
dependencies:
'@types/chai': 5.2.2
'@vitest/expect': 3.2.4
- '@vitest/mocker': 3.2.4(vite@7.1.1(@types/node@20.19.9)(sass@1.90.0)(stylus@0.64.0)(yaml@2.8.0))
+ '@vitest/mocker': 3.2.4(vite@7.1.1(@types/node@22.17.0)(sass@1.90.0)(stylus@0.64.0)(yaml@2.8.0))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4