Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 89 additions & 23 deletions packages/scripts/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const MiniCSSExtractPlugin = require( 'mini-css-extract-plugin' );
const { basename, dirname, resolve } = require( 'path' );
const ReactRefreshWebpackPlugin = require( '@pmmmwh/react-refresh-webpack-plugin' );
const TerserPlugin = require( 'terser-webpack-plugin' );
const { realpathSync } = require( 'fs' );
const { realpathSync } = require( 'node:fs' );
const path = require( 'node:path' );

/**
* WordPress dependencies
Expand All @@ -34,6 +35,7 @@ const {
getBlockJsonModuleFields,
getBlockJsonScriptFields,
} = require( '../utils' );
const { getBlockJsonStyleFields } = require( '../utils/block-json' );

const isProduction = process.env.NODE_ENV === 'production';
const mode = isProduction ? 'production' : 'development';
Expand Down Expand Up @@ -122,7 +124,6 @@ const baseConfig = {
target,
output: {
filename: '[name].js',
path: resolve( process.cwd(), 'build' ),
},
resolve: {
alias: {
Expand Down Expand Up @@ -281,6 +282,11 @@ if ( baseConfig.devtool ) {
const scriptConfig = {
...baseConfig,

output: {
...baseConfig.output,
path: resolve( process.cwd(), 'build/script' ),
},

entry: getWebpackEntryPoints( 'script' ),

devServer: isProduction
Expand Down Expand Up @@ -322,37 +328,95 @@ const scriptConfig = {
patterns: [
{
from: '**/block.json',
to: '..',
context: getWordPressSrcDirectory(),
noErrorOnMissing: true,
transform( content, absoluteFrom ) {
const convertExtension = ( path ) => {
return path.replace( /\.m?(j|t)sx?$/, '.js' );
const convertExtension = ( assetPath ) => {
return assetPath.replace( /\.m?(j|t)sx?$/, '.js' );
};

/**
* Adjust output path for compiled block assets
*
* If we're outputting to `build/script`,
* `build/module`, and `build/style` then we'll need
* to adjust the path. This is only true when doing
* experimental module builds.
*
* @param {string} pathPart Path part to prepend to the view path.
* @param {string} assetPath Path that should be adjusted.
*
* @return {string} Adjusted path.
*/
const adjustBlockJsonFilePath = (
pathPart,
assetPath
) => {
if ( ! hasExperimentalModulesFlag ) {
return assetPath;
}

const filePrefix = 'file:./';

if ( ! assetPath.startsWith( filePrefix ) ) {
return assetPath;
}

const parts = assetPath
.slice( filePrefix.length )
.split( path.sep );

return filePrefix + path.join( pathPart, ...parts );
};

if ( basename( absoluteFrom ) === 'block.json' ) {
const blockJson = JSON.parse( content.toString() );

[
getBlockJsonScriptFields( blockJson ),
getBlockJsonModuleFields( blockJson ),
].forEach( ( fields ) => {
if ( fields ) {
for ( const [
key,
value,
] of Object.entries( fields ) ) {
if ( Array.isArray( value ) ) {
blockJson[ key ] =
value.map( convertExtension );
} else if (
typeof value === 'string'
) {
blockJson[ key ] =
convertExtension( value );
[
'module',
getBlockJsonModuleFields( blockJson ),
],
[
'script',
getBlockJsonScriptFields( blockJson ),
],
[
'style',
getBlockJsonStyleFields( blockJson ),
],
].forEach(
( [ multiCompilerOutputPath, fields ] ) => {
if ( fields ) {
for ( const [
key,
value,
] of Object.entries( fields ) ) {
if ( Array.isArray( value ) ) {
blockJson[ key ] = value
.map( convertExtension )
.map( ( val ) =>
adjustBlockJsonFilePath(
multiCompilerOutputPath,
val
)
);
} else if (
typeof value === 'string'
) {
blockJson[ key ] =
adjustBlockJsonFilePath(
multiCompilerOutputPath,
convertExtension(
value
)
);
}
}
}
}
} );
);

return JSON.stringify( blockJson, null, 2 );
}
Expand All @@ -362,6 +426,7 @@ const scriptConfig = {
},
{
from: '**/*.php',
to: '..',
context: getWordPressSrcDirectory(),
noErrorOnMissing: true,
filter: ( filepath ) => {
Expand All @@ -379,7 +444,7 @@ const scriptConfig = {
// bundle content as a convenient interactive zoomable treemap.
process.env.WP_BUNDLE_ANALYZER && new BundleAnalyzerPlugin(),
// MiniCSSExtractPlugin to extract the CSS thats gets imported into JavaScript.
new MiniCSSExtractPlugin( { filename: '[name].css' } ),
new MiniCSSExtractPlugin( { filename: '../style/[name].css' } ),
// WP_NO_EXTERNALS global variable controls whether scripts' assets get
// generated, and the default externals set.
! process.env.WP_NO_EXTERNALS &&
Expand All @@ -401,6 +466,7 @@ if ( hasExperimentalModulesFlag ) {

output: {
...baseConfig.output,
path: resolve( process.cwd(), 'build/module' ),
module: true,
chunkFormat: 'module',
environment: {
Expand All @@ -422,7 +488,7 @@ if ( hasExperimentalModulesFlag ) {
// bundle content as a convenient interactive zoomable treemap.
process.env.WP_BUNDLE_ANALYZER && new BundleAnalyzerPlugin(),
// MiniCSSExtractPlugin to extract the CSS thats gets imported into JavaScript.
new MiniCSSExtractPlugin( { filename: '[name].css' } ),
new MiniCSSExtractPlugin( { filename: '../style/[name].css' } ),
// React Fast Refresh.
hasReactFastRefresh && new ReactRefreshWebpackPlugin(),
// WP_NO_EXTERNALS global variable controls whether scripts' assets get
Expand Down
49 changes: 20 additions & 29 deletions packages/scripts/utils/block-json.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,32 @@
const moduleFields = new Set( [ 'viewModule' ] );
const scriptFields = new Set( [ 'viewScript', 'script', 'editorScript' ] );
const styleFields = new Set( [ 'style', 'editorStyle' ] );

/**
* @param {Object} blockJson
* @return {null|Record<string, unknown>} Fields
*/
function getBlockJsonModuleFields( blockJson ) {
let result = null;
for ( const field of moduleFields ) {
if ( Object.hasOwn( blockJson, field ) ) {
if ( ! result ) {
result = {};
function makeBlockJsonGetter( properties ) {
/**
* @param {Object} blockJson
* @return {null|Record<string, unknown>} Fields
*/
return ( blockJson ) => {
let result = null;
for ( const property of properties ) {
if ( Object.hasOwn( blockJson, property ) ) {
if ( ! result ) {
result = {};
}
result[ property ] = blockJson[ property ];
}
result[ field ] = blockJson[ field ];
}
}
return result;
return result;
};
}

/**
* @param {Object} blockJson
* @return {null|Record<string, unknown>} Fields
*/
function getBlockJsonScriptFields( blockJson ) {
let result = null;
for ( const field of scriptFields ) {
if ( Object.hasOwn( blockJson, field ) ) {
if ( ! result ) {
result = {};
}
result[ field ] = blockJson[ field ];
}
}
return result;
}
const getBlockJsonModuleFields = makeBlockJsonGetter( moduleFields );
const getBlockJsonScriptFields = makeBlockJsonGetter( scriptFields );
const getBlockJsonStyleFields = makeBlockJsonGetter( styleFields );

module.exports = {
getBlockJsonModuleFields,
getBlockJsonScriptFields,
getBlockJsonStyleFields,
};