From 9e69cf53dc27da121662169dc2ae3ca1d8945181 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:50:46 +0900 Subject: [PATCH 1/4] fix(optimize-deps): hoist CJS interop assignment --- .../src/node/__tests__/plugins/import.spec.ts | 88 ++++++++++--------- .../vite/src/node/plugins/importAnalysis.ts | 21 +++-- 2 files changed, 59 insertions(+), 50 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/import.spec.ts b/packages/vite/src/node/__tests__/plugins/import.spec.ts index ac5b94c9be9624..d464b77e2482d0 100644 --- a/packages/vite/src/node/__tests__/plugins/import.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/import.spec.ts @@ -19,12 +19,14 @@ describe('runTransform', () => { isNodeMode, config, ) - if (result !== undefined) { - expect(result.split('\n').length, 'result line count').toBe( - importExp.split('\n').length, - ) - } - return result?.replaceAll(';', ';\n') + if (result === undefined) return undefined + const joined = result.hoistedAssignments + ? `${result.hoistedAssignments}; ${result.importLine}` + : result.importLine + expect(joined.split('\n').length, 'result line count').toBe( + importExp.split('\n').length, + ) + return joined.replaceAll(';', ';\n') } beforeEach(() => { @@ -38,10 +40,10 @@ describe('runTransform', () => { false, ), ).toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const useState = __vite__cjsImport0_react["useState"]; + "const useState = __vite__cjsImport0_react["useState"]; const Component = __vite__cjsImport0_react["Component"]; - const fake = __vite__cjsImport0_react["👋"]" + const fake = __vite__cjsImport0_react["👋"]; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) expect( runTransformCjsImport( @@ -49,43 +51,43 @@ describe('runTransform', () => { true, ), ).toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const useState = __vite__cjsImport0_react["useState"]; + "const useState = __vite__cjsImport0_react["useState"]; const Component = __vite__cjsImport0_react["Component"]; - const fake = __vite__cjsImport0_react["👋"]" + const fake = __vite__cjsImport0_react["👋"]; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) }) test('import default specifier', () => { expect(runTransformCjsImport('import React from "react"', false)) .toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const React = !__vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react : __vite__cjsImport0_react.default" + "const React = !__vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react : __vite__cjsImport0_react.default; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) expect(runTransformCjsImport('import React from "react"', true)) .toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const React = __vite__cjsImport0_react" + "const React = __vite__cjsImport0_react; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) expect( runTransformCjsImport('import { default as React } from "react"', false), ).toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const React = !__vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react : __vite__cjsImport0_react.default" + "const React = !__vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react : __vite__cjsImport0_react.default; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) }) test('import all specifier', () => { expect(runTransformCjsImport('import * as react from "react"', false)) .toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const react = ((m, n) => n || !m?.__esModule ? { ...typeof m === "object" && !Array.isArray(m) || typeof m === "function" ? m : {}, default: m} : m)(__vite__cjsImport0_react, 0)" + "const react = ((m, n) => n || !m?.__esModule ? { ...typeof m === "object" && !Array.isArray(m) || typeof m === "function" ? m : {}, default: m} : m)(__vite__cjsImport0_react, 0); + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) expect(runTransformCjsImport('import * as react from "react"', true)) .toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const react = ((m, n) => n || !m?.__esModule ? { ...typeof m === "object" && !Array.isArray(m) || typeof m === "function" ? m : {}, default: m} : m)(__vite__cjsImport0_react, 1)" + "const react = ((m, n) => n || !m?.__esModule ? { ...typeof m === "object" && !Array.isArray(m) || typeof m === "function" ? m : {}, default: m} : m)(__vite__cjsImport0_react, 1); + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) }) @@ -115,11 +117,11 @@ describe('runTransform', () => { false, ), ).toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const __vite__cjsExportI_useState = __vite__cjsImport0_react["useState"]; + "const __vite__cjsExportI_useState = __vite__cjsImport0_react["useState"]; const __vite__cjsExportI_Component = __vite__cjsImport0_react["Component"]; const __vite__cjsExportL_1d0452e3 = __vite__cjsImport0_react["👋"]; - export { __vite__cjsExportI_useState as useState, __vite__cjsExportI_Component as Component, __vite__cjsExportL_1d0452e3 as "👋" }" + export { __vite__cjsExportI_useState as useState, __vite__cjsExportI_Component as Component, __vite__cjsExportL_1d0452e3 as "👋" }; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) expect( runTransformCjsImport( @@ -127,11 +129,11 @@ describe('runTransform', () => { true, ), ).toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const __vite__cjsExportI_useState = __vite__cjsImport0_react["useState"]; + "const __vite__cjsExportI_useState = __vite__cjsImport0_react["useState"]; const __vite__cjsExportI_Component = __vite__cjsImport0_react["Component"]; const __vite__cjsExportL_1d0452e3 = __vite__cjsImport0_react["👋"]; - export { __vite__cjsExportI_useState as useState, __vite__cjsExportI_Component as Component, __vite__cjsExportL_1d0452e3 as "👋" }" + export { __vite__cjsExportI_useState as useState, __vite__cjsExportI_Component as Component, __vite__cjsExportL_1d0452e3 as "👋" }; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) expect( @@ -140,34 +142,34 @@ describe('runTransform', () => { false, ), ).toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const __vite__cjsExportI_useStateAlias = __vite__cjsImport0_react["useState"]; + "const __vite__cjsExportI_useStateAlias = __vite__cjsImport0_react["useState"]; const __vite__cjsExportI_ComponentAlias = __vite__cjsImport0_react["Component"]; const __vite__cjsExportL_5d57d39e = __vite__cjsImport0_react["👋"]; - export { __vite__cjsExportI_useStateAlias as useStateAlias, __vite__cjsExportI_ComponentAlias as ComponentAlias, __vite__cjsExportL_5d57d39e as "👍" }" + export { __vite__cjsExportI_useStateAlias as useStateAlias, __vite__cjsExportI_ComponentAlias as ComponentAlias, __vite__cjsExportL_5d57d39e as "👍" }; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) }) test('export default specifier', () => { expect(runTransformCjsImport('export { default } from "react"', false)) .toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const __vite__cjsExportDefault_0 = !__vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react : __vite__cjsImport0_react.default; - export default __vite__cjsExportDefault_0" + "const __vite__cjsExportDefault_0 = !__vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react : __vite__cjsImport0_react.default; + export default __vite__cjsExportDefault_0; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) expect(runTransformCjsImport('export { default } from "react"', true)) .toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const __vite__cjsExportDefault_0 = __vite__cjsImport0_react; - export default __vite__cjsExportDefault_0" + "const __vite__cjsExportDefault_0 = __vite__cjsImport0_react; + export default __vite__cjsExportDefault_0; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) expect( runTransformCjsImport('export { default as React} from "react"', false), ).toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const __vite__cjsExportI_React = !__vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react : __vite__cjsImport0_react.default; - export { __vite__cjsExportI_React as React }" + "const __vite__cjsExportI_React = !__vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react : __vite__cjsImport0_react.default; + export { __vite__cjsExportI_React as React }; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) expect( @@ -176,9 +178,9 @@ describe('runTransform', () => { false, ), ).toMatchInlineSnapshot(` - "import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; - const __vite__cjsExportDefault_0 = __vite__cjsImport0_react["Component"]; - export default __vite__cjsExportDefault_0" + "const __vite__cjsExportDefault_0 = __vite__cjsImport0_react["Component"]; + export default __vite__cjsExportDefault_0; + import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"" `) }) }) diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index d15038b477574b..b463a0d7c63019 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -964,9 +964,15 @@ export function interopNamedImports( config, ) if (rewritten) { - str.overwrite(expStart, expEnd, rewritten + getLineBreaks(exp), { - contentOnly: true, - }) + str.overwrite( + expStart, + expEnd, + rewritten.importLine + getLineBreaks(exp), + { contentOnly: true }, + ) + if (rewritten.hoistedAssignments) { + str.appendLeft(0, rewritten.hoistedAssignments + ';') + } } else { // #1439 export * from '...' str.overwrite( @@ -1009,7 +1015,7 @@ export function transformCjsImport( importer: string, isNodeMode: boolean, config: ResolvedConfig, -): string | undefined { +): { importLine: string; hoistedAssignments?: string } | undefined { const node = parseAst(importExp).body[0] // `export * from '...'` may cause unexpected problem, so give it a warning @@ -1028,7 +1034,7 @@ export function transformCjsImport( node.type === 'ExportNamedDeclaration' ) { if (!node.specifiers.length) { - return `import "${url}"` + return { importLine: `import "${url}"` } } const importNames: ImportNameSpecifier[] = [] @@ -1076,7 +1082,8 @@ export function transformCjsImport( const cjsModuleName = makeLegalIdentifier( `__vite__cjsImport${importIndex}_${rawUrl}`, ) - const lines: string[] = [`import ${cjsModuleName} from "${url}"`] + const importLine = `import ${cjsModuleName} from "${url}"` + const lines: string[] = [] importNames.forEach(({ importedName, localName }) => { if (importedName === '*') { lines.push( @@ -1101,7 +1108,7 @@ export function transformCjsImport( lines.push(`export { ${exportNames.join(', ')} }`) } - return lines.join('; ') + return { importLine, hoistedAssignments: lines.join('; ') } } } From a77248682006267ba288abf153c56baa62f06cfb Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:58:05 +0900 Subject: [PATCH 2/4] chore: update snapshot --- playground/js-sourcemap/__tests__/js-sourcemap.spec.ts | 2 +- playground/worker/__tests__/iife/worker-iife.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts b/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts index 84fdc1412a6f9d..2943ebed745085 100644 --- a/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts +++ b/playground/js-sourcemap/__tests__/js-sourcemap.spec.ts @@ -134,7 +134,7 @@ if (!isBuild) { ], "version": 3, }, - visualization: "https://evanw.github.io/source-map-visualization/#MjQ4AC8vIHByZXR0aWVyLWlnbm9yZQppbXBvcnQgX192aXRlX19janNJbXBvcnQwX192aXRlanNfdGVzdEltcG9ydGVlUGtnIGZyb20gIi9ub2RlX21vZHVsZXMvLnZpdGUvZGVwcy9Adml0ZWpzX3Rlc3QtaW1wb3J0ZWUtcGtnLmpzP3Y9MDAwMDAwMDAiOyBjb25zdCBmb28gPSBfX3ZpdGVfX2Nqc0ltcG9ydDBfX3ZpdGVqc190ZXN0SW1wb3J0ZWVQa2dbImZvbyJdOwpjb25zb2xlLmxvZygid2l0aC1tdWx0aWxpbmUtaW1wb3J0IiwgZm9vKTsKMjQ4AHsibWFwcGluZ3MiOiI7QUFDQSxTQUNFLFdBQ0s7QUFFUCxRQUFRLElBQUkseUJBQXlCLElBQUkiLCJzb3VyY2VzIjpbIndpdGgtbXVsdGlsaW5lLWltcG9ydC50cyJdLCJ2ZXJzaW9uIjozLCJzb3VyY2VzQ29udGVudCI6WyIvLyBwcmV0dGllci1pZ25vcmVcbmltcG9ydCB7XG4gIGZvb1xufSBmcm9tICdAdml0ZWpzL3Rlc3QtaW1wb3J0ZWUtcGtnJ1xuXG5jb25zb2xlLmxvZygnd2l0aC1tdWx0aWxpbmUtaW1wb3J0JywgZm9vKVxuIl19" + visualization: "https://evanw.github.io/source-map-visualization/#MjQ3AGNvbnN0IGZvbyA9IF9fdml0ZV9fY2pzSW1wb3J0MF9fdml0ZWpzX3Rlc3RJbXBvcnRlZVBrZ1siZm9vIl07Ly8gcHJldHRpZXItaWdub3JlCmltcG9ydCBfX3ZpdGVfX2Nqc0ltcG9ydDBfX3ZpdGVqc190ZXN0SW1wb3J0ZWVQa2cgZnJvbSAiL25vZGVfbW9kdWxlcy8udml0ZS9kZXBzL0B2aXRlanNfdGVzdC1pbXBvcnRlZS1wa2cuanM/dj0wMDAwMDAwMCI7CmNvbnNvbGUubG9nKCJ3aXRoLW11bHRpbGluZS1pbXBvcnQiLCBmb28pOwoyNDgAeyJtYXBwaW5ncyI6IjtBQUNBLFNBQ0UsV0FDSztBQUVQLFFBQVEsSUFBSSx5QkFBeUIsSUFBSSIsInNvdXJjZXMiOlsid2l0aC1tdWx0aWxpbmUtaW1wb3J0LnRzIl0sInZlcnNpb24iOjMsInNvdXJjZXNDb250ZW50IjpbIi8vIHByZXR0aWVyLWlnbm9yZVxuaW1wb3J0IHtcbiAgZm9vXG59IGZyb20gJ0B2aXRlanMvdGVzdC1pbXBvcnRlZS1wa2cnXG5cbmNvbnNvbGUubG9nKCd3aXRoLW11bHRpbGluZS1pbXBvcnQnLCBmb28pXG4iXX0=" } `) }) diff --git a/playground/worker/__tests__/iife/worker-iife.spec.ts b/playground/worker/__tests__/iife/worker-iife.spec.ts index b2989f85a8833d..0840621e935a6d 100644 --- a/playground/worker/__tests__/iife/worker-iife.spec.ts +++ b/playground/worker/__tests__/iife/worker-iife.spec.ts @@ -213,7 +213,7 @@ test.runIf(isServe)('sourcemap is correct after env is injected', async () => { ], "version": 3, }, - visualization: "https://evanw.github.io/source-map-visualization/#OTkwAAo7CmltcG9ydCB7IG1zZyBhcyBtc2dGcm9tRGVwIH0gZnJvbSAiL2lpZmUvbm9kZV9tb2R1bGVzLy52aXRlLWlpZmUvZGVwcy9Adml0ZWpzX3Rlc3QtZGVwLXRvLW9wdGltaXplLmpzP3Y9MDAwMDAwMDAiOwppbXBvcnQgX192aXRlX19janNJbXBvcnQyX192aXRlanNfdGVzdFdvcmtlckRlcENqcyBmcm9tICIvaWlmZS9ub2RlX21vZHVsZXMvLnZpdGUtaWlmZS9kZXBzL0B2aXRlanNfdGVzdC13b3JrZXItZGVwLWNqcy5qcz92PTAwMDAwMDAwIjsgY29uc3QgZGVwQ2pzID0gX192aXRlX19janNJbXBvcnQyX192aXRlanNfdGVzdFdvcmtlckRlcENqczsKaW1wb3J0IHsgbW9kZSwgbXNnIH0gZnJvbSAiL2lpZmUvbW9kdWxlcy93b3JrZXJJbXBvcnQudHMiOwppbXBvcnQgeyBidW5kbGVXaXRoUGx1Z2luIH0gZnJvbSAiL2lpZmUvbW9kdWxlcy90ZXN0LXBsdWdpbi5qcyI7CmltcG9ydCB2aXRlU3ZnIGZyb20gIi9paWZlL3ZpdGUuc3ZnP2ltcG9ydCI7CmNvbnN0IG1ldGFVcmwgPSBpbXBvcnQubWV0YS51cmw7CnNlbGYub25tZXNzYWdlID0gKGUpID0+IHsKCWlmIChlLmRhdGEgPT09ICJwaW5nIikgewoJCXNlbGYucG9zdE1lc3NhZ2UoewoJCQltc2csCgkJCW1vZGUsCgkJCWJ1bmRsZVdpdGhQbHVnaW4sCgkJCXZpdGVTdmcsCgkJCW1ldGFVcmwsCgkJCW5hbWUsCgkJCWRlcENqcwoJCX0pOwoJfQoJaWYgKGUuZGF0YSA9PT0gInBpbmctdW5pY29kZSIpIHsKCQlzZWxmLnBvc3RNZXNzYWdlKHsKCQkJbXNnOiAi4oCicG9uZ+KAoiIsCgkJCW1vZGUsCgkJCWJ1bmRsZVdpdGhQbHVnaW4sCgkJCXZpdGVTdmcsCgkJCW1ldGFVcmwsCgkJCW5hbWUsCgkJCWRlcENqcwoJCX0pOwoJfQp9OwpzZWxmLnBvc3RNZXNzYWdlKHsKCW1zZywKCW1vZGUsCglidW5kbGVXaXRoUGx1Z2luLAoJbXNnRnJvbURlcCwKCXZpdGVTdmcsCgltZXRhVXJsLAoJbmFtZSwKCWRlcENqcwp9KTsKLy8gZm9yIHNvdXJjZW1hcApjb25zb2xlLmxvZygibXktd29ya2VyLmpzIik7CjEzOTYAeyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6Ijs7QUFBQSxTQUFTLE9BQU8sa0JBQWtCO0FBQ2xDLE9BQU8sWUFBWTtBQUNuQixTQUFTLE1BQU0sV0FBVztBQUMxQixTQUFTLHdCQUF3QjtBQUNqQyxPQUFPLGFBQWE7QUFDcEIsTUFBTSxVQUFVLE9BQU8sS0FBSztBQUU1QixLQUFLLGFBQWEsTUFBTTtBQUN0QixLQUFJLEVBQUUsU0FBUyxRQUFRO0FBQ3JCLE9BQUssWUFBWTtHQUNmO0dBQ0E7R0FDQTtHQUNBO0dBQ0E7R0FDQTtHQUNBO0dBQ0QsQ0FBQzs7QUFFSixLQUFJLEVBQUUsU0FBUyxnQkFBZ0I7QUFDN0IsT0FBSyxZQUFZO0dBQ2YsS0FBSztHQUNMO0dBQ0E7R0FDQTtHQUNBO0dBQ0E7R0FDQTtHQUNELENBQUM7OztBQUdOLEtBQUssWUFBWTtDQUNmO0NBQ0E7Q0FDQTtDQUNBO0NBQ0E7Q0FDQTtDQUNBO0NBQ0E7Q0FDRCxDQUFDOztBQUdGLFFBQVEsSUFBSSxlQUFlIiwiaWdub3JlTGlzdCI6W10sInNvdXJjZXMiOlsibXktd29ya2VyLnRzP3dvcmtlcl9maWxlJnR5cGU9bW9kdWxlIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IG1zZyBhcyBtc2dGcm9tRGVwIH0gZnJvbSAnQHZpdGVqcy90ZXN0LWRlcC10by1vcHRpbWl6ZSdcbmltcG9ydCBkZXBDanMgZnJvbSAnQHZpdGVqcy90ZXN0LXdvcmtlci1kZXAtY2pzJ1xuaW1wb3J0IHsgbW9kZSwgbXNnIH0gZnJvbSAnLi9tb2R1bGVzL3dvcmtlckltcG9ydC5qcydcbmltcG9ydCB7IGJ1bmRsZVdpdGhQbHVnaW4gfSBmcm9tICcuL21vZHVsZXMvdGVzdC1wbHVnaW4nXG5pbXBvcnQgdml0ZVN2ZyBmcm9tICcuL3ZpdGUuc3ZnJ1xuY29uc3QgbWV0YVVybCA9IGltcG9ydC5tZXRhLnVybFxuXG5zZWxmLm9ubWVzc2FnZSA9IChlKSA9PiB7XG4gIGlmIChlLmRhdGEgPT09ICdwaW5nJykge1xuICAgIHNlbGYucG9zdE1lc3NhZ2Uoe1xuICAgICAgbXNnLFxuICAgICAgbW9kZSxcbiAgICAgIGJ1bmRsZVdpdGhQbHVnaW4sXG4gICAgICB2aXRlU3ZnLFxuICAgICAgbWV0YVVybCxcbiAgICAgIG5hbWUsXG4gICAgICBkZXBDanMsXG4gICAgfSlcbiAgfVxuICBpZiAoZS5kYXRhID09PSAncGluZy11bmljb2RlJykge1xuICAgIHNlbGYucG9zdE1lc3NhZ2Uoe1xuICAgICAgbXNnOiAn4oCicG9uZ+KAoicsXG4gICAgICBtb2RlLFxuICAgICAgYnVuZGxlV2l0aFBsdWdpbixcbiAgICAgIHZpdGVTdmcsXG4gICAgICBtZXRhVXJsLFxuICAgICAgbmFtZSxcbiAgICAgIGRlcENqcyxcbiAgICB9KVxuICB9XG59XG5zZWxmLnBvc3RNZXNzYWdlKHtcbiAgbXNnLFxuICBtb2RlLFxuICBidW5kbGVXaXRoUGx1Z2luLFxuICBtc2dGcm9tRGVwLFxuICB2aXRlU3ZnLFxuICBtZXRhVXJsLFxuICBuYW1lLFxuICBkZXBDanMsXG59KVxuXG4vLyBmb3Igc291cmNlbWFwXG5jb25zb2xlLmxvZygnbXktd29ya2VyLmpzJylcbiJdfQ==" + visualization: "https://evanw.github.io/source-map-visualization/#MTEwNgBjb25zdCBkZXBDanMgPSBfX3ZpdGVfX2Nqc0ltcG9ydDJfX3ZpdGVqc190ZXN0V29ya2VyRGVwQ2pzO2ltcG9ydCAiL2lpZmUvQGZzL0Q6L2RvY3VtZW50cy9HaXRIdWIvdml0ZS8uY2xhdWRlL3dvcmt0cmVlcy9zbW9vdGgtd2VhdmluZy13cmVhdGgvcGFja2FnZXMvdml0ZS9kaXN0L2NsaWVudC9lbnYubWpzIgo7CmltcG9ydCB7IG1zZyBhcyBtc2dGcm9tRGVwIH0gZnJvbSAiL2lpZmUvbm9kZV9tb2R1bGVzLy52aXRlLWlpZmUvZGVwcy9Adml0ZWpzX3Rlc3QtZGVwLXRvLW9wdGltaXplLmpzP3Y9MDAwMDAwMDAiOwppbXBvcnQgX192aXRlX19janNJbXBvcnQyX192aXRlanNfdGVzdFdvcmtlckRlcENqcyBmcm9tICIvaWlmZS9ub2RlX21vZHVsZXMvLnZpdGUtaWlmZS9kZXBzL0B2aXRlanNfdGVzdC13b3JrZXItZGVwLWNqcy5qcz92PTAwMDAwMDAwIjsKaW1wb3J0IHsgbW9kZSwgbXNnIH0gZnJvbSAiL2lpZmUvbW9kdWxlcy93b3JrZXJJbXBvcnQudHMiOwppbXBvcnQgeyBidW5kbGVXaXRoUGx1Z2luIH0gZnJvbSAiL2lpZmUvbW9kdWxlcy90ZXN0LXBsdWdpbi5qcyI7CmltcG9ydCB2aXRlU3ZnIGZyb20gIi9paWZlL3ZpdGUuc3ZnP2ltcG9ydCI7CmNvbnN0IG1ldGFVcmwgPSBpbXBvcnQubWV0YS51cmw7CnNlbGYub25tZXNzYWdlID0gKGUpID0+IHsKCWlmIChlLmRhdGEgPT09ICJwaW5nIikgewoJCXNlbGYucG9zdE1lc3NhZ2UoewoJCQltc2csCgkJCW1vZGUsCgkJCWJ1bmRsZVdpdGhQbHVnaW4sCgkJCXZpdGVTdmcsCgkJCW1ldGFVcmwsCgkJCW5hbWUsCgkJCWRlcENqcwoJCX0pOwoJfQoJaWYgKGUuZGF0YSA9PT0gInBpbmctdW5pY29kZSIpIHsKCQlzZWxmLnBvc3RNZXNzYWdlKHsKCQkJbXNnOiAi4oCicG9uZ+KAoiIsCgkJCW1vZGUsCgkJCWJ1bmRsZVdpdGhQbHVnaW4sCgkJCXZpdGVTdmcsCgkJCW1ldGFVcmwsCgkJCW5hbWUsCgkJCWRlcENqcwoJCX0pOwoJfQp9OwpzZWxmLnBvc3RNZXNzYWdlKHsKCW1zZywKCW1vZGUsCglidW5kbGVXaXRoUGx1Z2luLAoJbXNnRnJvbURlcCwKCXZpdGVTdmcsCgltZXRhVXJsLAoJbmFtZSwKCWRlcENqcwp9KTsKLy8gZm9yIHNvdXJjZW1hcApjb25zb2xlLmxvZygibXktd29ya2VyLmpzIik7CjEzOTYAeyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6Ijs7QUFBQSxTQUFTLE9BQU8sa0JBQWtCO0FBQ2xDLE9BQU8sWUFBWTtBQUNuQixTQUFTLE1BQU0sV0FBVztBQUMxQixTQUFTLHdCQUF3QjtBQUNqQyxPQUFPLGFBQWE7QUFDcEIsTUFBTSxVQUFVLE9BQU8sS0FBSztBQUU1QixLQUFLLGFBQWEsTUFBTTtBQUN0QixLQUFJLEVBQUUsU0FBUyxRQUFRO0FBQ3JCLE9BQUssWUFBWTtHQUNmO0dBQ0E7R0FDQTtHQUNBO0dBQ0E7R0FDQTtHQUNBO0dBQ0QsQ0FBQzs7QUFFSixLQUFJLEVBQUUsU0FBUyxnQkFBZ0I7QUFDN0IsT0FBSyxZQUFZO0dBQ2YsS0FBSztHQUNMO0dBQ0E7R0FDQTtHQUNBO0dBQ0E7R0FDQTtHQUNELENBQUM7OztBQUdOLEtBQUssWUFBWTtDQUNmO0NBQ0E7Q0FDQTtDQUNBO0NBQ0E7Q0FDQTtDQUNBO0NBQ0E7Q0FDRCxDQUFDOztBQUdGLFFBQVEsSUFBSSxlQUFlIiwiaWdub3JlTGlzdCI6W10sInNvdXJjZXMiOlsibXktd29ya2VyLnRzP3dvcmtlcl9maWxlJnR5cGU9bW9kdWxlIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IG1zZyBhcyBtc2dGcm9tRGVwIH0gZnJvbSAnQHZpdGVqcy90ZXN0LWRlcC10by1vcHRpbWl6ZSdcbmltcG9ydCBkZXBDanMgZnJvbSAnQHZpdGVqcy90ZXN0LXdvcmtlci1kZXAtY2pzJ1xuaW1wb3J0IHsgbW9kZSwgbXNnIH0gZnJvbSAnLi9tb2R1bGVzL3dvcmtlckltcG9ydC5qcydcbmltcG9ydCB7IGJ1bmRsZVdpdGhQbHVnaW4gfSBmcm9tICcuL21vZHVsZXMvdGVzdC1wbHVnaW4nXG5pbXBvcnQgdml0ZVN2ZyBmcm9tICcuL3ZpdGUuc3ZnJ1xuY29uc3QgbWV0YVVybCA9IGltcG9ydC5tZXRhLnVybFxuXG5zZWxmLm9ubWVzc2FnZSA9IChlKSA9PiB7XG4gIGlmIChlLmRhdGEgPT09ICdwaW5nJykge1xuICAgIHNlbGYucG9zdE1lc3NhZ2Uoe1xuICAgICAgbXNnLFxuICAgICAgbW9kZSxcbiAgICAgIGJ1bmRsZVdpdGhQbHVnaW4sXG4gICAgICB2aXRlU3ZnLFxuICAgICAgbWV0YVVybCxcbiAgICAgIG5hbWUsXG4gICAgICBkZXBDanMsXG4gICAgfSlcbiAgfVxuICBpZiAoZS5kYXRhID09PSAncGluZy11bmljb2RlJykge1xuICAgIHNlbGYucG9zdE1lc3NhZ2Uoe1xuICAgICAgbXNnOiAn4oCicG9uZ+KAoicsXG4gICAgICBtb2RlLFxuICAgICAgYnVuZGxlV2l0aFBsdWdpbixcbiAgICAgIHZpdGVTdmcsXG4gICAgICBtZXRhVXJsLFxuICAgICAgbmFtZSxcbiAgICAgIGRlcENqcyxcbiAgICB9KVxuICB9XG59XG5zZWxmLnBvc3RNZXNzYWdlKHtcbiAgbXNnLFxuICBtb2RlLFxuICBidW5kbGVXaXRoUGx1Z2luLFxuICBtc2dGcm9tRGVwLFxuICB2aXRlU3ZnLFxuICBtZXRhVXJsLFxuICBuYW1lLFxuICBkZXBDanMsXG59KVxuXG4vLyBmb3Igc291cmNlbWFwXG5jb25zb2xlLmxvZygnbXktd29ya2VyLmpzJylcbiJdfQ==" } `) }) From 4ddf29c918798bab3e2c63de09fe63f7a4915c2d Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Mon, 6 Apr 2026 15:07:01 +0900 Subject: [PATCH 3/4] fix: hashbang --- packages/vite/src/node/plugins/importAnalysis.ts | 6 +++++- packages/vite/src/node/ssr/ssrTransform.ts | 6 ++---- packages/vite/src/node/utils.ts | 7 +++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index b463a0d7c63019..c97851b0d69106 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -33,6 +33,7 @@ import { createDebugger, fsPathFromUrl, generateCodeFrame, + getFileStartIndex, getHash, injectQuery, isBuiltin, @@ -971,7 +972,10 @@ export function interopNamedImports( { contentOnly: true }, ) if (rewritten.hoistedAssignments) { - str.appendLeft(0, rewritten.hoistedAssignments + ';') + str.appendLeft( + getFileStartIndex(source), + rewritten.hoistedAssignments + ';', + ) } } else { // #1439 export * from '...' diff --git a/packages/vite/src/node/ssr/ssrTransform.ts b/packages/vite/src/node/ssr/ssrTransform.ts index 0b889de0d43af9..85ff13736796c1 100644 --- a/packages/vite/src/node/ssr/ssrTransform.ts +++ b/packages/vite/src/node/ssr/ssrTransform.ts @@ -10,6 +10,7 @@ import type { TransformResult } from '../server/transformRequest' import { combineSourcemaps, generateCodeFrame, + getFileStartIndex, isDefined, numberToPos, } from '../utils' @@ -29,8 +30,6 @@ export const ssrExportAllKey = `__vite_ssr_exportAll__` export const ssrExportNameKey = `__vite_ssr_exportName__` export const ssrImportMetaKey = `__vite_ssr_import_meta__` -const hashbangRE = /^#!.*\n/ - export async function ssrTransform( code: string, inMap: SourceMap | { mappings: '' } | null, @@ -92,8 +91,7 @@ async function ssrTransformScript( const idToImportMap = new Map() const declaredConst = new Set() - // hoist at the start of the file, after the hashbang - const fileStartIndex = hashbangRE.exec(code)?.[0].length ?? 0 + const fileStartIndex = getFileStartIndex(code) let hoistIndex = fileStartIndex function defineImport( diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index f8c7154a879b39..9d031ead05e8c5 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -1817,3 +1817,10 @@ export function formatAndTruncateFileList(files: string[]): { } return { formatted: log, truncated } } + +const hashbangRE = /^#!.*\n/ + +// find the start of the file, after the hashbang +export function getFileStartIndex(code: string): number { + return hashbangRE.exec(code)?.[0].length ?? 0 +} From f0f2f5f4350add945bfc9425c9d6bd74ac113caf Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Mon, 6 Apr 2026 15:15:37 +0900 Subject: [PATCH 4/4] fix: hashbang --- playground/worker/__tests__/iife/worker-iife.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playground/worker/__tests__/iife/worker-iife.spec.ts b/playground/worker/__tests__/iife/worker-iife.spec.ts index 0840621e935a6d..4aa5fa6188e8da 100644 --- a/playground/worker/__tests__/iife/worker-iife.spec.ts +++ b/playground/worker/__tests__/iife/worker-iife.spec.ts @@ -199,7 +199,7 @@ test.runIf(isServe)('sourcemap is correct after env is injected', async () => { ) await page.goto(viteTestUrl) const code = (await (await response).text()).replace( - /^import "\/iife\/@fs\/.+?\/client\/env\.mjs"/, + /\bimport "\/iife\/@fs\/.+?\/client\/env\.mjs"/, '', ) const map = extractSourcemap(code) @@ -213,7 +213,7 @@ test.runIf(isServe)('sourcemap is correct after env is injected', async () => { ], "version": 3, }, - visualization: "https://evanw.github.io/source-map-visualization/#MTEwNgBjb25zdCBkZXBDanMgPSBfX3ZpdGVfX2Nqc0ltcG9ydDJfX3ZpdGVqc190ZXN0V29ya2VyRGVwQ2pzO2ltcG9ydCAiL2lpZmUvQGZzL0Q6L2RvY3VtZW50cy9HaXRIdWIvdml0ZS8uY2xhdWRlL3dvcmt0cmVlcy9zbW9vdGgtd2VhdmluZy13cmVhdGgvcGFja2FnZXMvdml0ZS9kaXN0L2NsaWVudC9lbnYubWpzIgo7CmltcG9ydCB7IG1zZyBhcyBtc2dGcm9tRGVwIH0gZnJvbSAiL2lpZmUvbm9kZV9tb2R1bGVzLy52aXRlLWlpZmUvZGVwcy9Adml0ZWpzX3Rlc3QtZGVwLXRvLW9wdGltaXplLmpzP3Y9MDAwMDAwMDAiOwppbXBvcnQgX192aXRlX19janNJbXBvcnQyX192aXRlanNfdGVzdFdvcmtlckRlcENqcyBmcm9tICIvaWlmZS9ub2RlX21vZHVsZXMvLnZpdGUtaWlmZS9kZXBzL0B2aXRlanNfdGVzdC13b3JrZXItZGVwLWNqcy5qcz92PTAwMDAwMDAwIjsKaW1wb3J0IHsgbW9kZSwgbXNnIH0gZnJvbSAiL2lpZmUvbW9kdWxlcy93b3JrZXJJbXBvcnQudHMiOwppbXBvcnQgeyBidW5kbGVXaXRoUGx1Z2luIH0gZnJvbSAiL2lpZmUvbW9kdWxlcy90ZXN0LXBsdWdpbi5qcyI7CmltcG9ydCB2aXRlU3ZnIGZyb20gIi9paWZlL3ZpdGUuc3ZnP2ltcG9ydCI7CmNvbnN0IG1ldGFVcmwgPSBpbXBvcnQubWV0YS51cmw7CnNlbGYub25tZXNzYWdlID0gKGUpID0+IHsKCWlmIChlLmRhdGEgPT09ICJwaW5nIikgewoJCXNlbGYucG9zdE1lc3NhZ2UoewoJCQltc2csCgkJCW1vZGUsCgkJCWJ1bmRsZVdpdGhQbHVnaW4sCgkJCXZpdGVTdmcsCgkJCW1ldGFVcmwsCgkJCW5hbWUsCgkJCWRlcENqcwoJCX0pOwoJfQoJaWYgKGUuZGF0YSA9PT0gInBpbmctdW5pY29kZSIpIHsKCQlzZWxmLnBvc3RNZXNzYWdlKHsKCQkJbXNnOiAi4oCicG9uZ+KAoiIsCgkJCW1vZGUsCgkJCWJ1bmRsZVdpdGhQbHVnaW4sCgkJCXZpdGVTdmcsCgkJCW1ldGFVcmwsCgkJCW5hbWUsCgkJCWRlcENqcwoJCX0pOwoJfQp9OwpzZWxmLnBvc3RNZXNzYWdlKHsKCW1zZywKCW1vZGUsCglidW5kbGVXaXRoUGx1Z2luLAoJbXNnRnJvbURlcCwKCXZpdGVTdmcsCgltZXRhVXJsLAoJbmFtZSwKCWRlcENqcwp9KTsKLy8gZm9yIHNvdXJjZW1hcApjb25zb2xlLmxvZygibXktd29ya2VyLmpzIik7CjEzOTYAeyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6Ijs7QUFBQSxTQUFTLE9BQU8sa0JBQWtCO0FBQ2xDLE9BQU8sWUFBWTtBQUNuQixTQUFTLE1BQU0sV0FBVztBQUMxQixTQUFTLHdCQUF3QjtBQUNqQyxPQUFPLGFBQWE7QUFDcEIsTUFBTSxVQUFVLE9BQU8sS0FBSztBQUU1QixLQUFLLGFBQWEsTUFBTTtBQUN0QixLQUFJLEVBQUUsU0FBUyxRQUFRO0FBQ3JCLE9BQUssWUFBWTtHQUNmO0dBQ0E7R0FDQTtHQUNBO0dBQ0E7R0FDQTtHQUNBO0dBQ0QsQ0FBQzs7QUFFSixLQUFJLEVBQUUsU0FBUyxnQkFBZ0I7QUFDN0IsT0FBSyxZQUFZO0dBQ2YsS0FBSztHQUNMO0dBQ0E7R0FDQTtHQUNBO0dBQ0E7R0FDQTtHQUNELENBQUM7OztBQUdOLEtBQUssWUFBWTtDQUNmO0NBQ0E7Q0FDQTtDQUNBO0NBQ0E7Q0FDQTtDQUNBO0NBQ0E7Q0FDRCxDQUFDOztBQUdGLFFBQVEsSUFBSSxlQUFlIiwiaWdub3JlTGlzdCI6W10sInNvdXJjZXMiOlsibXktd29ya2VyLnRzP3dvcmtlcl9maWxlJnR5cGU9bW9kdWxlIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IG1zZyBhcyBtc2dGcm9tRGVwIH0gZnJvbSAnQHZpdGVqcy90ZXN0LWRlcC10by1vcHRpbWl6ZSdcbmltcG9ydCBkZXBDanMgZnJvbSAnQHZpdGVqcy90ZXN0LXdvcmtlci1kZXAtY2pzJ1xuaW1wb3J0IHsgbW9kZSwgbXNnIH0gZnJvbSAnLi9tb2R1bGVzL3dvcmtlckltcG9ydC5qcydcbmltcG9ydCB7IGJ1bmRsZVdpdGhQbHVnaW4gfSBmcm9tICcuL21vZHVsZXMvdGVzdC1wbHVnaW4nXG5pbXBvcnQgdml0ZVN2ZyBmcm9tICcuL3ZpdGUuc3ZnJ1xuY29uc3QgbWV0YVVybCA9IGltcG9ydC5tZXRhLnVybFxuXG5zZWxmLm9ubWVzc2FnZSA9IChlKSA9PiB7XG4gIGlmIChlLmRhdGEgPT09ICdwaW5nJykge1xuICAgIHNlbGYucG9zdE1lc3NhZ2Uoe1xuICAgICAgbXNnLFxuICAgICAgbW9kZSxcbiAgICAgIGJ1bmRsZVdpdGhQbHVnaW4sXG4gICAgICB2aXRlU3ZnLFxuICAgICAgbWV0YVVybCxcbiAgICAgIG5hbWUsXG4gICAgICBkZXBDanMsXG4gICAgfSlcbiAgfVxuICBpZiAoZS5kYXRhID09PSAncGluZy11bmljb2RlJykge1xuICAgIHNlbGYucG9zdE1lc3NhZ2Uoe1xuICAgICAgbXNnOiAn4oCicG9uZ+KAoicsXG4gICAgICBtb2RlLFxuICAgICAgYnVuZGxlV2l0aFBsdWdpbixcbiAgICAgIHZpdGVTdmcsXG4gICAgICBtZXRhVXJsLFxuICAgICAgbmFtZSxcbiAgICAgIGRlcENqcyxcbiAgICB9KVxuICB9XG59XG5zZWxmLnBvc3RNZXNzYWdlKHtcbiAgbXNnLFxuICBtb2RlLFxuICBidW5kbGVXaXRoUGx1Z2luLFxuICBtc2dGcm9tRGVwLFxuICB2aXRlU3ZnLFxuICBtZXRhVXJsLFxuICBuYW1lLFxuICBkZXBDanMsXG59KVxuXG4vLyBmb3Igc291cmNlbWFwXG5jb25zb2xlLmxvZygnbXktd29ya2VyLmpzJylcbiJdfQ==" + visualization: "https://evanw.github.io/source-map-visualization/#OTg5AGNvbnN0IGRlcENqcyA9IF9fdml0ZV9fY2pzSW1wb3J0Ml9fdml0ZWpzX3Rlc3RXb3JrZXJEZXBDanM7CjsKaW1wb3J0IHsgbXNnIGFzIG1zZ0Zyb21EZXAgfSBmcm9tICIvaWlmZS9ub2RlX21vZHVsZXMvLnZpdGUtaWlmZS9kZXBzL0B2aXRlanNfdGVzdC1kZXAtdG8tb3B0aW1pemUuanM/dj0wMDAwMDAwMCI7CmltcG9ydCBfX3ZpdGVfX2Nqc0ltcG9ydDJfX3ZpdGVqc190ZXN0V29ya2VyRGVwQ2pzIGZyb20gIi9paWZlL25vZGVfbW9kdWxlcy8udml0ZS1paWZlL2RlcHMvQHZpdGVqc190ZXN0LXdvcmtlci1kZXAtY2pzLmpzP3Y9MDAwMDAwMDAiOwppbXBvcnQgeyBtb2RlLCBtc2cgfSBmcm9tICIvaWlmZS9tb2R1bGVzL3dvcmtlckltcG9ydC50cyI7CmltcG9ydCB7IGJ1bmRsZVdpdGhQbHVnaW4gfSBmcm9tICIvaWlmZS9tb2R1bGVzL3Rlc3QtcGx1Z2luLmpzIjsKaW1wb3J0IHZpdGVTdmcgZnJvbSAiL2lpZmUvdml0ZS5zdmc/aW1wb3J0IjsKY29uc3QgbWV0YVVybCA9IGltcG9ydC5tZXRhLnVybDsKc2VsZi5vbm1lc3NhZ2UgPSAoZSkgPT4gewoJaWYgKGUuZGF0YSA9PT0gInBpbmciKSB7CgkJc2VsZi5wb3N0TWVzc2FnZSh7CgkJCW1zZywKCQkJbW9kZSwKCQkJYnVuZGxlV2l0aFBsdWdpbiwKCQkJdml0ZVN2ZywKCQkJbWV0YVVybCwKCQkJbmFtZSwKCQkJZGVwQ2pzCgkJfSk7Cgl9CglpZiAoZS5kYXRhID09PSAicGluZy11bmljb2RlIikgewoJCXNlbGYucG9zdE1lc3NhZ2UoewoJCQltc2c6ICLigKJwb25n4oCiIiwKCQkJbW9kZSwKCQkJYnVuZGxlV2l0aFBsdWdpbiwKCQkJdml0ZVN2ZywKCQkJbWV0YVVybCwKCQkJbmFtZSwKCQkJZGVwQ2pzCgkJfSk7Cgl9Cn07CnNlbGYucG9zdE1lc3NhZ2UoewoJbXNnLAoJbW9kZSwKCWJ1bmRsZVdpdGhQbHVnaW4sCgltc2dGcm9tRGVwLAoJdml0ZVN2ZywKCW1ldGFVcmwsCgluYW1lLAoJZGVwQ2pzCn0pOwovLyBmb3Igc291cmNlbWFwCmNvbnNvbGUubG9nKCJteS13b3JrZXIuanMiKTsKMTM5NgB7InZlcnNpb24iOjMsIm1hcHBpbmdzIjoiOztBQUFBLFNBQVMsT0FBTyxrQkFBa0I7QUFDbEMsT0FBTyxZQUFZO0FBQ25CLFNBQVMsTUFBTSxXQUFXO0FBQzFCLFNBQVMsd0JBQXdCO0FBQ2pDLE9BQU8sYUFBYTtBQUNwQixNQUFNLFVBQVUsT0FBTyxLQUFLO0FBRTVCLEtBQUssYUFBYSxNQUFNO0FBQ3RCLEtBQUksRUFBRSxTQUFTLFFBQVE7QUFDckIsT0FBSyxZQUFZO0dBQ2Y7R0FDQTtHQUNBO0dBQ0E7R0FDQTtHQUNBO0dBQ0E7R0FDRCxDQUFDOztBQUVKLEtBQUksRUFBRSxTQUFTLGdCQUFnQjtBQUM3QixPQUFLLFlBQVk7R0FDZixLQUFLO0dBQ0w7R0FDQTtHQUNBO0dBQ0E7R0FDQTtHQUNBO0dBQ0QsQ0FBQzs7O0FBR04sS0FBSyxZQUFZO0NBQ2Y7Q0FDQTtDQUNBO0NBQ0E7Q0FDQTtDQUNBO0NBQ0E7Q0FDQTtDQUNELENBQUM7O0FBR0YsUUFBUSxJQUFJLGVBQWUiLCJpZ25vcmVMaXN0IjpbXSwic291cmNlcyI6WyJteS13b3JrZXIudHM/d29ya2VyX2ZpbGUmdHlwZT1tb2R1bGUiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbXNnIGFzIG1zZ0Zyb21EZXAgfSBmcm9tICdAdml0ZWpzL3Rlc3QtZGVwLXRvLW9wdGltaXplJ1xuaW1wb3J0IGRlcENqcyBmcm9tICdAdml0ZWpzL3Rlc3Qtd29ya2VyLWRlcC1janMnXG5pbXBvcnQgeyBtb2RlLCBtc2cgfSBmcm9tICcuL21vZHVsZXMvd29ya2VySW1wb3J0LmpzJ1xuaW1wb3J0IHsgYnVuZGxlV2l0aFBsdWdpbiB9IGZyb20gJy4vbW9kdWxlcy90ZXN0LXBsdWdpbidcbmltcG9ydCB2aXRlU3ZnIGZyb20gJy4vdml0ZS5zdmcnXG5jb25zdCBtZXRhVXJsID0gaW1wb3J0Lm1ldGEudXJsXG5cbnNlbGYub25tZXNzYWdlID0gKGUpID0+IHtcbiAgaWYgKGUuZGF0YSA9PT0gJ3BpbmcnKSB7XG4gICAgc2VsZi5wb3N0TWVzc2FnZSh7XG4gICAgICBtc2csXG4gICAgICBtb2RlLFxuICAgICAgYnVuZGxlV2l0aFBsdWdpbixcbiAgICAgIHZpdGVTdmcsXG4gICAgICBtZXRhVXJsLFxuICAgICAgbmFtZSxcbiAgICAgIGRlcENqcyxcbiAgICB9KVxuICB9XG4gIGlmIChlLmRhdGEgPT09ICdwaW5nLXVuaWNvZGUnKSB7XG4gICAgc2VsZi5wb3N0TWVzc2FnZSh7XG4gICAgICBtc2c6ICfigKJwb25n4oCiJyxcbiAgICAgIG1vZGUsXG4gICAgICBidW5kbGVXaXRoUGx1Z2luLFxuICAgICAgdml0ZVN2ZyxcbiAgICAgIG1ldGFVcmwsXG4gICAgICBuYW1lLFxuICAgICAgZGVwQ2pzLFxuICAgIH0pXG4gIH1cbn1cbnNlbGYucG9zdE1lc3NhZ2Uoe1xuICBtc2csXG4gIG1vZGUsXG4gIGJ1bmRsZVdpdGhQbHVnaW4sXG4gIG1zZ0Zyb21EZXAsXG4gIHZpdGVTdmcsXG4gIG1ldGFVcmwsXG4gIG5hbWUsXG4gIGRlcENqcyxcbn0pXG5cbi8vIGZvciBzb3VyY2VtYXBcbmNvbnNvbGUubG9nKCdteS13b3JrZXIuanMnKVxuIl19" } `) })