-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Build Tools: Add wpPlugin.packageSources for additional package directories #77226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8e59c9a
9c68169
263275e
a914703
dc47e96
ef1fc80
491abf1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -90,23 +90,64 @@ const TEST_FILE_PATTERNS = [ | |||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Get all package names from the packages directory. | ||||||||||||||||||||||||||||||||||
| * A discovered package in the registry. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| * @return {string[]} Array of package names. | ||||||||||||||||||||||||||||||||||
| * @typedef {Object} PackageEntry | ||||||||||||||||||||||||||||||||||
| * @property {string} dir Absolute path to the package directory. | ||||||||||||||||||||||||||||||||||
| * @property {import('./package-utils.mjs').PackageJson} packageJson Parsed package.json contents. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| function getAllPackages() { | ||||||||||||||||||||||||||||||||||
| return glob | ||||||||||||||||||||||||||||||||||
| .sync( normalizePath( path.join( PACKAGES_DIR, '*', 'package.json' ) ) ) | ||||||||||||||||||||||||||||||||||
| .map( ( packageJsonPath ) => | ||||||||||||||||||||||||||||||||||
| path.basename( path.dirname( packageJsonPath ) ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const PACKAGES = getAllPackages(); | ||||||||||||||||||||||||||||||||||
| const ROOT_PACKAGE_JSON = getPackageInfoFromFile( | ||||||||||||||||||||||||||||||||||
| path.join( ROOT_DIR, 'package.json' ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| const WP_PLUGIN_CONFIG = ROOT_PACKAGE_JSON.wpPlugin || {}; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Directories to scan for packages. Always starts with `./packages/`. | ||||||||||||||||||||||||||||||||||
| * Additional directories from `wpPlugin.packageSources` are appended | ||||||||||||||||||||||||||||||||||
| * and resolved relative to the project root. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| * @type {string[]} | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| const PACKAGE_DIRS = [ | ||||||||||||||||||||||||||||||||||
| PACKAGES_DIR, | ||||||||||||||||||||||||||||||||||
| ...( WP_PLUGIN_CONFIG.packageSources || [] ).map( ( s ) => | ||||||||||||||||||||||||||||||||||
| path.resolve( ROOT_DIR, s ) | ||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Discover every package by scanning each directory in PACKAGE_DIRS. | ||||||||||||||||||||||||||||||||||
| * Local packages (`./packages/`) are scanned first, so they take | ||||||||||||||||||||||||||||||||||
| * priority when two directories contain a package with the same name. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| * @return {Map<string, PackageEntry>} Map of package names to their entry data. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| function getAllPackages() { | ||||||||||||||||||||||||||||||||||
| const registry = new Map(); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| for ( const dir of PACKAGE_DIRS ) { | ||||||||||||||||||||||||||||||||||
| const pkgJsonPaths = glob.sync( | ||||||||||||||||||||||||||||||||||
| normalizePath( path.join( dir, '*', 'package.json' ) ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| for ( const pkgJsonPath of pkgJsonPaths ) { | ||||||||||||||||||||||||||||||||||
| const name = path.basename( path.dirname( pkgJsonPath ) ); | ||||||||||||||||||||||||||||||||||
| // First match wins — local packages take priority over | ||||||||||||||||||||||||||||||||||
| // sources-discovered packages. | ||||||||||||||||||||||||||||||||||
| if ( ! registry.has( name ) ) { | ||||||||||||||||||||||||||||||||||
| registry.set( name, { | ||||||||||||||||||||||||||||||||||
| dir: path.dirname( pkgJsonPath ), | ||||||||||||||||||||||||||||||||||
| packageJson: getPackageInfoFromFile( pkgJsonPath ), | ||||||||||||||||||||||||||||||||||
| } ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return registry; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const PACKAGES = getAllPackages(); | ||||||||||||||||||||||||||||||||||
| const SCRIPT_GLOBAL = WP_PLUGIN_CONFIG.scriptGlobal; | ||||||||||||||||||||||||||||||||||
| const PACKAGE_NAMESPACE = WP_PLUGIN_CONFIG.packageNamespace; | ||||||||||||||||||||||||||||||||||
| const HANDLE_PREFIX = WP_PLUGIN_CONFIG.handlePrefix || PACKAGE_NAMESPACE; | ||||||||||||||||||||||||||||||||||
|
|
@@ -480,7 +521,6 @@ function resolveEntryPoint( packageDir, packageJson ) { | |||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| async function bundlePackage( packageName, options = {} ) { | ||||||||||||||||||||||||||||||||||
| const { | ||||||||||||||||||||||||||||||||||
| sourceDir = PACKAGES_DIR, | ||||||||||||||||||||||||||||||||||
| handlePrefix = HANDLE_PREFIX, | ||||||||||||||||||||||||||||||||||
| scriptGlobal = SCRIPT_GLOBAL, | ||||||||||||||||||||||||||||||||||
| packageNamespace = PACKAGE_NAMESPACE, | ||||||||||||||||||||||||||||||||||
|
|
@@ -489,10 +529,9 @@ async function bundlePackage( packageName, options = {} ) { | |||||||||||||||||||||||||||||||||
| const builtModules = []; | ||||||||||||||||||||||||||||||||||
| const builtScripts = []; | ||||||||||||||||||||||||||||||||||
| const builtStyles = []; | ||||||||||||||||||||||||||||||||||
| const packageDir = path.join( sourceDir, packageName ); | ||||||||||||||||||||||||||||||||||
| const packageJson = getPackageInfoFromFile( | ||||||||||||||||||||||||||||||||||
| path.join( sourceDir, packageName, 'package.json' ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| const packageEntry = PACKAGES.get( packageName ); | ||||||||||||||||||||||||||||||||||
| const packageDir = packageEntry.dir; | ||||||||||||||||||||||||||||||||||
| const packageJson = packageEntry.packageJson; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const builds = []; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
@@ -862,7 +901,7 @@ async function inferStyleDependencies( scriptDependencies, packageName ) { | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const styleDeps = []; | ||||||||||||||||||||||||||||||||||
| // Get the resolve directory for context-aware package resolution | ||||||||||||||||||||||||||||||||||
| const resolveDir = path.join( PACKAGES_DIR, packageName ); | ||||||||||||||||||||||||||||||||||
| const resolveDir = PACKAGES.get( packageName ).dir; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| for ( const scriptHandle of scriptDependencies ) { | ||||||||||||||||||||||||||||||||||
| // Skip non-package dependencies (like 'react', 'lodash', etc.) | ||||||||||||||||||||||||||||||||||
|
|
@@ -1215,16 +1254,9 @@ async function generatePagesPhp( pageData, replacements ) { | |||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| async function transpilePackage( packageName ) { | ||||||||||||||||||||||||||||||||||
| const startTime = Date.now(); | ||||||||||||||||||||||||||||||||||
| const packageDir = path.join( PACKAGES_DIR, packageName ); | ||||||||||||||||||||||||||||||||||
| const packageJson = getPackageInfoFromFile( | ||||||||||||||||||||||||||||||||||
| path.join( PACKAGES_DIR, packageName, 'package.json' ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if ( ! packageJson ) { | ||||||||||||||||||||||||||||||||||
| throw new Error( | ||||||||||||||||||||||||||||||||||
| `Could not find package.json for package: ${ packageName }` | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| const packageEntry = PACKAGES.get( packageName ); | ||||||||||||||||||||||||||||||||||
| const packageDir = packageEntry.dir; | ||||||||||||||||||||||||||||||||||
| const packageJson = packageEntry.packageJson; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const srcFiles = await glob( `src/**/*.${ SOURCE_EXTENSIONS }`, { | ||||||||||||||||||||||||||||||||||
| cwd: packageDir, | ||||||||||||||||||||||||||||||||||
|
|
@@ -1432,10 +1464,9 @@ async function transpilePackage( packageName ) { | |||||||||||||||||||||||||||||||||
| * @return {Promise<number|null>} Build time in milliseconds, or null if no styles. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| async function compileStyles( packageName ) { | ||||||||||||||||||||||||||||||||||
| const packageDir = path.join( PACKAGES_DIR, packageName ); | ||||||||||||||||||||||||||||||||||
| const packageJson = getPackageInfoFromFile( | ||||||||||||||||||||||||||||||||||
| path.join( PACKAGES_DIR, packageName, 'package.json' ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| const packageEntry = PACKAGES.get( packageName ); | ||||||||||||||||||||||||||||||||||
| const packageDir = packageEntry.dir; | ||||||||||||||||||||||||||||||||||
| const packageJson = packageEntry.packageJson; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Get SCSS entry point patterns from package.json, default to root-level only | ||||||||||||||||||||||||||||||||||
| const scssEntryPointPatterns = packageJson.wpStyleEntryPoints || [ | ||||||||||||||||||||||||||||||||||
|
|
@@ -1543,12 +1574,15 @@ function isPackageSourceFile( filename ) { | |||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return PACKAGES.some( ( packageName ) => { | ||||||||||||||||||||||||||||||||||
| for ( const entry of PACKAGES.values() ) { | ||||||||||||||||||||||||||||||||||
| const packagePath = normalizePath( | ||||||||||||||||||||||||||||||||||
| path.join( 'packages', packageName ) | ||||||||||||||||||||||||||||||||||
| path.relative( ROOT_DIR, entry.dir ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| return relativePath.startsWith( packagePath + '/' ); | ||||||||||||||||||||||||||||||||||
| } ); | ||||||||||||||||||||||||||||||||||
| if ( relativePath.startsWith( packagePath + '/' ) ) { | ||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
|
|
@@ -1562,9 +1596,9 @@ function getPackageName( filename ) { | |||||||||||||||||||||||||||||||||
| path.relative( process.cwd(), filename ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| for ( const packageName of PACKAGES ) { | ||||||||||||||||||||||||||||||||||
| for ( const [ packageName, entry ] of PACKAGES ) { | ||||||||||||||||||||||||||||||||||
| const packagePath = normalizePath( | ||||||||||||||||||||||||||||||||||
| path.join( 'packages', packageName ) | ||||||||||||||||||||||||||||||||||
| path.relative( ROOT_DIR, entry.dir ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| if ( relativePath.startsWith( packagePath + '/' ) ) { | ||||||||||||||||||||||||||||||||||
| return packageName; | ||||||||||||||||||||||||||||||||||
|
|
@@ -1727,17 +1761,14 @@ async function buildAll( baseUrlExpression ) { | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const startTime = Date.now(); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Build maps: short name ↔ full name ↔ package.json from package.json files | ||||||||||||||||||||||||||||||||||
| // Build maps: short name ↔ full name ↔ package.json from the registry | ||||||||||||||||||||||||||||||||||
| const shortToFull = new Map(); | ||||||||||||||||||||||||||||||||||
| const fullToShort = new Map(); | ||||||||||||||||||||||||||||||||||
| const fullToPackageJson = new Map(); | ||||||||||||||||||||||||||||||||||
| for ( const pkg of PACKAGES ) { | ||||||||||||||||||||||||||||||||||
| const packageJson = getPackageInfoFromFile( | ||||||||||||||||||||||||||||||||||
| path.join( PACKAGES_DIR, pkg, 'package.json' ) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| shortToFull.set( pkg, packageJson.name ); | ||||||||||||||||||||||||||||||||||
| fullToShort.set( packageJson.name, pkg ); | ||||||||||||||||||||||||||||||||||
| fullToPackageJson.set( packageJson.name, packageJson ); | ||||||||||||||||||||||||||||||||||
| for ( const [ pkg, entry ] of PACKAGES ) { | ||||||||||||||||||||||||||||||||||
| shortToFull.set( pkg, entry.packageJson.name ); | ||||||||||||||||||||||||||||||||||
| fullToShort.set( entry.packageJson.name, pkg ); | ||||||||||||||||||||||||||||||||||
| fullToPackageJson.set( entry.packageJson.name, entry.packageJson ); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+1769
to
+1771
|
||||||||||||||||||||||||||||||||||
| shortToFull.set( pkg, entry.packageJson.name ); | |
| fullToShort.set( entry.packageJson.name, pkg ); | |
| fullToPackageJson.set( entry.packageJson.name, entry.packageJson ); | |
| const fullName = entry.packageJson.name; | |
| if ( fullToShort.has( fullName ) ) { | |
| const existingPackage = fullToShort.get( fullName ); | |
| throw new Error( | |
| `Duplicate package.json name "${ fullName }" detected for package directories "${ existingPackage }" and "${ pkg }". Package names must be unique across all discovered roots.` | |
| ); | |
| } | |
| shortToFull.set( pkg, fullName ); | |
| fullToShort.set( fullName, pkg ); | |
| fullToPackageJson.set( fullName, entry.packageJson ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Valid edge case, but the existing code doesn't validate any similar collision. Keeping consistent — can address in a follow-up if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
transpilePackagenow assumesPACKAGES.get( packageName )always returns an entry. IfpackageNameis ever missing/undefined (e.g., due to duplicate full package names or unexpected dependency graph output), this will throw a generic TypeError. Consider adding an explicit guard and throwing a more actionable error (similar to the prior “Could not find package.json…” check).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All callers pass names from
PACKAGESiterations, soget()always returns a defined entry. The removed check was also dead code —getPackageInfoFromFilethrows on missing files, never returns null.