diff --git a/packages/dependency-extraction-webpack-plugin/lib/index.js b/packages/dependency-extraction-webpack-plugin/lib/index.js index cf780d7370dcfc..8bc7cb29312161 100644 --- a/packages/dependency-extraction-webpack-plugin/lib/index.js +++ b/packages/dependency-extraction-webpack-plugin/lib/index.js @@ -387,6 +387,16 @@ class DependencyExtractionWebpackPlugin { assetData.type = 'module'; } + if ( compilation.options?.optimization?.runtimeChunk !== false ) { + // Sets the script handle for the shared runtime file so WordPress registers it only once when using the asset file. + assetData.handle = + compilation.name + + '-' + + chunkJSFile + .replace( /\\/g, '/' ) + .replace( jsExtensionRegExp, '' ); + } + if ( combineAssets ) { combinedAssetsData[ chunkJSFile ] = assetData; continue; diff --git a/packages/dependency-extraction-webpack-plugin/test/__snapshots__/build.js.snap b/packages/dependency-extraction-webpack-plugin/test/__snapshots__/build.js.snap index 8ea40b00d7c2d1..bafae8eb914867 100644 --- a/packages/dependency-extraction-webpack-plugin/test/__snapshots__/build.js.snap +++ b/packages/dependency-extraction-webpack-plugin/test/__snapshots__/build.js.snap @@ -265,17 +265,17 @@ exports[`DependencyExtractionWebpackPlugin modules Webpack \`polyfill-magic-comm exports[`DependencyExtractionWebpackPlugin modules Webpack \`polyfill-magic-comment-minified\` should produce expected output: External modules should match snapshot 1`] = `[]`; exports[`DependencyExtractionWebpackPlugin modules Webpack \`runtime-chunk-single\` should produce expected output: Asset file 'a.asset.php' should match snapshot 1`] = ` -" array('@wordpress/blob'), 'version' => 'ee5ac21a1f0003d732e6', 'type' => 'module'); +" array('@wordpress/blob'), 'version' => 'ee5ac21a1f0003d732e6', 'type' => 'module', 'handle' => 'runtime-chunk-single-modules-a'); " `; exports[`DependencyExtractionWebpackPlugin modules Webpack \`runtime-chunk-single\` should produce expected output: Asset file 'b.asset.php' should match snapshot 1`] = ` -" array('@wordpress/blob', 'lodash'), 'version' => '5b112b32c6db548c2997', 'type' => 'module'); +" array('@wordpress/blob', 'lodash'), 'version' => '5b112b32c6db548c2997', 'type' => 'module', 'handle' => 'runtime-chunk-single-modules-b'); " `; exports[`DependencyExtractionWebpackPlugin modules Webpack \`runtime-chunk-single\` should produce expected output: Asset file 'runtime.asset.php' should match snapshot 1`] = ` -" array(), 'version' => 'b1ca4106075e0bd94f9c', 'type' => 'module'); +" array(), 'version' => 'b1ca4106075e0bd94f9c', 'type' => 'module', 'handle' => 'runtime-chunk-single-modules-runtime'); " `; @@ -681,17 +681,17 @@ exports[`DependencyExtractionWebpackPlugin scripts Webpack \`polyfill-magic-comm exports[`DependencyExtractionWebpackPlugin scripts Webpack \`polyfill-magic-comment-minified\` should produce expected output: External modules should match snapshot 1`] = `[]`; exports[`DependencyExtractionWebpackPlugin scripts Webpack \`runtime-chunk-single\` should produce expected output: Asset file 'a.asset.php' should match snapshot 1`] = ` -" array('wp-blob'), 'version' => 'd091f1cbbf7603d6e12c'); +" array('wp-blob'), 'version' => 'd091f1cbbf7603d6e12c', 'handle' => 'runtime-chunk-single-scripts-a'); " `; exports[`DependencyExtractionWebpackPlugin scripts Webpack \`runtime-chunk-single\` should produce expected output: Asset file 'b.asset.php' should match snapshot 1`] = ` -" array('lodash', 'wp-blob'), 'version' => '845bc6d4ffbdb9419ebd'); +" array('lodash', 'wp-blob'), 'version' => '845bc6d4ffbdb9419ebd', 'handle' => 'runtime-chunk-single-scripts-b'); " `; exports[`DependencyExtractionWebpackPlugin scripts Webpack \`runtime-chunk-single\` should produce expected output: Asset file 'runtime.asset.php' should match snapshot 1`] = ` -" array(), 'version' => '717eb779e609d175a7dd'); +" array(), 'version' => '717eb779e609d175a7dd', 'handle' => 'runtime-chunk-single-scripts-runtime'); " `; diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 55143ae792ae5b..ceaa25c4ff9a09 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Bug Fix + +- Make React Fast Refresh in the `start` command work with multiple blocks ([64924](https://github.com/WordPress/gutenberg/pull/64924)). + ## 30.6.0 (2024-11-27) ## 30.5.1 (2024-11-18) diff --git a/packages/scripts/config/webpack.config.js b/packages/scripts/config/webpack.config.js index f9ef7dc5b7acca..2c3d423fcbd1e8 100644 --- a/packages/scripts/config/webpack.config.js +++ b/packages/scripts/config/webpack.config.js @@ -7,7 +7,7 @@ const CopyWebpackPlugin = require( 'copy-webpack-plugin' ); const webpack = require( 'webpack' ); const browserslist = require( 'browserslist' ); const MiniCSSExtractPlugin = require( 'mini-css-extract-plugin' ); -const { basename, dirname, resolve } = require( 'path' ); +const { basename, dirname, relative, resolve, sep } = require( 'path' ); const ReactRefreshWebpackPlugin = require( '@pmmmwh/react-refresh-webpack-plugin' ); const RtlCssPlugin = require( 'rtlcss-webpack-plugin' ); const TerserPlugin = require( 'terser-webpack-plugin' ); @@ -115,6 +115,7 @@ const baseConfig = { optimization: { // Only concatenate modules in production, when not analyzing bundles. concatenateModules: isProduction && ! process.env.WP_BUNDLE_ANALYZER, + runtimeChunk: hasReactFastRefresh && 'single', splitChunks: { cacheGroups: { style: { @@ -340,6 +341,32 @@ const scriptConfig = { } } ); + if ( hasReactFastRefresh ) { + // Prepends the file reference to the shared runtime chunk to every script type defined for the block. + const runtimePath = relative( + dirname( absoluteFrom ), + fromProjectRoot( + getWordPressSrcDirectory() + + sep + + 'runtime.js' + ) + ); + const fields = + getBlockJsonScriptFields( blockJson ); + for ( const [ fieldName ] of Object.entries( + fields + ) ) { + blockJson[ fieldName ] = [ + `file:${ runtimePath }`, + ...( Array.isArray( + blockJson[ fieldName ] + ) + ? blockJson[ fieldName ] + : [ blockJson[ fieldName ] ] ), + ]; + } + } + return JSON.stringify( blockJson, null, 2 ); }