Skip to content

Webpack config: replace the duplicated @wordpress/ui bundling block with an opt-in option - #52207

Merged
CGastrell merged 4 commits into
trunkfrom
update/webpack-config-default-request-map
Sep 17, 2026
Merged

CGastrell merged 4 commits into
trunkfrom
update/webpack-config-default-request-map

Conversation

@CGastrell

@CGastrell CGastrell commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #

Proposed changes

Follow-up to the review on #52160, which was about to add a fourth copy of the same DependencyExtractionPlugin override.

Four webpack configs repeat the same nine-line block plus its rationale:

requestMap: {
	'@wordpress/theme': { external: false },
	'@wordpress/private-apis': { external: false },
},

This PR replaces those four copies with one opt-in option on DependencyExtractionPlugin:

jetpackWebpackConfig.StandardPlugins( {
	DependencyExtractionPlugin: { bundleWpUiDeps: true },
} )
  • Adds bundleWpUiDeps to projects/js-packages/webpack-config/src/webpack.js. It defaults to false, so no existing consumer changes behaviour.
  • When set, it merges the two entries in under the caller's own requestMap, so an explicit per-request override still wins.
  • States the one rule next to the map: a bundled @wordpress/private-apis unlocks only what its own bundle locked. So it must not be bundled while @wordpress/theme stays external, or in an entry that unlocks private APIs of an external wp-* script. Either way it throws "Cannot unlock an object that was not locked before".
  • Documents the option in the package README, with the current reason to use it: @wordpress/ui is built against a newer @wordpress/theme than core's wp-theme.
  • Removes the Jetpack admin call-site comment. It said WP < 7.0 has no core wp-theme, which no longer applies at the WP 7.0 minimum.

Converted call sites:

Call site Change
projects/plugins/boost/webpack.config.js block → bundleWpUiDeps: true
projects/packages/search/tools/webpack.dashboard.config.js block → bundleWpUiDeps: true
projects/plugins/protect/webpack.config.js block → bundleWpUiDeps: true
projects/plugins/jetpack/tools/webpack.config.js, admin entry only block → bundleWpUiDeps: true

Left alone on purpose

  • jetpack-ai-admin in the Jetpack config bundles @wordpress/theme alone and deliberately keeps @wordpress/private-apis external, so bundled DataViews can unlock private APIs on external @wordpress/components. A boolean cannot express that shape, so this entry keeps its own requestMap. It is the reason the option is not "always bundle both".
  • email-design-editor in the same file has no override on trunk and gets none here.
  • packages/wp-build-polyfills and packages/jetpack-mu-wpcom — untouched.
  • What gets bundled. This PR does not change it. Stopping @wordpress/theme bundling, or the theme-only shape, needs runtime proof on every affected screen first. WP 7.0 core ships @wordpress/theme 0.7.1, and these bundles use 2.0.0.

Why the earlier defaultRequestMap approach was abandoned

The first version of this PR put both entries in defaultRequestMap, flipping the default for every consumer of the shared config. That is recorded here because it is the most useful evidence on this PR. It failed in four ways:

  1. It broke packages/jetpack-mu-wpcom's build outright. @automattic/components@3.0.3 imports @wordpress/private-apis without declaring it as a dependency. Once webpack had to resolve the request instead of externalizing it, the build failed with Module not found. CI job: Install the Monorepo and build wpcomsh.
  2. It broke three tests in packages/wp-build-polyfills — the package that exists to register these very handles. One failed with the literal message Cannot unlock an object that was not locked before, which is the split failure the rule above describes. CI jobs: JS tests and Code coverage (JS).
  3. It needed two immediate opt-outs inside projects/plugins/jetpack/tools/webpack.config.js (jetpack-ai-admin and email-design-editor), written as magic empty entries ('@wordpress/private-apis': {}). Two opt-outs in the first plugin built is not a good sign for a default.
  4. It grew bundles for consumers that were already paying nothing, because they get both packages from the wp-build-polyfills shim:
Project Asset gzip before gzip after Delta
packages/newsletter build/writing-prompt.js 59,701 87,016 +27,315 (+45.8%)
packages/newsletter build/newsletter.js 155,481 182,840 +27,359 (+17.6%)
packages/my-jetpack build/index.js 579,725 607,523 +27,798 (+4.8%)

An opt-in flag has none of those costs: it touches only the four entries that already had the block.

Related product discussion/links

Does this pull request change what data or activity we track or use?

No.

Testing instructions

