Skip to content

Add wp-build-polyfills package for WP < 7.0 compatibility#47367

Merged
dhasilva merged 40 commits intotrunkfrom
fix/polyfill-wp-build-dependencies
Mar 16, 2026
Merged

Add wp-build-polyfills package for WP < 7.0 compatibility#47367
dhasilva merged 40 commits intotrunkfrom
fix/polyfill-wp-build-dependencies

Conversation

@dhasilva
Copy link
Contributor

@dhasilva dhasilva commented Feb 26, 2026

Fixes FORMS-616

Proposed changes:

  • Create a new wp-build-polyfills package that bundles WordPress Core packages (@wordpress/notices, @wordpress/private-apis, @wordpress/theme, @wordpress/boot, @wordpress/route, @wordpress/a11y) as polyfills for WordPress < 7.0
  • The build uses a standard webpack configuration with @automattic/jetpack-webpack-config:
    • IIFE builds (classic scripts) use @wordpress/dependency-extraction-webpack-plugin via StandardPlugins for externals and .asset.php generation
    • ESM builds (script modules) use a custom PolyfillModulePlugin that handles hybrid externals — script module deps become import @wordpress/route, classic-only deps become var wp.notices window globals — and generates combined dependencies/module_dependencies asset files
  • A PHP class WP_Build_Polyfills conditionally registers the polyfill scripts/modules only when they are not already provided by Core or Gutenberg. On WP < 7.0 it force-replaces wp-notices (missing SnackbarNotices/InlineNotices exports) and wp-private-apis (incomplete allowlist)
  • Integrate the new package into the Forms package as a dependency — polyfills are registered in the Forms dashboard before wp-build runs
  • Add a provide-boot-asset-file bin script in the polyfills package that copies the built boot module asset file (build/modules/boot/index.asset.php) to the location wp-build page templates expect (build/modules/boot/index.min.asset.php). Consumers add @automattic/jetpack-wp-build-polyfills as a devDependency and call the script in their build chain — no special-case logic in the monorepo CLI needed

Why?

The @wordpress/build package no longer bundles modules from Gutenberg that are necessary for it to work. When Gutenberg is installed, or on a site with WP 7.0 (yet unreleased), those modules will be available, but if Gutenberg is not installed and the site uses a Core version < 7.0, pages that use wp-build fail due to missing dependencies.

This polyfill addresses that problem by building those dependencies for us. Since Jetpack supports the current and the last versions of WP, this polyfill will be necessary for all projects in the monorepo until WordPress 7.1 is released, at which point versions below 7.0 will not be supported anymore and we can deprecate it.

For now, only the Forms package uses wp-build for its dashboard, but the polyfill was made having in mind that other projects should be able to opt-in with as little friction as possible. Consumer setup is:

  1. Add automattic/jetpack-wp-build-polyfills as a Composer dependency
  2. Add @automattic/jetpack-wp-build-polyfills as an npm devDependency (workspace:*)
  3. Add "build:boot-asset": "provide-boot-asset-file" to the build chain (after wp-build)

