Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/plugin-legacy/src/__tests__/snippets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, test } from 'vitest'
import type { ecmaVersion } from 'acorn'
import { parse } from 'acorn'
import {
createModernChunkLegacyGuard,
detectModernBrowserCode,
detectModernBrowserDetector,
dynamicFallbackInlineCode,
Expand Down Expand Up @@ -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()
})
})
9 changes: 6 additions & 3 deletions packages/plugin-legacy/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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
}
Expand Down
22 changes: 17 additions & 5 deletions packages/plugin-legacy/src/snippets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}};`