From a00b4703a0aa50f367b9d72c970662db787366dd Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Thu, 26 Mar 2026 11:27:08 +0900 Subject: [PATCH 1/2] fix(legacy): workaround safari 15 error caching bug --- packages/plugin-legacy/src/index.ts | 9 ++++++--- packages/plugin-legacy/src/snippets.ts | 22 +++++++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/plugin-legacy/src/index.ts b/packages/plugin-legacy/src/index.ts index d0829f23f0fa49..a57a2336c03e94 100644 --- a/packages/plugin-legacy/src/index.ts +++ b/packages/plugin-legacy/src/index.ts @@ -19,11 +19,11 @@ import colors from 'picocolors' import browserslist from 'browserslist' import type { Options } from './types' import { + createModernChunkLegacyGuard, detectModernBrowserCode, dynamicFallbackInlineCode, legacyEntryId, legacyPolyfillId, - modernChunkLegacyGuard, safari10NoModuleFix, systemJSInlineCode, } from './snippets' @@ -518,7 +518,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { if (genLegacy && chunk.isEntry) { // append this code to avoid modern chunks running on legacy targeted browsers - ms.prepend(modernChunkLegacyGuard) + ms.prepend(createModernChunkLegacyGuard(chunk.fileName)) } if (raw.includes(legacyEnvVarMarker)) { @@ -961,7 +961,10 @@ function prependModenChunkLegacyGuardPlugin(): Plugin { configResolved(config) { sourceMapEnabled = !!config.build.sourcemap }, - renderChunk(code) { + renderChunk(code, chunk) { + const modernChunkLegacyGuard = createModernChunkLegacyGuard( + chunk.fileName, + ) if (!sourceMapEnabled) { return modernChunkLegacyGuard + code } diff --git a/packages/plugin-legacy/src/snippets.ts b/packages/plugin-legacy/src/snippets.ts index 7980bba0644dce..f464f6c18bd02d 100644 --- a/packages/plugin-legacy/src/snippets.ts +++ b/packages/plugin-legacy/src/snippets.ts @@ -7,11 +7,23 @@ export const legacyEntryId: string = 'vite-legacy-entry' export const systemJSInlineCode: string = `System.import(document.getElementById('${legacyEntryId}').getAttribute('data-src'))` const detectModernBrowserVarName = '__vite_is_modern_browser' -// inline module to execute the code before other imports -const detectImportMetaResolveSupportModule: string = - 'data:text/javascript,if(!import.meta.resolve)throw Error("import.meta.resolve not supported")' + +/** + * Create an inline module to detect if the browser supports import.meta.resolve + * + * This is an inline module to execute the code before other imports. + * Throwing an error can prevent the browser from executing the rest of the code. + * + * Note that due to a bug in Safari 15.x and below, each inline module has to be unique, + * otherwise Safari will only throw the error for the first time that module is imported. + * https://github.com/vitejs/vite/issues/22008 + */ +const createDetectImportMetaResolveSupportModule = (chunkId: string | null) => + `data:text/javascript,${chunkId != null ? `${JSON.stringify(chunkId)};` : ''}if(!import.meta.resolve)throw Error("import.meta.resolve not supported")` + export const detectModernBrowserDetector: string = `import.meta.url;import("_").catch(()=>1);(async function*(){})().next()` -export const detectModernBrowserCode: string = `import'${detectImportMetaResolveSupportModule}';${detectModernBrowserDetector};window.${detectModernBrowserVarName}=true` +export const detectModernBrowserCode: string = `import'${createDetectImportMetaResolveSupportModule(null)}';${detectModernBrowserDetector};window.${detectModernBrowserVarName}=true` export const dynamicFallbackInlineCode: string = `!function(){if(window.${detectModernBrowserVarName})return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("${legacyPolyfillId}"),n=document.createElement("script");n.src=e.src,n.onload=function(){${systemJSInlineCode}},document.body.appendChild(n)}();` -export const modernChunkLegacyGuard: string = `import'${detectImportMetaResolveSupportModule}';export function __vite_legacy_guard(){${detectModernBrowserDetector}};` +export const createModernChunkLegacyGuard = (chunkId: string): string => + `import'${createDetectImportMetaResolveSupportModule(chunkId)}';export function __vite_legacy_guard(){${detectModernBrowserDetector}};` From 3a9437e05f54ecbb8d6828277065ac1d49cefbb2 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Thu, 26 Mar 2026 11:44:09 +0900 Subject: [PATCH 2/2] test: add test --- .../src/__tests__/snippets.spec.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/plugin-legacy/src/__tests__/snippets.spec.ts b/packages/plugin-legacy/src/__tests__/snippets.spec.ts index 0b2812a991c5e1..c5e8f5806a1e8e 100644 --- a/packages/plugin-legacy/src/__tests__/snippets.spec.ts +++ b/packages/plugin-legacy/src/__tests__/snippets.spec.ts @@ -2,6 +2,7 @@ import { describe, expect, test } from 'vitest' import type { ecmaVersion } from 'acorn' import { parse } from 'acorn' import { + createModernChunkLegacyGuard, detectModernBrowserCode, detectModernBrowserDetector, dynamicFallbackInlineCode, @@ -60,3 +61,22 @@ describe('snippets are valid', () => { }) } }) + +describe('createModernChunkLegacyGuard', () => { + // https://github.com/vitejs/vite/issues/22008 + test('generates unique data URLs for different chunk filenames', () => { + const guard1 = createModernChunkLegacyGuard('assets/index-abc123.js') + const guard2 = createModernChunkLegacyGuard('assets/chunk-def456.js') + expect(guard1).not.toBe(guard2) + }) + + test('is valid JS', () => { + const guard = createModernChunkLegacyGuard('assets/index-abc123.js') + expect(() => { + parse(guard, { + ecmaVersion: 'latest', + sourceType: 'module', + }) + }).not.toThrow() + }) +})