This is a build-configuration change with no runtime UI. The acceptance test is zero change in build output. Everything below is what I ran.

  1. For each of plugins/boost, plugins/protect, packages/search, plugins/jetpack and packages/jetpack-mu-wpcom, on trunk and on this branch, in separate worktrees:

    pnpm jetpack install <project>
    pnpm jetpack build <project> --deps -p
    

    All ten builds exit 0. packages/jetpack-mu-wpcom builds again, which is failure 1 above resolved.

  2. diff -r the build output directory of each project between trunk and this branch:

    Project Build directory *.asset.php compared Result
    plugins/boost app/assets/dist 1 whole directory byte-identical
    plugins/protect build 1 whole directory byte-identical
    packages/search build 27 whole directory byte-identical
    plugins/jetpack _inc/build 68 whole directory byte-identical
    packages/jetpack-mu-wpcom src/build 53 whole directory byte-identical
  3. Spot-check the two handles this PR is about, trunk vs branch:

    Asset wp-theme / wp-private-apis on trunk on this branch
    boost/app/assets/dist/jetpack-boost.asset.php neither neither
    protect/build/index.asset.php neither neither
    search/build/dashboard/jp-search-dashboard.asset.php neither neither
    jetpack/_inc/build/admin.asset.php neither neither
    jetpack/_inc/build/jetpack-ai-admin.asset.php wp-private-apis wp-private-apis
    jetpack/_inc/build/email-design-editor.asset.php wp-private-apis wp-private-apis
    jetpack-mu-wpcom/src/build 3 assets list a handle same 3 assets
  4. pnpm jetpack test js packages/wp-build-polyfills: passes, which is failure 2 above resolved.

  5. pnpm exec eslint on all six changed files: clean.

Not run: no browser check of any admin page. Build output is byte-identical everywhere, so there is nothing new to click through.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SWVs5oUDimen1FeGJhJAkx

…ed default

Three webpack configs each carried the same `DependencyExtractionPlugin`
override for `@wordpress/theme` and `@wordpress/private-apis`, with the
rationale written out four times. The rule now lives once in
`defaultRequestMap`, which merges under every caller's own `requestMap`.