Other information:

  • Have you written new tests for your changes, if applicable?
  • Have you checked the E2E test CI results, and verified that your changes do not break them?
  • Have you tested your changes on WordPress.com, if applicable (if so, you'll see a generated comment below with a script to run)?

Jetpack product discussion

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

No.

Testing instructions:

To enable the flags necessary to view the test page, add the following snippet to your site:

add_filter( 'jetpack_forms_alpha', '__return_true' );
add_filter( 'jetpack_block_editor_feature_flags', 'eb_register_feature' );
function eb_register_feature( $flags ) {
    $flags['central-form-management'] = true;
    return $flags;
}

On a JN test site:

  • Install the Code Snippets plugin, then create and activate a snippet with the code above.
  • Go to Jetpack > Forms
  • Check that the dashboard loads and works
  • Install and activate Gutenberg
  • Go back to the Forms dashboard
  • Check that it loads and works (visually there will be some minor UI fixes, like the pagination number positioning)

Locally:

  • Check out this branch and run pnpm install then jetpack build packages/wp-build-polyfills
  • Verify that projects/packages/wp-build-polyfills/build/ is generated with scripts/ and modules/ subdirectories containing bundled polyfills and .asset.php files
  • Build the Forms package: jetpack build packages/forms
  • Create/enable the snippet mentioned above
  • Disable Gutenberg if installed
  • Navigate to the Forms dashboard — verify the dashboard loads without errors
  • Activate Gutenberg
  • Navigate to the Forms dashboard — verify the dashboard loads without errors (visually there will be some minor UI fixes, like the pagination number positioning)

Changelog

  • Generate changelog entries for this PR (using AI).

@github-actions
Copy link
Contributor

github-actions bot commented Feb 26, 2026

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: March 31, 2026
    • Code freeze: March 31, 2026

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

@github-actions
Copy link
Contributor

github-actions bot commented Feb 26, 2026

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 fix/polyfill-wp-build-dependencies branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack fix/polyfill-wp-build-dependencies
bin/jetpack-downloader test jetpack-mu-wpcom-plugin fix/polyfill-wp-build-dependencies

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

@dhasilva dhasilva self-assigned this Feb 26, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new wp-build-polyfills package to provide WordPress Core packages (@wordpress/private-apis, @wordpress/theme, @wordpress/boot, @wordpress/route, @wordpress/a11y) as polyfills for WordPress versions prior to 7.0. The package includes a custom esbuild-based build script that bundles these packages as both classic scripts (IIFE format) and script modules (ESM format), with externals handling that matches wp-build's strategy. The polyfills are conditionally registered only when not already provided by Core or Gutenberg, and are integrated into the Forms package as a build dependency.

Changes:

  • Created new wp-build-polyfills package with build script, PHP registration class, and package configuration
  • Integrated polyfills into Forms package by adding dependency and calling registration during dashboard initialization
  • Updated build scripts to generate polyfills before running wp-build

Reviewed changes

Copilot reviewed 9 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
projects/packages/wp-build-polyfills/src/class-wp-build-polyfills.php PHP class for conditional polyfill registration
projects/packages/wp-build-polyfills/package.json Package configuration with devDependencies and build script
projects/packages/wp-build-polyfills/composer.json Composer configuration for PHP package
projects/packages/wp-build-polyfills/bin/build-polyfills.mjs Custom esbuild script to bundle polyfills with proper externals
projects/packages/wp-build-polyfills/.gitignore Ignore node_modules
projects/packages/wp-build-polyfills/changelog/fix-polyfill-wp-build-dependencies Changelog entry for new package
projects/packages/forms/src/dashboard/class-dashboard.php Integration of polyfill registration in Forms dashboard
projects/packages/forms/package.json Added build-polyfills script and dependency
projects/packages/forms/composer.json Added wp-build-polyfills as PHP dependency
projects/packages/forms/changelog/fix-polyfill-wp-build-dependencies Changelog entry for Forms integration
pnpm-lock.yaml Lockfile updates for new dependencies
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (2)

projects/packages/wp-build-polyfills/src/class-wp-build-polyfills.php:26

  • The documentation for the $base_file parameter should clarify that it expects a reference to a PHP file within the plugin (typically __FILE__), not a constructed path. This would help prevent the misuse seen in the Forms integration. Consider updating the parameter description to: "File path for plugins_url() computation. Should be FILE or a reference to a PHP file in the plugin."
	 * @param string $base_file File path for plugins_url() computation.

projects/packages/forms/changelog/fix-polyfill-wp-build-dependencies:2

  • The changelog type is listed as "fixed" but this change is adding a new feature (polyfill support) rather than fixing an existing bug. Consider using "added" or "changed" as the type instead to more accurately reflect the nature of the change.
Type: fixed

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@jp-launch-control
Copy link

jp-launch-control bot commented Feb 26, 2026

Code Coverage Summary

Coverage changed in 1 file.

File Coverage Δ% Δ Uncovered
projects/packages/forms/src/dashboard/class-dashboard.php 67/221 (30.32%) 4.62% -5 💚

1 file is newly checked for coverage.

File Coverage
projects/packages/wp-build-polyfills/src/class-wp-build-polyfills.php 67/73 (91.78%) 💚

Full summary · PHP report · JS report

@github-actions github-actions bot added the [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ label Feb 26, 2026
Copilot AI review requested due to automatic review settings February 27, 2026 00:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 17 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings February 27, 2026 01:35
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@dhasilva dhasilva added DO NOT MERGE don't merge it! labels Feb 27, 2026
@dhasilva dhasilva marked this pull request as draft February 27, 2026 02:13
@dhasilva dhasilva marked this pull request as draft February 27, 2026 02:13
@simison simison requested review from a team and youknowriad February 27, 2026 07:34
@dhasilva dhasilva force-pushed the fix/polyfill-wp-build-dependencies branch from 3e99057 to ebbb074 Compare March 3, 2026 00:11
@dhasilva dhasilva marked this pull request as ready for review March 4, 2026 01:55
Copilot AI review requested due to automatic review settings March 4, 2026 01:55
dhasilva and others added 24 commits March 16, 2026 17:41
When webpack bundles @wordpress/boot, it converts dynamic `import(variable)`
calls into context-module stubs that always throw "Cannot find module".
This breaks route loading because boot uses `import(route.route_module)`
to load route modules via the browser's import map at runtime.

Add a webpack loader that injects `/* webpackIgnore: true */` into
dynamic import() calls with non-string-literal arguments, telling
webpack to preserve them as native browser imports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add $wp_version_threshold parameter to register() (defaults to '7.0')
- Change version comparison from '7.0-dev' to '7.0' so polyfills also
  apply on pre-release builds
- Deduplicate version_compare calls into a single $force_replace variable

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consumers now pass a name and a list of polyfill handles they need,
enabling tracking of which plugin uses which polyfill for easier
future deprecation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d in static property

Add setAccessible(true) guards for PHP < 8.1 when accessing private
static properties via reflection in tests. Store wp_version_threshold
as a static property so multiple register() callers can raise it,
with the highest threshold winning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lAssets flag

Update preserve-dynamic-imports-loader regex to correctly handle
dynamic imports with leading block/line comments. Add additionalAssets
flag to processAssets tap for proper webpack 5 asset emission.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the regex with exponential backtracking risk with a
callback-based approach that linearly scans past comments and
whitespace to find the first meaningful character.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix backtick-split package name in loader doc comment
- Add preserve-dynamic-imports-loader.js to production-exclude
- Add wp-notices to PHP class docblock polyfill list
- Move test cleanup to tear_down() so state resets even on failure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PolyfillModulePlugin was generating incorrect dependency metadata
compared to wp-build because it couldn't resolve transitive dependencies
and lacked dynamic import detection.

- Add @wordpress/admin-ui, icons, and lazy-editor as devDependencies so
  their package.json can be read at build time
- Check wpScript field: packages with neither wpScriptModuleExports nor
  wpScript are now bundled instead of incorrectly externalized
- Use parser importCall hook to detect dynamic imports, since webpack 5's
  ExternalsPlugin reports dependencyType 'esm' for both static and
  dynamic imports

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When wp-build removes the boot module bundling, page templates will
reference a missing asset file. This adds a proxy PHP file to the
polyfills package that resolves the asset data via ReflectionClass,
and auto-detection in the monorepo CLI build that copies it to the
expected location for any package with wp-build pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PolyfillModulePlugin's scriptDeps, moduleDeps, and
dynamicImportRequests collections were never cleared between
compilations, causing stale dependencies to accumulate in watch mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…issing proxy

- Create fixture asset files in tests instead of skipping when build
  hasn't run, ensuring deterministic execution in all environments.
- Emit a warning in provideBootAssetProxy() when build/pages exists
  but the proxy source is not found.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add tests/.phpcs.dir.xml with Jetpack-Tests ruleset to eliminate
inline phpcs:ignore comments. Use secure atomic mkdir for temp
directory creation to prevent symlink race conditions. Fix inaccurate
docblock on request_polyfills helper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
phpunit.12.xml.dist is identical to phpunit.11.xml.dist, and
phpunit.8.xml.dist is identical to phpunit.9.xml.dist, matching
the convention used elsewhere in the monorepo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The i18n plugins are disabled because Core doesn't provide
translations for these packages (they aren't shipped with Core),
not because @wordpress/i18n is external.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of a runtime proxy that resolves asset data via class
autoloading, copy the built asset file directly at build time.
Add a Node.js bin script (provide-boot-asset-file) in wp-build-polyfills
that consumers call after wp-build. Remove boot-module-asset-proxy.php
and the load_boot_module_asset_file() static method as they are no
longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dhasilva dhasilva force-pushed the fix/polyfill-wp-build-dependencies branch from ea47a13 to 10a0ba1 Compare March 16, 2026 20:46
@dhasilva dhasilva merged commit 32419ce into trunk Mar 16, 2026
91 checks passed
@dhasilva dhasilva deleted the fix/polyfill-wp-build-dependencies branch March 16, 2026 21:45
@github-actions github-actions bot removed the [Status] Needs Review This PR is ready for review. label Mar 16, 2026
@github-actions github-actions bot added this to the jetpack/15.7 milestone Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Docs E2E Tests [Feature] Contact Form [Package] Forms [Package] Wp Build Polyfills [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Tests] Includes Tests [Tools] Development CLI The tools/cli to assist during JP development.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants