Skip to content

wp-build: Stop bundling Core packages, generate prerequisites asset instead#75987

Merged
youknowriad merged 4 commits intoWordPress:trunkfrom
dhasilva:update/wp-build-remove-bundling
Mar 10, 2026
Merged

wp-build: Stop bundling Core packages, generate prerequisites asset instead#75987
youknowriad merged 4 commits intoWordPress:trunkfrom
dhasilva:update/wp-build-remove-bundling

Conversation

@dhasilva
Copy link
Contributor

@dhasilva dhasilva commented Feb 27, 2026

What?

Follow-up to #75650

wp-build was bundling boot, route, theme, and private-apis from node_modules and registering them as WordPress scripts/modules. This caused the plugin to overwrite Core's or Gutenberg's versions at runtime.

This PR replaces the bundling approach with a static analysis step that generates a page-prerequisites.asset.php file listing the classic script handles WordPress needs to load.

Why?

As identified in this comment, the root cause of the private-apis version mismatch issue (see #75440) is that wp-build was bundling its own copies of Core packages instead of externalizing them. This is particularly dangerous for private-apis, where a Symbol/WeakMap mismatch causes silent failures and page crashes.

Plugins using wp-build with pages should rely on Core (WP 7.0+) or Gutenberg to provide these packages, rather than shipping their own copies.

How?

  • Removes the bundlePackage() calls for boot, route, theme, and private-apis in the page build flow.
  • Adds a new generatePagePrerequisitesAsset() function that reads @wordpress/boot's package.json dependencies and produces a build/page-prerequisites.asset.php file with the corresponding WordPress script handles.
  • Extracts the vendorExternals map to module scope in wordpress-externals-plugin.mjs so it can be shared with the prerequisites generator.
  • Updates the page PHP templates to reference the new page-prerequisites.asset.php path instead of the old modules/boot/index.min.asset.php.

Testing Instructions

Without polyfills:

  1. Clone https://github.com/dhasilva/minimal-wp-build-test locally
  2. pnpm install
  3. Delete the build folder if it is there
  4. Back on Gutenberg, build this branch
  5. Back on the test plugin, symlink wp-build to the test repo: rm -rf node_modules/@wordpress/build && ln -s <gutenberg path>/packages/wp-build node_modules/@wordpress/build
  6. Build the test plugin: pnpm run build
  7. Verify build/page-prerequisites.asset.php exists and contains the expected script handles
  8. Verify build/modules/boot/, build/scripts/private-apis/, build/scripts/theme/ are not generated
  9. With Gutenberg active, go to Tools > Minimal WP-Build Test and confirm the page loads without errors
  10. With Gutenbert inactive, go to Tools > Minimal WP-Build Test and confirm the page does not load

With a polyfill:

  1. Clone https://github.com/dhasilva/minimal-wp-build-test locally
  2. Checkout the test/wp-build-polyfill branch
  3. pnpm install
  4. Delete the build folder if it is there
  5. Back on Gutenberg, build this branch
  6. Back on the test plugin, symlink wp-build to the test repo: rm -rf node_modules/@wordpress/build && ln -s <gutenberg path>/packages/wp-build node_modules/@wordpress/build
  7. Build the test plugin: pnpm run build
  8. Verify build/page-prerequisites.asset.php exists and contains the expected script handles
  9. Verify build/modules/boot/, build/scripts/private-apis/, build/scripts/theme/ are not generated
  10. With Gutenberg active, go to Tools > Minimal WP-Build Test and confirm the page loads without errors
  11. With Gutenberg inactive, go to Tools > Minimal WP-Build Test and confirm the page loads without errors, except for the "Open editor canvas (draft post)" button.

Testing Instructions for Keyboard

N/A — no UI changes.

Screenshots or screencast

N/A — build tooling change only.

@simison simison requested a review from youknowriad February 27, 2026 07:34
* WordPress's script dependency system handles transitive dependencies
* automatically, so we only need to capture direct dependencies.
*/
async function generatePagePrerequisitesAsset() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, We don't need this at all, the "boot" package is going to be registered by Core and Gutenberg as a regular module it will be available already.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Boot will be available as a module, yes, but when on Core < 7.0 and Gutenberg disabled, the page template still needs to enqueue boot's classic script dependencies. Without this, pages using wp-build in these conditions will still fail to load.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the whole idea of this PR is to remove support for Core < 7.0, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is to remove the bundled modules while making it possible to polyfill them temporarily. Without this, the polyfill won't work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still a bit unclear to me, why can't the polyfill, provide these packages by building them from npm and using the generated asset file that the polyfill provides, why do we need to keep this code here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my mind, the polyfill would do that basically, It would build the "boot" package using through the regular pipeline which would also result in the asset file generated properly. What's the purpose of the polyfill otherwise?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my mind, the polyfill would do that basically, It would build the "boot" package using through the regular pipeline which would also result in the asset file generated properly.

I updated the code to remove the generatePagePrerequisitesAsset function. The issue is that for plugins using wp-build before 7.0, we need to run bundlePackage('boot', ...) and then discard everything except for the asset file here then. We can't completely remove this.

What's the purpose of the polyfill otherwise?

To bundle the modules. Those are two distinct issues, the problem here is enqueing the classic scripts that the modules need, bundled or not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is that for plugins using wp-build before 7.0, we need to run bundlePackage('boot', ...) and then discard everything except for the asset file here then. We can't completely remove this.

Building regular packages using wp-build already builds the output of the script modules and also generates the assets file. So what I'm suggesting personally is to build the "@wordpress/boot" package in the polyfill and generating the assets file there as well and just do nothing here. I don't really know how straightforward is this. Maybe it means doing export * from '@wordpress/build' or something like that in a custom boot package or maybe it means a custom build script or trying to reproduce the "gutenberg" folder structure in a temporary folder in the build script... But I don't think building half of the things here (assets) and the other half (the code) in the polyfill is a good approach, it results in quick inconsistency.

I don't believe these are distinct issues, when you build a module/script/package you need to extract its dependencies and that's what the asset file is about.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem, and the reason I kept trying to keep the asset file definition here, is that the asset file location is hardcoded on the template files, so they end up in the build directory, that can't be edited reliably, nor copied to in runtime.
This makes it necessary to run a post-build script to copy the asset file to the expected folder, which IMO is a hacky solution.

That said, I removed the entire asset enqueing and module bundling logic, as requested.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reason I kept trying to keep the asset file definition here, is that the asset file location is hardcoded on the template files, so they end up in the build directory, that can't be edited reliably, nor copied to in runtime.

This is a good point, if you think it helps we can potentially make the "boot package" or the "boot package assets" a config or something if it helps.

@dhasilva dhasilva marked this pull request as ready for review March 4, 2026 01:56
@github-actions
Copy link

github-actions bot commented Mar 4, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: dhasilva <thehenridev@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@dhasilva dhasilva force-pushed the update/wp-build-remove-bundling branch from 589d181 to 76ee64e Compare March 4, 2026 01:56
@simison simison added [Package] wp-build /packages/wp-build [Type] Bug An existing feature does not function as intended labels Mar 4, 2026
@dhasilva dhasilva force-pushed the update/wp-build-remove-bundling branch from 76ee64e to d16c311 Compare March 4, 2026 17:06
@dhasilva dhasilva force-pushed the update/wp-build-remove-bundling branch 2 times, most recently from 49c3e05 to b6cc9cc Compare March 6, 2026 19:22
dhasilva and others added 3 commits March 9, 2026 21:46
…nstead

wp-build previously bundled boot, route, theme, and private-apis from
node_modules and registered them as WordPress scripts/modules. This caused
the plugin to overwrite Core's or Gutenberg's versions at runtime, which is
particularly dangerous for private-apis (Symbol/WeakMap mismatch causes
silent failures).

Replace the bundling block with a new generatePagePrerequisitesAsset()
function that statically analyzes @wordpress/boot's package.json to produce
a build/page-prerequisites.asset.php file listing the classic script handles
WordPress needs to load. The 4 packages are now treated as external
dependencies provided by Core (WP 7.0+) or Gutenberg.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of statically analyzing boot's package.json to generate a
separate page-prerequisites.asset.php, use the asset file that esbuild
naturally produces when building boot as a module.

For Gutenberg, boot is already built in Phase 2. For external plugins,
build boot from node_modules solely for the asset file, then clean up
the unused JS output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dhasilva dhasilva force-pushed the update/wp-build-remove-bundling branch from b6cc9cc to 21e9e9f Compare March 10, 2026 00:51
@dhasilva dhasilva requested a review from youknowriad March 10, 2026 01:38
Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Let's add a breaking change changelog entry to ensure folks know that 7.0 is now a requirement for this.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@youknowriad youknowriad merged commit 5114ae3 into WordPress:trunk Mar 10, 2026
40 checks passed
@github-actions github-actions bot added this to the Gutenberg 22.8 milestone Mar 10, 2026
@dhasilva dhasilva deleted the update/wp-build-remove-bundling branch March 10, 2026 23:06
@dhasilva
Copy link
Contributor Author

For anyone affected by this change in wp-build, I have a sample polyfill here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] wp-build /packages/wp-build [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants