Skip to content

Build: Fix import map ordering in wp-build page template#76870

Open
lezama wants to merge 1 commit intoWordPress:trunkfrom
lezama:fix/wp-build-boot-importmap-compat
Open

Build: Fix import map ordering in wp-build page template#76870
lezama wants to merge 1 commit intoWordPress:trunkfrom
lezama:fix/wp-build-boot-importmap-compat

Conversation

@lezama
Copy link
Copy Markdown
Contributor

@lezama lezama commented Mar 27, 2026

Description

The page-wp-admin.php template generated by @wordpress/build uses import("@wordpress/boot") inside a classic inline script (wp_add_inline_script). This is incorrect: import() with a bare specifier requires the import map to already be in the DOM.

In admin_print_footer_scripts, both _wp_footer_scripts and print_import_map are registered at priority 10, but _wp_footer_scripts comes first in registration order. The classic inline script therefore always appears before the import map in the HTML output.

This works by accident in most environments — browsers typically defer the specifier resolution to a microtask, by which point the import map has been parsed. But any plugin that changes execution timing (e.g. converting scripts to `type="module"` via `script_loader_tag`) breaks it:

```
TypeError: Failed to resolve module specifier '@wordpress/boot'
```

This affects all wp-build pages: Forms, Font Library, Connectors.

Fix

Two changes:

  1. Template (page-wp-admin.php.template): The inline script no longer calls import(). Instead it sets the boot config as a plain global (window.__wpBuildBootConfig).

  2. Loader (build.mjs): The previously empty loader.js stub now contains the actual boot code — it imports @wordpress/boot and calls initSinglePage with the config from the global. Since loader.js is a registered script module, it executes after the import map by definition.

Testing

  1. Build a project that uses @wordpress/build with a wp-admin page layout
  2. Install The Events Calendar
  3. Navigate to the wp-build page — should render normally
  4. Check console — no module specifier errors
  5. With Gutenberg plugin active, also test /wp-admin/themes.php?page=font-library-wp-admin and /wp-admin/options-general.php?page=options-connectors-wp-admin

@github-actions
Copy link
Copy Markdown

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: lezama <migueluy@git.wordpress.org>

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

@simison simison requested review from jsnajdr and youknowriad March 27, 2026 19:59
@simison simison added [Type] Bug An existing feature does not function as intended [Package] wp-build /packages/wp-build labels Mar 27, 2026
@lezama lezama changed the title wp-build: Fix importmap compatibility in page-wp-admin boot sequence Build: Fix import map ordering in wp-build page template Mar 27, 2026
The generated `page-wp-admin.php` uses `import("@wordpress/boot")`
inside a regular inline script (`wp_add_inline_script`). WordPress
outputs the importmap AFTER regular footer scripts in the DOM, so
the `import()` call executes before the importmap is available. This
works by coincidence due to browser microtask timing in most setups.

However, plugins that convert scripts to `type="module"` via the
`script_loader_tag` filter (e.g., The Events Calendar via StellarWP)
disrupt this timing, causing the import to fail with:

  TypeError: Failed to resolve module specifier '@wordpress/boot'

This results in a blank page with no content rendered.

Fix: Replace the fragile inline `import()` with a two-step approach:
1. The regular inline script sets boot config as a plain global
   (`window.__wpBuildBootConfig`) — no module specifiers needed.
2. The `loader.js` script module (previously empty) imports
   `@wordpress/boot` and calls `initSinglePage` with the config.
   Script modules are guaranteed to execute after the importmap.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lezama lezama force-pushed the fix/wp-build-boot-importmap-compat branch from 7703ff4 to f954089 Compare March 27, 2026 20:56
Copy link
Copy Markdown
Contributor

@CGastrell CGastrell left a comment

Choose a reason for hiding this comment

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

Tests as described, worked with Gutenberg disabled as well. The build error is not entirely correct, the pageSlugUnderscore identifier is on a different scope, but in the same global scope? Maybe you'll need to fix that in order to make the CI checks happy

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