[wrong fork] Use package.json name as the script-module ID source of truth#78810
Closed
retrofox wants to merge 2 commits into
Closed
[wrong fork] Use package.json name as the script-module ID source of truth#78810retrofox wants to merge 2 commits into
retrofox wants to merge 2 commits into
Conversation
Decouples script-module identity from wpPlugin.packageNamespace by reading each package's own name field as the script-module ID and externalizing internal-package imports against an exact-name registry. The PHP registry, the asset manifest, and wp_register_script_module already treat IDs as opaque strings, so the npm name now survives end-to-end (npm name === import specifier === script-module ID). No-op for Core (every package's name already matches the legacy derivation). Unblocks consumers whose owned npm scope differs from packageNamespace from keeping a single identifier across pnpm, IDE, and the WordPress runtime. Replaces WordPress#77226 with a removal-of-coupling framing.
…convention Extends discovery so a plugin can pull in shared script-module packages from outside ./packages/ without any wp-build config. Any entry in package.json#dependencies whose own package.json declares wpScriptModuleExports is registered as a script module, bundled, and externalized under its actual npm name. Refactors the PACKAGES registry from string[] to Map<key, PackageEntry> so a single bundler pass handles local-source packages (transpiled + bundled) and convention-discovered packages (bundled + externalized, no transpilation). The packageJson name field already drives the script-module ID after the previous commit, so convention-discovered packages keep their npm identity end-to-end. Together with the identity refactor, closes the path from "shared package living anywhere the package manager can resolve it" to "separately-registered script module with module_dependencies tracked in .asset.php", with no new config surface. Local packages still take first-match precedence on name collision. Verified: Gutenberg's build is byte-identical (no dependencies entries declare wpScriptModuleExports, so the convention path is a no-op for Core).
Contributor
Author
|
Moved to #78822 so the branch lives on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
wpPlugin.packageNamespaceplays three roles in wp-build today:In Core, the three roles collapse into a single identifier through alignment, not by design. Gutenberg owns the
@wordpressscope; every package's directory name matches its npm name:Specifier === name. wp-build, npm, the IDE, and
wp_register_script_moduleall see@wordpress/blocks.In an organization-owned monorepo with multiple plugins, that alignment breaks. Each plugin needs its own
packageNamespace, but every package's npm name has to live under the org-owned scope (npm ownership, host-repo lint):wp-build emits the specifier
@plugin-a/feature; the npm name is@org/plugin-a-feature. Same package, two strings. Two costs follow: the IDE needs a tsconfigpathsalias to bridge them, and the unregistered specifier triggers dependency-confusion scanners.A second symptom of the same coupling: wp-build only discovers packages under
./packages/. Shared packages that live outside that directory (workspace siblings, npm-installed siblings) cannot be compiled as script modules, so they get inlined into every consumer's bundle.wp_register_script_module( $id, ... )already accepts arbitrary IDs and the PHP registry treats them as opaque strings. The runtime indirection layer exists; wp-build is the only piece tying identity back to a config-derived shortcut.Proposal
Two convention-driven changes that close the identity-discovery loop together:
1. Identity from
package.json#name. Read each script module's ID from the package itself. Every other modern bundler treatsnameas the source of truth.(
build.mjs:727-730) Plus an exact-nameonResolvehandler inwordpress-externals-plugin.mjsthat externalizes discovered packages by their actualname. The legacy regex pattern stays as a fallback for Core's prerequisites pipeline.2. Discovery via
wpScriptModuleExports. Beyond./packages/<dir>/, any entry in the plugin'sdependencieswhosepackage.jsondeclareswpScriptModuleExportsis registered as a script module, bundled, and externalized under its own npm name. No new config; local packages take first-match precedence on name collision.The two changes are interlocked: identity decoupling makes discovery extension safe (a convention-discovered package keeps its npm identity, never gets renamed to
@<packageNamespace>/<dir>); discovery extension is what makes identity decoupling materially useful (any plugin can now consume a shared script-module package living anywhere the package manager resolves it).Compatibility
No-op for Core. Every Gutenberg package's
namealready matches the legacy derivation, and the rootdependenciesdeclares zero entries withwpScriptModuleExports, so both paths are no-ops. A full Gutenberg build on this branch produces a byte-identicalbuild/modules/tree compared to trunk (verified locally).For consumers with the dual-naming pattern, migration is renaming the package's
namefield. The directory does not need to move. For consumers consuming shared script modules via inlined bundles today, the migration is addingwpScriptModuleExportsto the shared package'spackage.jsonand letting the convention path pick it up.Context
Replaces #77226 (which tried to extend discovery via a
packageSourcesconfig). No new config here; one less role forpackageNamespace, and #77225 closes via convention rather than configuration.Relates to #78714 / #78715.