block_editor-1.0.x-dev/tools/webpack/wordpress-packages.js

tools/webpack/wordpress-packages.js
/**
 * External dependencies
 */
const { join } = require( 'path' );
const { resolve } = require( 'path' );

/**
 * Internal dependencies
 */
const packageJson = require( '../../package.json' );

// WordPress packages namespace
const WORDPRESS_NAMESPACE = '@wordpress/';

/**
 * Dynamically extract dependencies from a WordPress package's package.json
 * 
 * @param {string} packageName Package name without @wordpress/ prefix
 * @return {Array} Array of dependency handles (react, react-dom, wp-*)
 */
function extractPackageDependencies( packageName ) {
	try {
		const pkgPath = resolve( __dirname, '..', '..', 'node_modules', '@wordpress', packageName );
		const pkgJson = require( join( pkgPath, 'package.json' ) );
		const deps = [];

		// Get all dependencies and peerDependencies
		const allDeps = {
			...( pkgJson.dependencies || {} ),
			...( pkgJson.peerDependencies || {} ),
		};

		// Extract relevant dependencies
		Object.keys( allDeps ).forEach( ( dep ) => {
			if ( dep === 'react' ) {
				deps.push( 'react' );
			} else if ( dep === 'react-dom' ) {
				deps.push( 'react-dom' );
			} else if ( dep.startsWith( '@wordpress/' ) ) {
				// Convert @wordpress/element to wp-element
				const wpPkg = dep.replace( '@wordpress/', '' );
				deps.push( `wp-${ wpPkg }` );
			}
		} );

		return deps;
	} catch ( error ) {
		console.warn( `⚠️  Could not extract dependencies for @wordpress/${ packageName }:`, error.message );
		return [];
	}
}

/**
 * Custom plugin to create asset files with dynamically extracted dependencies
 */
class WordPressAssetPlugin {
	apply( compiler ) {
		compiler.hooks.emit.tapAsync( 'WordPressAssetPlugin', ( compilation, callback ) => {
			const packages = getWordPressPackages();

			packages.forEach( ( pkg ) => {
				// Dynamically extract dependencies from package.json
				const deps = extractPackageDependencies( pkg );

				// Get the chunk hash for versioning
				const chunks = Array.from( compilation.chunks );
				const chunk = chunks.find( ( c ) => c.name === pkg );
				const hash = chunk && chunk.contentHash && chunk.contentHash.javascript
					? chunk.contentHash.javascript
					: 'dev';

				// Create asset file content
				const depsArray = deps.map( ( dep ) => `'${ dep }'` ).join( ', ' );
				const assetContent = `<?php return array('dependencies' => array(${ depsArray }), 'version' => '${ hash }');`;

				// Determine output filename based on webpack mode
				const filename = compilation.options.mode === 'production'
					? `${ pkg }/index.min.asset.php`
					: `${ pkg }/index.asset.php`;

				// Add to compilation assets
				compilation.assets[ filename ] = {
					source: () => assetContent,
					size: () => assetContent.length,
				};
			} );

			callback();
		} );
	}
}

/**
 * Get all @wordpress packages from package.json dependencies.
 *
 * @return {Array} Array of package names without the @wordpress/ prefix.
 */
function getWordPressPackages() {
	// Only use dependencies, not devDependencies (dev packages are build tools)
	const deps = packageJson.dependencies || {};

	return Object.keys( deps )
		.filter( ( packageName ) => packageName.startsWith( WORDPRESS_NAMESPACE ) )
		.map( ( packageName ) => packageName.replace( WORDPRESS_NAMESPACE, '' ) );
}

const wordpressPackages = getWordPressPackages();

// If no WordPress packages, return empty config
if ( wordpressPackages.length === 0 ) {
	module.exports = {
		mode: 'none',
		entry: {},
		plugins: [
			{
				apply: ( compiler ) => {
					compiler.hooks.done.tap( 'LogNoWordPressPackages', () => {
						console.log( '\nℹ No @wordpress packages found in dependencies. Install them with: npm install @wordpress/element' );
					} );
				},
			},
		],
	};
} else {
	// Build entry points for each WordPress package
	const entries = {};
	wordpressPackages.forEach( ( packageName ) => {
		entries[ packageName ] = `@wordpress/${ packageName }`;
	} );

	module.exports = [
		// Production build (minified)
		{
			mode: 'production',
			entry: entries,
			output: {
				path: join( __dirname, '..', '..', 'build', 'wordpress' ),
				filename: '[name]/index.min.js',
				library: {
					name: [ 'wp', '[name]' ],
					type: 'window',
				},
			},
			externals: {
				react: 'React',
				'react-dom': 'ReactDOM',
			},
			plugins: [
				new WordPressAssetPlugin(),
				{
					apply: ( compiler ) => {
						compiler.hooks.done.tap( 'LogWordPressPackages', () => {
							console.log( '\n✓ Built WordPress packages to build/wordpress/:' );
							wordpressPackages.forEach( ( pkg ) => {
								console.log( `  - @wordpress/${ pkg }` );
							} );
							console.log( '' );
						} );
					},
				},
			],
		},
		// Development build (for debugging)
		{
			mode: 'development',
			devtool: 'source-map',
			entry: entries,
			output: {
				path: join( __dirname, '..', '..', 'build', 'wordpress' ),
				filename: '[name]/index.js',
				library: {
					name: [ 'wp', '[name]' ],
					type: 'window',
				},
			},
			externals: {
				react: 'React',
				'react-dom': 'ReactDOM',
			},
			plugins: [
				new WordPressAssetPlugin(),
			],
		},
	];
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc