diff --git a/packages/vite/src/node/plugins/esbuild.ts b/packages/vite/src/node/plugins/esbuild.ts index 591e2883453fe3..d2bf848437a915 100644 --- a/packages/vite/src/node/plugins/esbuild.ts +++ b/packages/vite/src/node/plugins/esbuild.ts @@ -28,9 +28,10 @@ import { searchForWorkspaceRoot } from '../server/searchRoot' const debug = createDebugger('vite:esbuild') -// IIFE content looks like `var MyLib = function() {`. Spaces are removed when minified -const IIFE_BEGIN_RE = - /(const|var)\s+\S+\s*=\s*function\(\)\s*\{.*"use strict";/s +const INJECT_HELPERS_IIFE_RE = + /^(.*?)((?:const|var)\s+\S+\s*=\s*function\s*\([^)]*\)\s*\{\s*"use strict";)/s +const INJECT_HELPERS_UMD_RE = + /^(.*?)(\(function\([^)]*\)\s*\{.+?amd.+?function\([^)]*\)\s*\{\s*"use strict";)/s const validExtensionRE = /\.\w+$/ const jsxExtensionsRE = /\.(?:j|t)sx\b/ @@ -332,30 +333,22 @@ export const buildEsbuildPlugin = (config: ResolvedConfig): Plugin => { if (config.build.lib) { // #7188, esbuild adds helpers out of the UMD and IIFE wrappers, and the // names are minified potentially causing collision with other globals. - // We inject the helpers inside the wrappers. - // e.g. turn: - // (function(){ /*actual content/* })() - // into: - // (function(){ /*actual content/* })() - // Not using regex because it's too hard to rule out performance issues like #8738 #8099 #10900 #14065 - // Instead, using plain string index manipulation (indexOf, slice) which is simple and performant + // We use a regex to inject the helpers inside the wrappers. // We don't need to create a MagicString here because both the helpers and // the headers don't modify the sourcemap - const esbuildCode = res.code - const contentIndex = - opts.format === 'iife' - ? esbuildCode.match(IIFE_BEGIN_RE)?.index || 0 - : opts.format === 'umd' - ? esbuildCode.indexOf(`(function(`) // same for minified or not - : 0 - if (contentIndex > 0) { - const esbuildHelpers = esbuildCode.slice(0, contentIndex) - res.code = esbuildCode - .slice(contentIndex) - .replace(`"use strict";`, `"use strict";` + esbuildHelpers) + const injectHelpers = + opts.format === 'umd' + ? INJECT_HELPERS_UMD_RE + : opts.format === 'iife' + ? INJECT_HELPERS_IIFE_RE + : undefined + if (injectHelpers) { + res.code = res.code.replace( + injectHelpers, + (_, helpers, header) => header + helpers, + ) } } - return res }, } diff --git a/playground/lib/__tests__/lib.spec.ts b/playground/lib/__tests__/lib.spec.ts index 8232a2fd100649..b203535e0154da 100644 --- a/playground/lib/__tests__/lib.spec.ts +++ b/playground/lib/__tests__/lib.spec.ts @@ -33,9 +33,7 @@ describe.runIf(isBuild)('build', () => { 'dist/nominify/my-lib-custom-filename.iife.js', ) // esbuild helpers are injected inside of the IIFE wrapper - // esbuild has a bug that injects some statements before `"use strict"`: https://github.com/evanw/esbuild/issues/3322 - // remove the `.*?` part once it's fixed - expect(code).toMatch(/^var MyLib=function\(\)\{.*?"use strict";/) + expect(code).toMatch(/^var MyLib=function\(\)\{"use strict";/) expect(noMinifyCode).toMatch( /^var MyLib\s*=\s*function\(\)\s*\{.*?"use strict";/s, ) diff --git a/playground/lib/src/main.js b/playground/lib/src/main.js index 8be8ec37e635ee..59c8e897cb0789 100644 --- a/playground/lib/src/main.js +++ b/playground/lib/src/main.js @@ -10,6 +10,3 @@ export default function myLib(sel) { // make sure umd helper has been moved to the right position console.log(`amd function(){ "use strict"; }`) } - -// For triggering unhandled global esbuild helpers in previous regex-based implementation for injection -;(function () {})()?.foo diff --git a/playground/lib/vite.config.js b/playground/lib/vite.config.js index 84612ba1f65306..6b4395624dc27a 100644 --- a/playground/lib/vite.config.js +++ b/playground/lib/vite.config.js @@ -7,7 +7,6 @@ export default defineConfig({ supported: { // Force esbuild inject helpers to test regex 'object-rest-spread': false, - 'optional-chain': false, }, }, build: {