From 37c344f218ca01750472b336d8108c39b887ef39 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Tue, 23 Apr 2024 11:39:03 +0800 Subject: [PATCH] fix(legacy): improve deterministic build of the polyfill bundle by sorting the polyfills discovered by babel --- packages/plugin-legacy/src/index.ts | 58 +++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/packages/plugin-legacy/src/index.ts b/packages/plugin-legacy/src/index.ts index d1489fda5bb91d..abb6a0ef76b5b4 100644 --- a/packages/plugin-legacy/src/index.ts +++ b/packages/plugin-legacy/src/index.ts @@ -158,6 +158,14 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { const facadeToModernPolyfillMap = new Map() const modernPolyfills = new Set() const legacyPolyfills = new Set() + const polyfillsDiscovered = { + modern: new Map(), + legacy: new Map(), + } + const orderedChunks = { + modern: [] as string[], + legacy: [] as string[], + } if (Array.isArray(options.modernPolyfills) && genModern) { options.modernPolyfills.forEach((i) => { @@ -253,6 +261,28 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { }, } + function sortPolyfills( + polyfillInfo: Map, + chunkOrder: string[], + ): Set { + const resultSet = new Set() + chunkOrder.forEach((chunkName) => { + const polyfills = polyfillInfo.get(chunkName) + if (polyfills) { + polyfills.forEach((p) => { + resultSet.add(p) + }) + } + polyfillInfo.delete(chunkName) + }) + if (polyfillInfo.size) { + throw new Error( + 'Unexpected chunk: ' + Array.from(polyfillInfo.keys()).join(', '), + ) + } + return resultSet + } + const legacyGenerateBundlePlugin: Plugin = { name: 'vite:legacy-generate-polyfill-chunk', apply: 'build', @@ -263,6 +293,11 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { } if (!isLegacyBundle(bundle, opts)) { + sortPolyfills(polyfillsDiscovered.modern, orderedChunks.modern).forEach( + (polyfill) => { + modernPolyfills.add(polyfill) + }, + ) if (!modernPolyfills.size) { return } @@ -291,6 +326,12 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { return } + sortPolyfills(polyfillsDiscovered.legacy, orderedChunks.legacy).forEach( + (polyfill) => { + legacyPolyfills.add(polyfill) + }, + ) + // legacy bundle if (options.polyfills !== false) { // check if the target needs Promise polyfill because SystemJS relies on it @@ -410,7 +451,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { } }, - async renderChunk(raw, chunk, opts) { + async renderChunk(raw, chunk, opts, { chunks }) { if (config.build.ssr) { return null } @@ -421,8 +462,13 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { !Array.isArray(options.modernPolyfills) && genModern ) { + if (!orderedChunks.modern.length) { + orderedChunks.modern.push(...Object.keys(chunks)) + } // analyze and record modern polyfills - await detectPolyfills(raw, modernTargets, modernPolyfills) + const polyfills = new Set() + await detectPolyfills(raw, modernTargets, polyfills) + polyfillsDiscovered.modern.set(chunk.fileName, [...polyfills]) } const ms = new MagicString(raw) @@ -459,6 +505,10 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { return null } + if (!orderedChunks.legacy.length) { + orderedChunks.legacy.push(...Object.keys(chunks)) + } + // @ts-expect-error avoid esbuild transform on legacy chunks since it produces // legacy-unsafe code - e.g. rewriting object properties into shorthands opts.__vite_skip_esbuild__ = true @@ -481,6 +531,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { // transform the legacy chunk with @babel/preset-env const sourceMaps = !!config.build.sourcemap const babel = await loadBabel() + const polyfills = new Set() const result = babel.transform(raw, { babelrc: false, configFile: false, @@ -493,7 +544,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { [ () => ({ plugins: [ - recordAndRemovePolyfillBabelPlugin(legacyPolyfills), + recordAndRemovePolyfillBabelPlugin(polyfills), replaceLegacyEnvBabelPlugin(), wrapIIFEBabelPlugin(), ], @@ -505,6 +556,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] { ], ], }) + polyfillsDiscovered.legacy.set(chunk.fileName, [...polyfills]) if (result) return { code: result.code!, map: result.map } return null