From cc133bfae5fe1b575e754fbcd71ff3505a448a35 Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Tue, 10 Sep 2024 09:41:32 +0200 Subject: [PATCH] Build: Include Core blocks' `render` and `variations` files (#63311) If a Core block's `block.json` contains a `render` and/or `variations` field that points to a PHP file name, copy those files to the build directory. Co-authored-by: ockham Co-authored-by: gziolo --- packages/scripts/config/webpack.config.js | 51 ++-------------- packages/scripts/utils/config.js | 13 ++-- packages/scripts/utils/index.js | 2 + .../scripts/utils/php-file-paths-plugin.js | 60 +++++++++++++++++++ tools/webpack/blocks.js | 37 +++++++++--- 5 files changed, 103 insertions(+), 60 deletions(-) create mode 100644 packages/scripts/utils/php-file-paths-plugin.js diff --git a/packages/scripts/config/webpack.config.js b/packages/scripts/config/webpack.config.js index 4c60e3859207de..91ef19fc27ed6b 100644 --- a/packages/scripts/config/webpack.config.js +++ b/packages/scripts/config/webpack.config.js @@ -13,7 +13,6 @@ const RtlCssPlugin = require( 'rtlcss-webpack-plugin' ); const TerserPlugin = require( 'terser-webpack-plugin' ); const { realpathSync } = require( 'fs' ); const { sync: glob } = require( 'fast-glob' ); -const { validate } = require( 'schema-utils' ); /** * WordPress dependencies @@ -32,11 +31,11 @@ const { hasPostCSSConfig, getWordPressSrcDirectory, getWebpackEntryPoints, - getPhpFilePaths, getAsBooleanFromENV, getBlockJsonModuleFields, getBlockJsonScriptFields, fromProjectRoot, + PhpFilePathsPlugin, } = require( '../utils' ); const isProduction = process.env.NODE_ENV === 'production'; @@ -50,49 +49,6 @@ const hasExperimentalModulesFlag = getAsBooleanFromENV( 'WP_EXPERIMENTAL_MODULES' ); -const phpFilePathsPluginSchema = { - type: 'object', - properties: { - props: { - type: 'array', - items: { - type: 'string', - }, - }, - }, -}; - -/** - * The plugin recomputes PHP file paths once on each compilation. It is necessary to avoid repeating processing - * when filtering every discovered PHP file in the source folder. This is the most performant way to ensure that - * changes in `block.json` files are picked up in watch mode. - */ -class PhpFilePathsPlugin { - /** - * PHP file paths from `render` and `variations` props found in `block.json` files. - * - * @type {string[]} - */ - static paths; - - constructor( options = {} ) { - validate( phpFilePathsPluginSchema, options, { - name: 'PHP File Paths Plugin', - baseDataPath: 'options', - } ); - - this.options = options; - } - - apply( compiler ) { - const pluginName = this.constructor.name; - - compiler.hooks.thisCompilation.tap( pluginName, () => { - this.constructor.paths = getPhpFilePaths( this.options.props ); - } ); - } -} - const cssLoaders = [ { loader: MiniCSSExtractPlugin.loader, @@ -345,7 +301,10 @@ const scriptConfig = { cleanStaleWebpackAssets: false, } ), - new PhpFilePathsPlugin( { props: [ 'render', 'variations' ] } ), + new PhpFilePathsPlugin( { + context: getWordPressSrcDirectory(), + props: [ 'render', 'variations' ], + } ), new CopyWebpackPlugin( { patterns: [ { diff --git a/packages/scripts/utils/config.js b/packages/scripts/utils/config.js index 7196c0376377d4..dfb44730438c4a 100644 --- a/packages/scripts/utils/config.js +++ b/packages/scripts/utils/config.js @@ -351,22 +351,23 @@ function getWebpackEntryPoints( buildType ) { /** * Returns the list of PHP file paths found in `block.json` files for the given props. * - * @param {string[]} props The props to search for in the `block.json` files. + * @param {string} context The path to search for `block.json` files. + * @param {string[]} props The props to search for in the `block.json` files. * @return {string[]} The list of PHP file paths. */ -function getPhpFilePaths( props ) { +function getPhpFilePaths( context, props ) { // Continue only if the source directory exists. - if ( ! hasProjectFile( getWordPressSrcDirectory() ) ) { + if ( ! hasProjectFile( context ) ) { return []; } // Checks whether any block metadata files can be detected in the defined source directory. const blockMetadataFiles = glob( '**/block.json', { absolute: true, - cwd: fromProjectRoot( getWordPressSrcDirectory() ), + cwd: fromProjectRoot( context ), } ); - const srcDirectory = fromProjectRoot( getWordPressSrcDirectory() + sep ); + const srcDirectory = fromProjectRoot( context + sep ); return blockMetadataFiles.flatMap( ( blockMetadataFile ) => { const blockJson = JSON.parse( readFileSync( blockMetadataFile ) ); @@ -396,7 +397,7 @@ function getPhpFilePaths( props ) { ) }" listed in "${ blockMetadataFile.replace( fromProjectRoot( sep ), '' - ) }". File is located outside of the "${ getWordPressSrcDirectory() }" directory.` + ) }". File is located outside of the "${ context }" directory.` ) ); continue; diff --git a/packages/scripts/utils/index.js b/packages/scripts/utils/index.js index dc4008b16197d6..cb7e592f83d554 100644 --- a/packages/scripts/utils/index.js +++ b/packages/scripts/utils/index.js @@ -29,6 +29,7 @@ const { getBlockJsonModuleFields, getBlockJsonScriptFields, } = require( './block-json' ); +const { PhpFilePathsPlugin } = require( './php-file-paths-plugin' ); module.exports = { fromProjectRoot, @@ -55,5 +56,6 @@ module.exports = { hasPostCSSConfig, hasPrettierConfig, hasProjectFile, + PhpFilePathsPlugin, spawnScript, }; diff --git a/packages/scripts/utils/php-file-paths-plugin.js b/packages/scripts/utils/php-file-paths-plugin.js new file mode 100644 index 00000000000000..6f95dae6505a80 --- /dev/null +++ b/packages/scripts/utils/php-file-paths-plugin.js @@ -0,0 +1,60 @@ +/** + * External dependencies + */ +const { validate } = require( 'schema-utils' ); + +/** + * Internal dependencies + */ +const { getPhpFilePaths } = require( './config' ); + +const phpFilePathsPluginSchema = { + type: 'object', + properties: { + context: { + type: 'string', + }, + props: { + type: 'array', + items: { + type: 'string', + }, + }, + }, +}; + +/** + * The plugin recomputes PHP file paths once on each compilation. It is necessary to avoid repeating processing + * when filtering every discovered PHP file in the source folder. This is the most performant way to ensure that + * changes in `block.json` files are picked up in watch mode. + */ +class PhpFilePathsPlugin { + /** + * PHP file paths from `render` and `variations` props found in `block.json` files. + * + * @type {string[]} + */ + static paths; + + constructor( options = {} ) { + validate( phpFilePathsPluginSchema, options, { + name: 'PHP File Paths Plugin', + baseDataPath: 'options', + } ); + + this.options = options; + } + + apply( compiler ) { + const pluginName = this.constructor.name; + + compiler.hooks.thisCompilation.tap( pluginName, () => { + this.constructor.paths = getPhpFilePaths( + this.options.context, + this.options.props + ); + } ); + } +} + +module.exports = { PhpFilePathsPlugin }; diff --git a/tools/webpack/blocks.js b/tools/webpack/blocks.js index 36329d39c1212b..fa0c6123dbcdba 100644 --- a/tools/webpack/blocks.js +++ b/tools/webpack/blocks.js @@ -4,11 +4,13 @@ const CopyWebpackPlugin = require( 'copy-webpack-plugin' ); const { join, sep } = require( 'path' ); const fastGlob = require( 'fast-glob' ); +const { realpathSync } = require( 'fs' ); /** * WordPress dependencies */ const DependencyExtractionWebpackPlugin = require( '@wordpress/dependency-extraction-webpack-plugin' ); +const { PhpFilePathsPlugin } = require( '@wordpress/scripts/utils' ); /** * Internal dependencies @@ -90,6 +92,10 @@ module.exports = [ plugins: [ ...plugins, new DependencyExtractionWebpackPlugin( { injectPolyfill: false } ), + new PhpFilePathsPlugin( { + context: './packages/block-library/src/', + props: [ 'render', 'variations' ], + } ), new CopyWebpackPlugin( { patterns: [].concat( [ @@ -127,17 +133,32 @@ module.exports = [ 'build/widgets/blocks/', } ).flatMap( ( [ from, to ] ) => [ { - from: `${ from }/**/index.php`, + from: `${ from }/**/*.php`, to( { absoluteFilename } ) { - const [ , dirname ] = absoluteFilename.match( - new RegExp( - `([\\w-]+)${ escapeRegExp( - sep - ) }index\\.php$` + const [ , dirname, basename ] = + absoluteFilename.match( + new RegExp( + `([\\w-]+)${ escapeRegExp( + sep + ) }([\\w-]+)\\.php$` + ) + ); + + if ( basename === 'index' ) { + return join( to, `${ dirname }.php` ); + } + return join( to, dirname, `${ basename }.php` ); + }, + filter: ( filepath ) => { + return ( + filepath.endsWith( sep + 'index.php' ) || + PhpFilePathsPlugin.paths.includes( + realpathSync( filepath ).replace( + /\\/g, + '/' + ) ) ); - - return join( to, `${ dirname }.php` ); }, transform: ( content ) => { const prefix = 'gutenberg_';