Skip to content

Conversation

@dcalhoun
Copy link
Member

@dcalhoun dcalhoun commented Oct 31, 2025

Related:

What?

Load plugin assets within the default, bundled editor.

Why?

This results in several improvements:

  • Reduce the number of assets retrieved from the site, improving performance through reduced network activity.
  • Enable important patches applied to external modules.
    • Fix CMM-880 - fix "Browse All" within quick inserter
    • Fix CMM-895 - fix broken text entry after swiping outside of block canvas
    • Fix CMM-902 - enable populating the Patterns tab within the block inserter
  • Enable exploratory private API usage to allow planning public APIs.
  • Enable private module access necessary for the native iOS inserter feature.
  • Fix CMM-583 - relying upon local @wordpress modules avoids WordPress core block limitations
  • Fix CMM-897 - no longer loading preferences file from remote site
  • Prepare for project simplification by negating the need for a separate "remote" editor variant (src/remote.html); related code will be removed at a later time in a separate PR.

How?

Testing Instructions

Important

To test the end result of these changes, Automattic/jetpack#45715 must be applied to your site. Otherwise, plugins will not load.

Accessibility Testing Instructions

N/A, no navigation changes.

Screenshots or screencast

bundled-editor-plugins-native-inserter.mov

We will expose these modules as globals for plugins.
Mirror the WP Admin post editor environment. Plugins often leverage
these globals.
Styles are absent entirely if these are removed.
The previous logic excluded all assets when the `disallowedPackages`
parameter was empty.
Now that the bundled editor loads plugins, the associated native logic
must always be available. Additionally, we should not invoke the logic
if site configuration is unavailable.
We must relocated this logic now that we initialize the editor before
loading remote assets.
These are included in the GBK bundle.
The remote editor is deprecated now that the bundled editor supports
plugins.
These are included in the GBK bundle.
These private module paths are used to access private APIs. Replacing
them is not possible, as the APIs are inherently not accessible on the
public globals. Long term, the plan is to replace the internal module
path usage with public APIs once available.
Several `@wordpress` modules include strings requiring localization.
These strings are set on module load, which means we cannot load the
module until after we configure localization.
Attempting to utilize `window.wp` globals before they are defined causes
editor load failures. These changes avoid such references by executing
code in a specific sequence and simplifying the top-level error message
UI.
The `remote.html` reference was erroneously copied from the
`vite.config.remote.js` file.
They are not externally provided, the bundled editor includes these
modules. The external designation was a mistake from copying over the
`vite.config.remote.js` configuration, where the modules are externally
provided.
Transforming these files fails, but also should not be done. The
transform is intended to first-party code, ensuring all `@wordpress`
module imports use globals instead.
@dcalhoun dcalhoun added the [Type] Enhancement A suggestion for improvement. label Oct 31, 2025
@dcalhoun dcalhoun requested a review from Copilot October 31, 2025 17:32
Copy link

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 implements bundled WordPress modules to reduce reliance on remote assets and enable consistent editor loading. The changes introduce a Vite plugin that externalizes @wordpress imports to global variables (mimicking Gutenberg's webpack plugin), preloads core WordPress modules via new utility files, and adjusts the editor initialization flow to load these globals before other modules.

  • Adds a custom Vite plugin (wordPressExternals) that transforms WordPress imports into global variable references
  • Introduces wordpress-i18n.js and wordpress-globals.js to pre-load WordPress modules onto window.wp
  • Updates the editor initialization flow to sequence module loading and enable plugin support conditionally

Reviewed Changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
vite.config.js Adds the wordPressExternals Vite plugin and imports for dependency externalization
src/utils/wordpress-i18n.js Pre-loads i18n and hooks modules onto window.wp
src/utils/wordpress-globals.js Initializes all WordPress modules and external dependencies as globals
src/utils/bundled-editor.jsx Refactors initialization flow to load globals sequentially and support plugins
src/utils/bridge.js Adds exclude=core,gutenberg param to editor assets endpoint
src/index.html Loads wordpress-i18n.js before main script
src/components/editor-load-error/style.scss Updates error message styling
src/components/editor-load-error/index.jsx Converts error component to return HTML string instead of JSX
package.json Adds @wordpress/data-controls and @wordpress/preferences-persistence dependencies
package-lock.json Updates lockfile with new dependencies and version changes
ios/Sources/GutenbergKit/Sources/EditorViewController.swift Simplifies editor loading logic and adds plugins config param
ios/Sources/GutenbergKit/Sources/Cache/EditorAssetsLibrary.swift Adds exclude=core,gutenberg param to manifest loading
android/Gutenberg/src/main/java/org/wordpress/gutenberg/GutenbergView.kt Simplifies editor URL logic and adds plugins config param
src/utils/editor-loader.js Fixes potential regex error with empty disallowed packages

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

We expose these a globals, so the project needs to declare them as
dependencies.
Comment on lines +25 to +26
// The GutenbergKit bundle includes the required `@wordpress` modules
let excludeParam = URLQueryItem(name: "exclude", value: "core,gutenberg")
Copy link
Member Author

Choose a reason for hiding this comment

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

This leverages the query parameter introduced in Automattic/jetpack#45715. We exclude "core" and Gutenberg so that only third-party plugin assets are returned.

Comment on lines +14 to +15
* Simple error message avoids `@wordpress` components to avoid
* complex dependency management during editor initialization.
Copy link
Member Author

Choose a reason for hiding this comment

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

This simple error message is used within the editor entry file if an error occurs during the sequence to load and initialize foundational @wordpress modules. Libraries like react or @wordpress/components may not be available depending on the error, so we use string templates instead.

Long term, we should broadcast the editor load failure to the native host app and allow it to control how an error is presented to the user.

Copy link
Contributor

Choose a reason for hiding this comment

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

we should broadcast the editor load failure to the native host app and allow it to control how an error is presented to the user

That sounds great. And thanks for addressing it. It already helped me see an error due to the new dependencies.

Comment on lines 27 to 31
.then( configureLocale )
.then( loadRemainingGlobals )
.then( initializeApiFetchWrapper )
.then( initializeEditor )
.then( loadPluginsIfEnabled )
Copy link
Member Author

Choose a reason for hiding this comment

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

This sequence is fairly similar to the one it's replacing and the one found in the to-be-deprecated src/utils/remote-editor.jsx. The important piece to understand is that a specific loading sequence is required to ensure dependencies are in place before the logic attempts to reference them.

  1. Load i18n modules (within index.html).
  2. Configure i18n.
  3. Load remaining @wordpress modules (depend upon i18n configuration).
  4. Load plugins (depend upon @wordpress modules).

Comment on lines +110 to +116
const excludedScriptIDs = disallowedPackages.length
? new RegExp(
disallowedPackages
.map( ( script ) => `wp-${ script }-js` )
.join( '|' )
)
: null;
Copy link
Member Author

Choose a reason for hiding this comment

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

This fixes a hidden bug where an empty disallowedPackages value resulted in disallowing all packages due to the empty regex created. Falling back to null avoids this.

Copy link
Member Author

Choose a reason for hiding this comment

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

We expose all the relevant @wordpress modules as window.wp globals to mimic the WP Admin environment. This allows plugins to rely upon them as they do in the WP Admin environment.

Copy link
Member Author

Choose a reason for hiding this comment

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

As noted elsewhere, we must load and configure i18n before the rest of the @wordpress modules load. This is due to top-level localization strings found in the @wordpress modules. See wordpress-mobile/gutenberg-mobile#4329.

Copy link
Member Author

Choose a reason for hiding this comment

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

Much of this is copied from the vite.config.remote.js file, with a few adjustments noted inline.

Comment on lines +46 to +49
// Skip transforming node_modules files
if ( id.includes( 'node_modules' ) ) {
return null;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

The previous remote editor variant prevented transforming node_modules by externalizing them via the external Rollup configuration. Because now bundle @wordpress modules, we no longer mark them as external. To avoid transforming node_modules, we add new guard logic here.

Copy link
Contributor

@kean kean left a comment

Choose a reason for hiding this comment

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

Tested with my WoA site – worked great, blocks from Jetpack worked.

"clsx": "^2.1.1",
"lodash": "^4.17.21",
"moment": "^2.30.1",
"react": "^18.3.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

Just checking – are these dependencies updates part of the change?
Is lodash something that plugins and react might need?

Copy link
Member Author

Choose a reason for hiding this comment

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

These dependencies were added as GutenbergKit now explicitly exposes them as globals for plugins.

Yes, plugins may leverage the lodash global. In my testing, the Jetpack plugin does.

Comment on lines +14 to +15
* Simple error message avoids `@wordpress` components to avoid
* complex dependency management during editor initialization.
Copy link
Contributor

Choose a reason for hiding this comment

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

we should broadcast the editor load failure to the native host app and allow it to control how an error is presented to the user

That sounds great. And thanks for addressing it. It already helped me see an error due to the new dependencies.

This fixes incorrect sequencing where the VideoPress extension of the
Video block was not registered.
Some third-party code expects this foundational library that is
available in the WP Admin context.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants