My Jetpack: register wp-build-polyfills so the app (and Boost) loads without Gutenberg on WP < 7.0 - #50291
Conversation
…nberg My Jetpack's `my_jetpack_main_app` bundle depends on the `wp-theme` script handle (pulled in via `@wordpress/theme` since the DataViews v13 update, my-jetpack 5.34.0 / #46973). That handle ships only with the Gutenberg plugin or WP >= 7.0 core, so on stock WordPress with Gutenberg inactive it is unregistered — WordPress then silently drops `my_jetpack_main_app` (no console error). Any consumer that hard-depends on that script, notably Jetpack Boost, is dropped along with it and renders a blank page. Register the shared `WP_Build_Polyfills` shim (as Social, VideoPress, Newsletter, Forms, etc. already do) for exactly the handles the bundle uses — wp-notices, wp-private-apis, wp-theme — before enqueuing the app, restoring My Jetpack and Boost on Gutenberg-off environments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…endency My Jetpack now requires automattic/jetpack-wp-build-polyfills. Regenerate the composer.lock of every plugin that bundles My Jetpack so the package is locked in (boost/protect/search/starter-plugin) and the my-jetpack entry's require list is refreshed (backup/jetpack/social/videopress). Boost carries a bugfix changelog entry for the user-visible blank-admin-page fix; the rest are composer.lock updates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
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:
If you have questions about anything, reach out in #jetpack-developers for guidance! Jetpack 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. Backup 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. 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. Search 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. Social 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. Starter Plugin 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. Videopress 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. |
Code Coverage SummaryCoverage changed in 1 file.
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
LiamSarsfield
left a comment
There was a problem hiding this comment.
LGTM; I built the package locally to sanity-check the handle list: the only polyfill-covered handles in build/index.asset.php are wp-notices, wp-private-apis, and wp-theme, so the set is right. Timing checks out too, since register() registers synchronously once wp_default_scripts has fired. Suite passes for me.
Some nits:
-
Move
self::register_wp_build_polyfills()above thedo_action( 'myjetpack_enqueue_scripts' )on the line before it. If any callback on that hook callsWP_Build_Polyfills::register()first with a narrower handle set, it flips the registrar's$hookedflag and my-jetpack's own call records the request without registering anything for the current request (class-wp-build-polyfills.php:92). Nothing hooks it that way today, but it's a public extension point one line above the call, and the reorder costs nothing. -
Nothing guards the hand-maintained handle list against the bundle drifting. A future
@wordpress/*bump that pulls in, say,wp-viewswould blank-page again with no console error while the test stays green. wp-build-polyfills has a pattern for this intest_boot_asset_has_no_unregistered_handles; a my-jetpack version that readsbuild/index.asset.phpand skips when unbuilt would catch it. -
git diff --check origin/trunk...HEADflags trailing blank lines in seven of the plugin changelog files. -
Tiny one: the my-jetpack changelog entry leads with the shim. Flipping it to lead with the user outcome ("Fix the My Jetpack app failing to load…") reads better in release notes.
If you touch the test anyway, a tearDown() that resets the registrar statics (same pattern as WP_Build_Polyfills_Test) would keep a future second test from inheriting the leftover state. Optional.
- Register the polyfill before the myjetpack_enqueue_scripts extension hook, so a hook consumer calling WP_Build_Polyfills::register() first can't leave our handles recorded-but-unregistered for the request. - Add a bundle-drift test that fails if the built app asset depends on a polyfill-covered handle we don't request (skips when unbuilt). - Reset the registrar statics in tearDown. - Lead the changelog entry with the user-facing outcome. - Strip trailing blank lines from the propagated composer.lock changelogs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks @LiamSarsfield — all four addressed in 253d5dc:
Also took the optional |
anomiex
left a comment
There was a problem hiding this comment.
Seems reasonable. I'm not sure just how much point there is to projects/packages/my-jetpack/tests/php/Register_Wp_Build_Polyfills_Test.php though. Minor suggestions inline.
| Significance: patch | ||
| Type: fixed | ||
|
|
||
| Fix the My Jetpack app failing to load on WordPress installs without the Gutenberg plugin active, where the wp-theme script handle it depends on is otherwise unregistered. |
There was a problem hiding this comment.
| Fix the My Jetpack app failing to load on WordPress installs without the Gutenberg plugin active, where the wp-theme script handle it depends on is otherwise unregistered. | |
| Fix the My Jetpack app failing to load on WordPress 6.9 installs without the Gutenberg plugin active, where the wp-theme script handle it depends on is otherwise unregistered. |
| Significance: patch | ||
| Type: fixed | ||
|
|
||
| Fix a blank Boost admin page on WordPress installs without the Gutenberg plugin active, where the wp-theme script handle the embedded My Jetpack app depends on was otherwise unregistered. |
There was a problem hiding this comment.
| Fix a blank Boost admin page on WordPress installs without the Gutenberg plugin active, where the wp-theme script handle the embedded My Jetpack app depends on was otherwise unregistered. | |
| Fix a blank Boost admin page on WordPress 6.9 installs without the Gutenberg plugin active, where the wp-theme script handle the embedded My Jetpack app depends on was otherwise unregistered. |
| * Register polyfills for the wp-notices / wp-private-apis / wp-theme handles the | ||
| * My Jetpack app bundle depends on but WP < 7.0 does not ship (or ships with an | ||
| * incomplete allowlist) when the Gutenberg plugin is not active. | ||
| * | ||
| * Without this, `my_jetpack_main_app` is enqueued with an unregistered `wp-theme` | ||
| * dependency, so WP silently drops the script (no console error) and the My Jetpack | ||
| * app — plus any consumer that hard-depends on it, such as Jetpack Boost — renders | ||
| * a blank page. Only the handles the bundle actually uses are requested. | ||
| * |
There was a problem hiding this comment.
Seems like AI over-explanation to me.
| * Register polyfills for the wp-notices / wp-private-apis / wp-theme handles the | |
| * My Jetpack app bundle depends on but WP < 7.0 does not ship (or ships with an | |
| * incomplete allowlist) when the Gutenberg plugin is not active. | |
| * | |
| * Without this, `my_jetpack_main_app` is enqueued with an unregistered `wp-theme` | |
| * dependency, so WP silently drops the script (no console error) and the My Jetpack | |
| * app — plus any consumer that hard-depends on it, such as Jetpack Boost — renders | |
| * a blank page. Only the handles the bundle actually uses are requested. | |
| * | |
| * Register polyfills for the wp-notices / wp-private-apis / wp-theme handles the | |
| * My Jetpack app bundle depends on but WP < 7.0 does not ship (or ships with an | |
| * incomplete allowlist). | |
| * |
LiamSarsfield
left a comment
There was a problem hiding this comment.
Tested on JN with Gutenberg off and My Jetpack and Boost render where trunk was blank. LGTM.
One fast-follow: the tests assert the get_consumers() map, not the ordering that broke, so reverting the reorder still passes. A test that runs Initializer::enqueue_scripts() and checks wp-theme registers before my_jetpack_main_app would catch that.
Two minor: test_requested_handles_cover_polyfilled_bundle_dependencies calls markTestSkipped() when build/ is absent (the CI state), so it's a no-op on PRs; fail instead of skip. And not this PR, but WP_Build_Polyfills::register() returns early once $hooked is set, so a later caller after wp_default_scripts fires gets recorded but not registered. Nothing hits it today; maybe fold into #50309.
Nice fix 🚀
- Specify 'WordPress 6.9' in the my-jetpack and boost changelog entries (7.0 registers wp-theme), per @anomiex. - Trim the register_wp_build_polyfills() doc comment. - Drop the bundle-drift test: it skips (no-op) when build/ is absent in CI; keep the handle-set coverage test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Applied in df02d7f. @anomiex — all three:
@LiamSarsfield — on the follow-ups:
|
Add the My Jetpack admin page (admin.php?page=my-jetpack) as a scenario, posting four production metrics (LCP, TTFB, FCP, decodedBytesKB). My Jetpack is the heaviest Jetpack admin bundle, so it is where a bundle-size regression is most damaging. Reuses the jetpack-connected WordPress instance (page- targeted scenario), modeled on formsResponses. - scenarios.js: new myJetpack scenario; four production keys under the same owner waiver as the Dashboard/Forms keys; minResourceCount floor 64 (~70% of the observed ~92-resource load) guards a truncated capture. - post-to-codevitals.test.js: pin the scenario's keys/types and navigation contract, mirroring the formsResponses config test. - README.md: metrics table, offline-mode attribution note with measured before/after deltas, known fixture behavior, and the #50291 dependency.
…ync) #50291 merged to the monorepo on 2026-07-08; the pinned jetpack-production mirror the fixture clones does not yet carry it. Reword the README from an unmerged-PR blocker to a merged-but-unpropagated prerequisite, matching the verified mirror state.
jetpack-production trunk now carries #50291's WP_Build_Polyfills registration; a clean checkout of mirror commit 9ef44a8 renders My Jetpack and passes every capture guard (verified 2026-07-10, full local run). Reword the README so the polyfill reads as a baseline prerequisite instead of a pending blocker, and note that the pre-existing local Forms /wp/v2/settings hang persists on the current mirror.
Proposed changes
WP_Build_Polyfillsshim before enqueuingmy_jetpack_main_app, providing thewp-notices/wp-private-apis/wp-themescript handles the My Jetpack bundle depends on when the runtime doesn't ship them (WP < 7.0 with the Gutenberg plugin inactive).my_jetpack_main_appbegan depending on thewp-themehandle after the@wordpress/*monorepo bump (Update Bundled @wordpress/* monorepo #49272, "Update Bundled @wordpress/* monorepo") — driven mainly by@wordpress/dataviews14.3→17.x. DataViews 17.x renders its form controls with bundled@wordpress/uipopup/dialog components that wrap in@wordpress/ui'sThemeProvider, which imports@wordpress/theme; the build externalizes that to thewp-themescript handle. (Verified via webpack's dependency reason graph on the frozen trunk build; Jetpack 16.0, on DataViews 14.3, does not pull this code path and has nowp-themedep.) WP core registerswp-themeonly from 7.0 (6.9 ships none); Jetpack supports the current + previous WP release (today 6.9 / 7.0). With Gutenberg inactive on 6.9,wp-themeis unregistered, so WordPress silently dropsmy_jetpack_main_app— and any script that hard-depends on it, notably Jetpack Boost's admin bundle, is dropped too, rendering a blank admin page with no console error.WP_Build_Polyfills. The shim is conditional and no-ops oncewp-themeis provided by Gutenberg or WP ≥ 7.0.automattic/jetpack-wp-build-polyfillsdependency into thecomposer.lockof every plugin that bundles My Jetpack.Scope: trunk regression, not present in any released version. The trigger (
@wordpress/dataviews17.x, via #49272) merged to trunk afterbranch-16.0was cut; every stable release through 16.0 bundles DataViews ≤ 14.3.0, which never pulls the@wordpress/uiThemeProvider path — so@wordpress/themeis not imported and nowp-themedep is emitted (verified by building the 16.0 tag frozen:my_jetpack_main_apphas nowp-theme). It first reaches a release with 16.1.How the bug happens
flowchart TD A["my_jetpack_main_app build<br/>bundles @wordpress/dataviews 17.x"] --> B["DataViews renders form controls<br/>with @wordpress/ui components"] B --> C["@wordpress/ui ThemeProvider<br/>imports @wordpress/theme"] C --> D["build adds a script dependency:<br/>my_jetpack_main_app needs <b>wp-theme</b>"] D --> Q{"What registers wp-theme<br/>at runtime?"} Q -->|"WP 7.0+ core, or active Gutenberg"| G1["environment provides wp-theme"] Q -->|"this PR"| G2["WP_Build_Polyfills registers<br/>a fallback wp-theme"] Q -->|"WP 6.9 and Gutenberg off, no fix"| K["WordPress drops my_jetpack_main_app<br/>(no console error)"] G1 --> OK["script loads<br/>My Jetpack & Boost render"] G2 --> OK K --> M["My Jetpack page is blank"] K --> N["jetpack-boost-admin depends on it →<br/>dropped too → Boost page is blank"] classDef bad fill:#f8d7da,stroke:#c33,color:#611; classDef good fill:#d7f0d9,stroke:#3a3,color:#161; classDef fix fill:#d7e6fb,stroke:#36c,color:#124; class K,M,N bad class OK,G1 good class G2 fixCause and effect, step by step:
my_jetpack_main_app) is built with@wordpress/dataviews17.x.@wordpress/uicomponents (dropdowns, dialogs, tooltips). Those components use@wordpress/ui'sThemeProvider, which imports@wordpress/theme.@wordpress/themeimport into a WordPress script dependency namedwp-theme. The code is not bundled into the file — the file now expects WordPress to provide awp-themescript at runtime.wp-themescript in WP 7.0. WP 6.9 does not have it. The Gutenberg plugin also provides it — but only while Gutenberg is active.wp-themescript exists.my_jetpack_main_app. No console error appears, because no script ever ran.my_jetpack_main_appas a dependency, so when that is dropped, Boost's script is dropped too — the Boost settings page is also blank.How this PR mitigates it: before enqueuing
my_jetpack_main_app, My Jetpack registers a fallbackwp-themescript (via the sharedWP_Build_Polyfillsshim) so the handle always exists. When WordPress 7.0+ or an active Gutenberg already provideswp-theme, the fallback does nothing.What pulls in the
wp-themedependencyThe bug appears whenever
my_jetpack_main_app's bundle imports@wordpress/theme— directly, or transitively through@wordpress/ui— because the build externalizes that import to thewp-themescript handle.In the current My Jetpack build the path is
@wordpress/dataviews17.x → the@wordpress/uicomponents it renders →ThemeProvider→@wordpress/theme, which is the change that introduced it here:@wordpress/dataviews@wordpress/uicomponents that useThemeProvider— the path that appeared in the trunk buildwp-themeappears@wordpress/uiThemeProviderdoes the actualimport from '@wordpress/theme'@wordpress/ui≥ 0.13 imports theme@wordpress/themewp-themehandleDataViews is not special here — it is simply the path that pulled the import into this bundle. Any direct use of
@wordpress/ui, or a direct@wordpress/themeimport, would introducewp-themeon its own. The fix therefore targets the missing handle, not any single package.Simplest check on any build: the bug is present when
my_jetpack_main_app's builtindex.asset.phplistswp-theme. Combined with WordPress < 7.0 and Gutenberg inactive, that is the exact failing condition.Related product discussion/links
@wordpress/themestabilization for WP 7.1 (internal P2 — shortlink to add).wp-theme/@wordpress/booton WP 7.0, where core ships them incomplete). Both PRs touchautomattic/jetpack-wp-build-polyfills(different parts — this one adds a consumer, WP Build Polyfills: force-replace boot and theme on WP 7.0 #50309 changes the shim), so whichever merges second needs a lock refresh (tools/check-intra-monorepo-deps.sh -au).Does this pull request change what data or activity we track or use?
No.
Testing instructions
Repro (before this PR, on trunk / a build with
@wordpress/dataviews17.x):admin.php?page=jetpack-boost): the content area is blank, the admin menu/top bar render, and there is no console error.my_jetpack_main_appandjetpack-boost-adminare absent from the page source — dropped by WordPress because of the unregisteredwp-themedependency.Verify (with this PR):
4. Same environment → the Boost admin page renders normally.
5. Activate the Gutenberg plugin → still renders (the polyfill no-ops when
wp-themeis already registered).6. The My Jetpack page (
admin.php?page=my-jetpack) also renders in both states.