Skip to content
Merged
Changes from 2 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
36 changes: 28 additions & 8 deletions packages/wp-build/lib/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -554,8 +554,35 @@ async function bundlePackage( packageName, options = {} ) {
? `${ scriptGlobal }.${ camelCase( packageName ) }`
: undefined;

// esbuild's IIFE output exposes each export as a non-configurable
// getter (`Object.defineProperty(ns, k, { get: () => binding })`) to
// preserve ESM live-binding semantics across hoisting. Once the IIFE
// has finished the bindings are stable, but consumers still pay a
// getter call on every access — about 2× slower than a data property
// in V8, and across the editor mount that's hundreds of thousands of
// reads from every hook and selector.
//
// Bundle a synthetic CJS entrypoint that spreads the real entry's
// exports into a plain object. Esbuild evaluates the spread inside
// the IIFE, so what's assigned to `globalName` is a plain object with
// data properties from the start. For `wpScriptDefaultExport`
// packages, the synthetic also unwraps the namespace so `globalName`
// IS the default value (replacing the previous post-hoc unwrap).
//
// `bin/packages/build-vendors.mjs` uses the same `stdin` trick to
// build the react-dom global.
const entrySpec = JSON.stringify( entryPoint );
const stdinContents = packageJson.wpScriptDefaultExport
? `module.exports = require(${ entrySpec }).default;`
: `module.exports = { ...require(${ entrySpec }) };`;

const baseConfig = {
entryPoints: [ entryPoint ],
stdin: {
contents: stdinContents,
resolveDir: packageDir,
sourcefile: 'index.js',
loader: 'js',
},
bundle: true,
sourcemap: true,
format: 'iife',
Expand All @@ -564,13 +591,6 @@ async function bundlePackage( packageName, options = {} ) {
globalName,
};

// For packages with default exports, add a footer to properly expose the default
if ( packageJson.wpScriptDefaultExport && globalName ) {
baseConfig.footer = {
js: `if (typeof ${ globalName } === 'object' && ${ globalName }.default) { ${ globalName } = ${ globalName }.default; }`,
};
}

const baseBundlePlugins = [
momentTimezoneAliasPlugin(),
styleRuntimeAliasPlugin(),
Expand Down
Loading