The Jetpack plugin's AI admin and email design editor entries opt
`@wordpress/private-apis` back out with an empty entry: both unlock private
APIs exposed by external WordPress packages, so their consent map has to
stay external.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWVs5oUDimen1FeGJhJAkx
@CGastrell
CGastrell requested review from a team as code owners September 10, 2026 19:58
@CGastrell CGastrell added the [Status] Needs Review This PR is ready for review. label Sep 10, 2026
@CGastrell CGastrell self-assigned this Sep 10, 2026
@CGastrell CGastrell added the [Status] Needs Review This PR is ready for review. label Sep 10, 2026
@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack or WordPress.com Site Helper), and enable the update/webpack-config-default-request-map branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack update/webpack-config-default-request-map
bin/jetpack-downloader test jetpack-mu-wpcom-plugin update/webpack-config-default-request-map

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions github-actions Bot added [JS Package] Webpack Config [Package] Search Contains core Search functionality for Jetpack and Search plugins [Plugin] Boost A feature to speed up the site and improve performance. [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ RNA labels Sep 10, 2026
@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Jetpack plugin:

The Jetpack plugin has different release cadences depending on the platform:

  • WordPress.com Simple releases happen as soon as you deploy your changes after merging this PR (PCYsg-Jjm-p2).
  • WoA releases happen weekly.
  • Releases to self-hosted sites happen monthly:
    • Scheduled release: October 6, 2026

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.


Boost plugin:

No scheduled milestone found for this plugin.

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.


Protect plugin:

No scheduled milestone found for this plugin.

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

@jp-launch-control

jp-launch-control Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 1 file.

File Coverage Δ% Δ Uncovered
projects/packages/agents-manager/src/class-agents-manager.php 426/450 (94.67%) -0.22% 1 ❤️‍🩹

Full summary · PHP report · JS report

@anomiex anomiex left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd much rather we get rid of the theme bundling entirely, and polyfill where necessary instead. IMO bundling was the wrong decision in the first place, and then people copied it into these other places.

For that matter, we might also benefit from going further and providing handles like jetpack-wp-ui-0-22-1 and jetpack-wp-dataviews-18-1-0 to provide the versions we use of those shared components, instead of including them in dozens of bundles. Although getting wp-build to use those would likely be a pain.

'@wordpress/global-styles-engine': { external: false },
// Opts out of the shared default: the editor packages this entry unlocks
// private APIs from are external, so their consent map has to be too.
'@wordpress/private-apis': {},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same for these.

CGastrell and others added 2 commits September 10, 2026 18:06
…s option

The earlier approach added @wordpress/theme and @wordpress/private-apis to
defaultRequestMap. That changed every consumer: it broke the
packages/jetpack-mu-wpcom build, broke three packages/wp-build-polyfills tests,
needed two opt-outs inside the Jetpack plugin config, and grew two bundles.

DependencyExtractionPlugin now takes bundleWpUiDeps, off by default, so nothing
changes unless a call site asks. The four call sites that carried the nine-line
requestMap block verbatim now set the flag instead. jetpack-ai-admin keeps its
own requestMap, because it bundles @wordpress/theme alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWVs5oUDimen1FeGJhJAkx
@CGastrell CGastrell changed the title Webpack config: move the @wordpress/theme bundling rule into the shared default Webpack config: replace the duplicated @wordpress/ui bundling block with an opt-in option Sep 10, 2026
@github-actions github-actions Bot added [Plugin] Protect A plugin with features to protect a site: brute force protection, security scanning, and a WAF. Docs labels Sep 10, 2026

@dhasilva dhasilva left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the follow-up. The mechanics are correct:

  • bundleWpUiDeps defaults to false and is pulled out of the options before they reach DEWP.
  • A caller's requestMap still takes priority.
  • The byte-identical build diff is the right acceptance test.

The problem is the rationale this PR makes canonical. Both halves are false at this SHA (details inline on src/webpack.js). That also affects the direction question in anomiex's review: at the WP 7.0 floor, the original reason for bundling @wordpress/theme no longer applies.

A correction to my own comment on #52160: I called bundling the pair jointly "load-bearing". It is, but only in one direction, and I should have checked which.

  1. [blocker] The stated rationale is wrong at this SHA: the wpUiRequestMap comment, the JSDoc, the README and the Jetpack call site.
  2. [suggestion] Give the webpack-config changelog a real added entry.

Generated by Claude.

Comment on lines +149 to +152
// @wordpress/ui pulls these in transitively; externalizing them targets script handles many pages
// never register, so the whole bundle fails to enqueue. Bundle the pair jointly — split, the
// module-scope lock() in @wordpress/theme and the per-instance consent map in
// @wordpress/private-apis diverge at runtime. See PR #48173.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[blocker] Both halves of this rationale are false at this SHA. The JSDoc below, the README and the Jetpack call site all repeat it.

"Script handles many pages never register, so the whole bundle fails to enqueue."

  • Jetpack (JETPACK__MINIMUM_WP_VERSION, since General: Update minimum WordPress version to 7.0 #51370), Boost, Protect and Search all require WP 7.0.
  • WP 7.0 core registers wp-theme. Core's private-apis allowlist includes @wordpress/theme and @wordpress/ui. I checked 7.0-beta1 and 7.1 core; 6.9 has neither. wp-private-apis has been registered since 6.2.
  • Script handles are registered globally, not per page. "A page that registers neither handle" isn't a state a supported site can be in.

"Split, the lock() and the consent map diverge at runtime. See PR #48173."

I haven't checked whether using core 7.0's wp-theme works at runtime. The open question is whether it's too old for the bundled @wordpress/ui, which is what a polyfill would solve. So the direction question in anomiex's review should be settled first.

If the option stays:

  • State the real current reason. If it's that version mismatch, say so.
  • Keep only the direction-specific gotcha here, e.g. // Never bundle @wordpress/private-apis without @wordpress/theme: theme would lock on core's consent map and the bundled unlock() throws.
  • Keep the when-to-use on the @param only.
  • Point at Boost: Migrate Notice to @wordpress/ui #48171, or drop the PR number.

Generated by Claude.

Two additional options are recognized:

- `requestMap`: An easier way to specify additional dependencies to extract, rather than redefining `requestToHandle` and `requestToExternal`. Key is the dependency, value is an object with `handle` and `external` keys corresponding to the return values of `requestToHandle` and `requestToExternal`.
- `bundleWpUiDeps`: Bundle `@wordpress/theme` and `@wordpress/private-apis` instead of externalizing them to the `wp-theme` and `wp-private-apis` script handles. Defaults to `false`. Set it to `true` on an entry that renders `@wordpress/ui` on a page that registers neither handle, otherwise the whole bundle fails to enqueue. The pair is bundled jointly on purpose: see [#48173](https://github.com/Automattic/jetpack/pull/48173). Your own `requestMap` still wins over it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[blocker] Same finding as on src/webpack.js:

This line should match whatever that thread settles on.

Generated by Claude.

Comment on lines +234 to +236
// The licensing activation screen pulls in @wordpress/ui, and this page
// registers neither handle: WP < 7.0 has no core wp-theme, and the
// wp-build-polyfills shim is not loaded here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[blocker] Same finding as on src/webpack.js. Jetpack's minimum has been WP 7.0 since #51370, and 7.0 core registers wp-theme. "WP < 7.0 has no core wp-theme" therefore describes a version Jetpack no longer supports. If this call site keeps a comment, it should give this entry's own current reason for opting in.

Generated by Claude.

Comment on lines +1 to +5
Significance: patch
Type: changed
Comment: Replace the duplicated DependencyExtractionPlugin requestMap block with an opt-in bundleWpUiDeps option. No build output changes.


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[suggestion] This package gains a public option. Every earlier addition is recorded under ### Added at minor significance:

With an empty entry, its CHANGELOG will never mention bundleWpUiDeps. The four consumer entries are right as they are.

Suggested change
Significance: patch
Type: changed
Comment: Replace the duplicated DependencyExtractionPlugin requestMap block with an opt-in bundleWpUiDeps option. No build output changes.
Significance: minor
Type: added
DependencyExtractionPlugin: Add a `bundleWpUiDeps` option to bundle `@wordpress/theme` and `@wordpress/private-apis`.

Generated by Claude.

The comments, README and Jetpack call site said the wp-theme and
wp-private-apis handles are missing on many pages, and cited #48173.
Neither holds at the WP 7.0 minimum: core registers both handles, and
#48173 merged no webpack change.

State the lock rule instead: a bundled @wordpress/private-apis unlocks
only what its own bundle locked. State the current reason to use the
option: @wordpress/ui is built against a newer @wordpress/theme than
core's wp-theme. Record the new option as an added changelog entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnmaaEamjHo2MmDpnrwiNa
@CGastrell

Copy link
Copy Markdown
Contributor Author

@dhasilva

Agreed. Fixed in e84a008:

  • The comment by the map now keeps only the direction rule: a bundled @wordpress/private-apis unlocks only what its own bundle locked. So never bundle it without @wordpress/theme, or in an entry that unlocks private APIs of an external wp-* script (AI Hub: add Scheduled tasks management #51319).
  • The JSDoc and README give the current reason: @wordpress/ui is built against a newer @wordpress/theme than core's wp-theme.
  • The Jetpack call-site comment is gone.
  • Changelog: your suggestion, applied as written.

On your open question, from the code only (not tested at runtime): WP 7.0.4's theme.js is @wordpress/theme 0.7.1. It exports only privateApis, and 89 of the 120 --wpds-* names that @wordpress/ui 0.21 uses are missing from it. Our bundles use 2.0.0.


@anomiex Could we push unbundling theme out of the scope of this? This PR does not change what gets bundled. It only removes the copies. Before we stop bundling @wordpress/theme, here is where what I got. The data comes from AI reading the code, not from runtime tests.

Our bundles use @wordpress/theme 2.0.0 with @wordpress/ui 0.21.

WP 7.0 WP 7.1
Core @wordpress/theme version 0.7.1 1.0.0
Core theme exports a public ThemeProvider No Yes
--wpds-* names ui 0.21 uses that core's theme lacks 89 of 120 0
wp-build-polyfills provides a newer wp-theme No No

Unbundling means these screens run on whatever wp-theme and wp-private-apis the page has. That we will need to test these combinations first:

Dimension Values
WP 7.0.x, 7.1.x, next beta
Gutenberg plugin Off, latest
wp-build-polyfills loaded on the page No, yes (it replaces wp-private-apis on WP < 7.1)
Host Self-hosted, Atomic, Simple
Entry Boost, Protect, Search dashboard, Jetpack admin, jetpack-ai-admin

That is about 180 runs, before screen states. Each run checks that the script enqueues, the console has no errors, and the screenshots match the current build.

Based on previous experiences messing with theme/ui/tokens/polyfill, I'd rather we don't rely only on theory, and running all these combinations would fit better on a separate, validating PR.

@anomiex

anomiex commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

I'd rather we don't make it easier to do the wrong thing by putting the wrong thing into the webpack-config package. To use a metaphor, let's leave the turd unpolished and work on cleaning it up instead.

| wp-build-polyfills provides a newer wp-theme | No | No |

I think it can, if it's activated for the page in question. Where that can get tricky is in editor blocks.

@CGastrell
CGastrell merged commit 51308d3 into trunk Sep 17, 2026
134 of 137 checks passed
@CGastrell
CGastrell deleted the update/webpack-config-default-request-map branch September 17, 2026 12:44
@github-actions github-actions Bot removed the [Status] Needs Review This PR is ready for review. label Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Docs [JS Package] Webpack Config [Package] Search Contains core Search functionality for Jetpack and Search plugins [Plugin] Boost A feature to speed up the site and improve performance. [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Plugin] Protect A plugin with features to protect a site: brute force protection, security scanning, and a WAF. RNA

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants