diff --git a/Gruntfile.js b/Gruntfile.js index f2b93adc4c..2919420701 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -124,7 +124,7 @@ module.exports = function(grunt) { 'webpack-assets': [ WORKING_DIR + 'wp-includes/assets/*', WORKING_DIR + 'wp-includes/css/dist/', - '!' + WORKING_DIR + 'wp-includes/assets/script-loader-packages.php' + '!' + WORKING_DIR + 'wp-includes/assets/script-loader-*.php' ], dynamic: { dot: true, diff --git a/package.json b/package.json index 7d2d76c1da..2e2ec63a9e 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "last 2 Opera versions" ], "devDependencies": { + "@pmmmwh/react-refresh-webpack-plugin": "0.5.5", "@wordpress/babel-preset-default": "6.8.0", "@wordpress/dependency-extraction-webpack-plugin": "3.4.1", "@wordpress/e2e-test-utils": "5.4.10", @@ -62,6 +63,7 @@ "matchdep": "~2.0.0", "prettier": "npm:wp-prettier@2.0.5", "qunit": "~2.18.1", + "react-refresh": "0.10.0", "sass": "^1.50.0", "sinon": "~13.0.1", "sinon-test": "~3.1.3", diff --git a/src/wp-includes/assets/script-loader-react-refresh-entry.php b/src/wp-includes/assets/script-loader-react-refresh-entry.php new file mode 100644 index 0000000000..f595680f32 --- /dev/null +++ b/src/wp-includes/assets/script-loader-react-refresh-entry.php @@ -0,0 +1 @@ + array('wp-react-refresh-runtime'), 'version' => '8151afc94a5ebc73b7a8229f0d7ee352'); \ No newline at end of file diff --git a/src/wp-includes/assets/script-loader-react-refresh-runtime.php b/src/wp-includes/assets/script-loader-react-refresh-runtime.php new file mode 100644 index 0000000000..80fcd1cd2f --- /dev/null +++ b/src/wp-includes/assets/script-loader-react-refresh-runtime.php @@ -0,0 +1 @@ + array(), 'version' => '4fb86f241c3b2d9d9e0411b507079823'); \ No newline at end of file diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 12a842a026..ad3ecee5d9 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -214,6 +214,45 @@ function wp_get_script_polyfill( $scripts, $tests ) { return $polyfill; } +/** + * Registers development scripts that integrate with `@wordpress/scripts`. + * + * @see https://github.com/WordPress/gutenberg/tree/trunk/packages/scripts#start + * + * @since 6.0.0 + * + * @param WP_Scripts $scripts WP_Scripts object. + */ +function wp_register_development_scripts( $scripts ) { + if ( + ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG + || empty( $scripts->registered['react'] ) + ) { + return; + } + + $development_scripts = array( + 'react-refresh-entry', + 'react-refresh-runtime', + ); + + foreach ( $development_scripts as $script_name ) { + $assets = include ABSPATH . WPINC . '/assets/script-loader-' . $script_name . '.php'; + if ( ! is_array( $assets ) ) { + return; + } + $scripts->add( + 'wp-' . $script_name, + '/wp-includes/js/dist/development/' . $script_name . '.js', + $assets['dependencies'], + $assets['version'] + ); + } + + // See https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/TROUBLESHOOTING.md#externalising-react. + $scripts->registered['react']->deps[] = 'wp-react-refresh-entry'; +} + /** * Registers all the WordPress packages scripts that are in the standardized * `js/dist/` location. @@ -560,6 +599,7 @@ function wp_tinymce_inline_scripts() { */ function wp_default_packages( $scripts ) { wp_default_packages_vendor( $scripts ); + wp_register_development_scripts( $scripts ); wp_register_tinymce_scripts( $scripts ); wp_default_packages_scripts( $scripts ); diff --git a/tools/webpack/development.js b/tools/webpack/development.js new file mode 100644 index 0000000000..1b871ee665 --- /dev/null +++ b/tools/webpack/development.js @@ -0,0 +1,61 @@ +/** + * External dependencies + */ +const { join } = require( 'path' ); + +/** + * WordPress dependencies + */ +const DependencyExtractionWebpackPlugin = require( '@wordpress/dependency-extraction-webpack-plugin' ); + +const baseDir = join( __dirname, '../../' ); + +module.exports = function( env = { environment: 'production', buildTarget: false } ) { + const mode = env.environment; + const suffix = mode === 'production' ? '.min' : ''; + let buildTarget = env.buildTarget ? env.buildTarget : ( mode === 'production' ? 'build' : 'src' ); + buildTarget = buildTarget + '/wp-includes'; + + const sharedConfig = { + mode: 'development', + target: 'browserslist', + output: { + filename: `[name]${ suffix }.js`, + path: join( baseDir, `${ buildTarget }/js/dist/development` ), + }, + }; + + // See https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/TROUBLESHOOTING.md#externalising-react. + return [ + { + ...sharedConfig, + name: 'react-refresh-entry', + entry: { + 'react-refresh-entry': + '@pmmmwh/react-refresh-webpack-plugin/client/ReactRefreshEntry.js', + }, + plugins: [ new DependencyExtractionWebpackPlugin( { + outputFilename: '../../../assets/script-loader-[name].php', + } ) ], + }, + { + ...sharedConfig, + name: 'react-refresh-runtime', + entry: { + 'react-refresh-runtime': { + import: 'react-refresh/runtime.js', + library: { + name: 'ReactRefreshRuntime', + type: 'window', + }, + }, + }, + plugins: [ + new DependencyExtractionWebpackPlugin( { + useDefaults: false, + outputFilename: '../../../assets/script-loader-[name].php' + } ), + ], + }, + ]; +}; diff --git a/webpack.config.js b/webpack.config.js index 5b7b7b632d..5e7c88a2cf 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,4 +1,5 @@ const blocksConfig = require( './tools/webpack/blocks' ); +const developmentConfig = require( './tools/webpack/development' ); const mediaConfig = require( './tools/webpack/media' ); const packagesConfig = require( './tools/webpack/packages' ); @@ -13,6 +14,7 @@ module.exports = function( env = { environment: "production", watch: false, buil const config = [ blocksConfig( env ), + ...developmentConfig( env ), mediaConfig( env ), packagesConfig( env ), ];