From f53a256aa55392c1893d50d118a852877b226af7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 Aug 2025 14:08:37 +0000 Subject: [PATCH 1/6] Initial plan From e3a90eccf2dd4a46dd05d460f30b409202b63b61 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 Aug 2025 14:18:47 +0000 Subject: [PATCH 2/6] Add Svelte #snippet export support in dependency scanner - Detect #snippet in Svelte files and add virtual module export - Externalize virtual-module-named-svelte-dummy modules - Add tests for Svelte snippet handling - Fixes issue #20511 where Svelte snippet exports caused scan failures Co-authored-by: sapphi-red <49056869+sapphi-red@users.noreply.github.com> --- .../__tests__/fixtures/svelte-regular.svelte | 13 ++++ .../__tests__/fixtures/svelte-snippet.svelte | 9 +++ packages/vite/src/node/__tests__/scan.spec.ts | 69 +++++++++++++++++++ packages/vite/src/node/optimizer/scan.ts | 14 ++++ 4 files changed, 105 insertions(+) create mode 100644 packages/vite/src/node/__tests__/fixtures/svelte-regular.svelte create mode 100644 packages/vite/src/node/__tests__/fixtures/svelte-snippet.svelte diff --git a/packages/vite/src/node/__tests__/fixtures/svelte-regular.svelte b/packages/vite/src/node/__tests__/fixtures/svelte-regular.svelte new file mode 100644 index 00000000000000..047ad267062605 --- /dev/null +++ b/packages/vite/src/node/__tests__/fixtures/svelte-regular.svelte @@ -0,0 +1,13 @@ + + + + +
Regular Svelte component without snippets
+Hello from snippet!
+ {/snippet} +Hello snippet!
+{/snippet} +` + + const svelteWithoutSnippet = ` + + +Regular content
+` + + // These tests verify that we detect #snippet correctly + expect(svelteWithSnippet.includes('#snippet')).toBe(true) + expect(svelteWithoutSnippet.includes('#snippet')).toBe(false) +}) + +test('svelte snippet virtual module pattern', () => { + // Test that our virtual module pattern is correctly handled + const virtualModulePath = 'virtual-module-named-svelte-dummy:test.svelte' + expect( + virtualModulePath.startsWith('virtual-module-named-svelte-dummy'), + ).toBe(true) + + // Test regex pattern for externalization + const pattern = /^virtual-module-named-svelte-dummy/ + expect(pattern.test(virtualModulePath)).toBe(true) + expect(pattern.test('regular-module')).toBe(false) +}) + +test('svelte snippet scanning behavior', async () => { + // Create a minimal Vite environment to test the scanning logic + const server = await createServer({ + configFile: false, + logLevel: 'silent', + root: path.join(import.meta.dirname, 'fixtures'), + environments: { + client: { + optimizeDeps: { + include: [], + entries: ['./svelte-snippet.svelte'], + }, + }, + }, + }) + + try { + // The scanner should handle the Svelte file with snippets without throwing errors + await server.listen() + // If we get here without errors, the scanning worked + expect(true).toBe(true) + } catch (error) { + // The test should not fail due to snippet export issues + expect(error.message).not.toContain( + '"mySnippet" is not declared in this file', + ) + } finally { + await server.close() + } +}) + test('scan jsx-runtime', async (ctx) => { const server = await createServer({ configFile: false, diff --git a/packages/vite/src/node/optimizer/scan.ts b/packages/vite/src/node/optimizer/scan.ts index 569e7bf2b493e2..b919fb8e7ade03 100644 --- a/packages/vite/src/node/optimizer/scan.ts +++ b/packages/vite/src/node/optimizer/scan.ts @@ -477,6 +477,15 @@ function esbuildScanPlugin( external: true, })) + // virtual-module-named-svelte-dummy modules (for Svelte snippets) + build.onResolve( + { filter: /^virtual-module-named-svelte-dummy/ }, + ({ path }) => ({ + path, + external: true, + }), + ) + // local scripts (` + +{#snippet mySnippet()} + snippet! +{/snippet} diff --git a/packages/vite/src/node/__tests__/fixtures/svelte-regular.svelte b/packages/vite/src/node/__tests__/fixtures/svelte-regular.svelte deleted file mode 100644 index 047ad267062605..00000000000000 --- a/packages/vite/src/node/__tests__/fixtures/svelte-regular.svelte +++ /dev/null @@ -1,13 +0,0 @@ - - - - -Regular Svelte component without snippets
-Hello from snippet!
- {/snippet} -Hello snippet!
-{/snippet} -` - - const svelteWithoutSnippet = ` - - -Regular content
-` - - // These tests verify that we detect #snippet correctly - expect(svelteWithSnippet.includes('#snippet')).toBe(true) - expect(svelteWithoutSnippet.includes('#snippet')).toBe(false) -}) - -test('svelte snippet virtual module pattern', () => { - // Test that our virtual module pattern is correctly handled - const virtualModulePath = 'virtual-module-named-svelte-dummy:test.svelte' - expect( - virtualModulePath.startsWith('virtual-module-named-svelte-dummy'), - ).toBe(true) - - // Test regex pattern for externalization - const pattern = /^virtual-module-named-svelte-dummy/ - expect(pattern.test(virtualModulePath)).toBe(true) - expect(pattern.test('regular-module')).toBe(false) -}) - -test('svelte snippet scanning behavior', async () => { - // Create a minimal Vite environment to test the scanning logic - const server = await createServer({ - configFile: false, - logLevel: 'silent', - root: path.join(import.meta.dirname, 'fixtures'), - environments: { - client: { - optimizeDeps: { - include: [], - entries: ['./svelte-snippet.svelte'], - }, +test('scan svelte', async () => { + const config = await resolveConfig( + { + configFile: false, + root: path.join(import.meta.dirname, 'fixtures', 'scan-svelte'), + optimizeDeps: { + include: [], + entries: ['./svelte-snippet.svelte'], + extensions: ['.svelte'], }, }, - }) - - try { - // The scanner should handle the Svelte file with snippets without throwing errors - await server.listen() - // If we get here without errors, the scanning worked - expect(true).toBe(true) - } catch (error) { - // The test should not fail due to snippet export issues - expect(error.message).not.toContain( - '"mySnippet" is not declared in this file', - ) - } finally { - await server.close() - } + 'serve', + ) + const environment = new ScanEnvironment('client', config) + await environment.init() + const { result } = scanImports(environment) + await result }) test('scan jsx-runtime', async (ctx) => { diff --git a/packages/vite/src/node/optimizer/scan.ts b/packages/vite/src/node/optimizer/scan.ts index b919fb8e7ade03..adbe2f9f629034 100644 --- a/packages/vite/src/node/optimizer/scan.ts +++ b/packages/vite/src/node/optimizer/scan.ts @@ -477,14 +477,11 @@ function esbuildScanPlugin( external: true, })) - // virtual-module-named-svelte-dummy modules (for Svelte snippets) - build.onResolve( - { filter: /^virtual-module-named-svelte-dummy/ }, - ({ path }) => ({ - path, - external: true, - }), - ) + // dummy module for Svelte file with snippets + build.onResolve({ filter: /^svelte-snippet-dummy:/ }, ({ path }) => ({ + path, + external: true, + })) // local scripts (`