diff --git a/tools/webpack/blocks.js b/tools/webpack/blocks.js index 36329d39c1212..56067e96d155b 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 { getRenderPropPaths } = require( '@wordpress/scripts/utils' ); /** * Internal dependencies @@ -77,6 +79,28 @@ const createEntrypoints = () => { }, {} ); }; +/** + * The plugin recomputes the render 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 RenderPathsPlugin { + /** + * Paths with the `render` props included in `block.json` files. + * + * @type {string[]} + */ + static renderPaths; + + apply( compiler ) { + const pluginName = this.constructor.name; + + compiler.hooks.thisCompilation.tap( pluginName, () => { + this.constructor.renderPaths = getRenderPropPaths(); + } ); + } +} + module.exports = [ { ...baseConfig, @@ -90,6 +114,7 @@ module.exports = [ plugins: [ ...plugins, new DependencyExtractionWebpackPlugin( { injectPolyfill: false } ), + new RenderPathsPlugin(), new CopyWebpackPlugin( { patterns: [].concat( [ @@ -127,17 +152,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' ) || + RenderPathsPlugin.renderPaths.includes( + realpathSync( filepath ).replace( + /\\/g, + '/' + ) ) ); - - return join( to, `${ dirname }.php` ); }, transform: ( content ) => { const prefix = 'gutenberg_';