Skip to content
Merged
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
150 changes: 106 additions & 44 deletions bin/packages/build-v2.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* External dependencies
*/
import { readFile, writeFile } from 'fs/promises';
import { readFile, writeFile, copyFile, mkdir } from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
import { parseArgs } from 'node:util';
Expand Down Expand Up @@ -35,6 +35,19 @@ const TEST_FILE_PATTERNS = [
/\.(spec|test)\.(js|ts|tsx)$/,
];

// Define global variables for feature flagging, matching webpack's DefinePlugin behavior
const define = {
'globalThis.IS_GUTENBERG_PLUGIN': JSON.stringify(
Boolean( process.env.npm_package_config_IS_GUTENBERG_PLUGIN )
),
'globalThis.IS_WORDPRESS_CORE': JSON.stringify(
Boolean( process.env.npm_package_config_IS_WORDPRESS_CORE )
),
'globalThis.SCRIPT_DEBUG': JSON.stringify(
process.env.NODE_ENV === 'development'
),
};

/**
* Normalize path separators for cross-platform compatibility.
*
Expand Down Expand Up @@ -113,10 +126,14 @@ function momentTimezoneAliasPlugin() {
* WordPress externals and asset plugin.
* Inspired by wp-build's wordpressExternalsAndAssetPlugin.
*
* @param {string} assetName Optional. The name of the asset file to generate (without .asset.php extension). Defaults to 'index.min'.
* @param {string} assetName Optional. The name of the asset file to generate (without .asset.php extension). Defaults to 'index.min'.
* @param {string} buildFormat Optional. The build format: 'iife' for scripts or 'esm' for script modules. Defaults to 'iife'.
* @return {Object} esbuild plugin.
*/
function wordpressExternalsPlugin( assetName = 'index.min' ) {
function wordpressExternalsPlugin(
assetName = 'index.min',
buildFormat = 'iife'
) {
return {
name: 'wordpress-externals',
setup( build ) {
Expand Down Expand Up @@ -257,11 +274,17 @@ function wordpressExternalsPlugin( assetName = 'index.min' ) {
return undefined;
}

// Check if this is a script module
const isScriptModule = isScriptModuleImport(
// Check if this is a script module or a script dependency.
let isScriptModule = isScriptModuleImport(
packageJson,
subpath
);
let isScript = packageJson.wpScript;
if ( isScriptModule && isScript ) {
// If the package is both a script and a script module, we should rely on the format being built
isScript = buildFormat === 'iife';
isScriptModule = buildFormat === 'esm';
}

// Determine import kind: dynamic or static
const kind =
Expand All @@ -283,7 +306,7 @@ function wordpressExternalsPlugin( assetName = 'index.min' ) {
}

// If it has wpScript, convert to global variable
if ( packageJson.wpScript ) {
if ( isScript ) {
// Track regular script dependency using wp- handle format
dependencies.add( wpHandle );

Expand Down Expand Up @@ -424,16 +447,21 @@ async function bundlePackage( packageName ) {
...baseConfig,
outfile: path.join( outputDir, 'index.min.js' ),
minify: true,
define,
plugins: [
momentTimezoneAliasPlugin(),
wordpressExternalsPlugin( 'index.min' ),
wordpressExternalsPlugin( 'index.min', 'iife' ),
],
} ),
esbuild.build( {
...baseConfig,
outfile: path.join( outputDir, 'index.js' ),
minify: false,
plugins: [ momentTimezoneAliasPlugin() ],
define,
plugins: [
momentTimezoneAliasPlugin(),
wordpressExternalsPlugin( 'index.min', 'iife' ),
],
} )
);
}
Expand Down Expand Up @@ -476,8 +504,9 @@ async function bundlePackage( packageName ) {
target,
platform: 'browser',
minify: true,
define,
plugins: [
wordpressExternalsPlugin( `${ fileName }.min` ),
wordpressExternalsPlugin( `${ fileName }.min`, 'esm' ),
],
} )
);
Expand All @@ -494,76 +523,109 @@ async function bundlePackage( packageName ) {
}

/**
* Transpile source files for a package (both CJS and ESM).
* Transpile a single package's source files and copy JSON files.
*
* @param {string} packageDir Package directory path.
* @param {string[]} srcFiles Array of source file paths.
* @param {Object} packageJson Package.json contents.
* @param {string} packageName Package name.
* @return {Promise<number>} Build time in milliseconds.
*/
async function transpilePackage( packageDir, srcFiles, packageJson ) {
async function transpilePackage( packageName ) {
const startTime = Date.now();
const packageDir = path.join( PACKAGES_DIR, packageName );
const packageJsonPath = path.join( packageDir, 'package.json' );
const packageJson = JSON.parse( await readFile( packageJsonPath, 'utf8' ) );

// Find source files to transpile
const srcFiles = await glob(
normalizePath(
path.join( packageDir, `src/**/*.${ SOURCE_EXTENSIONS }` )
),
{
ignore: IGNORE_PATTERNS,
}
);

// Find JSON files to copy
const jsonFiles = await glob(
normalizePath( path.join( packageDir, 'src/**/*.json' ) ),
{
ignore: IGNORE_PATTERNS,
}
);

const buildDir = path.join( packageDir, 'build' );
const buildModuleDir = path.join( packageDir, 'build-module' );
const srcDir = path.join( packageDir, 'src' );
const target = browserslistToEsbuild();

const builds = [];

// Only build CJS if package has 'main' property
// Build CJS and copy JSON files to build directory
if ( packageJson.main ) {
builds.push(
esbuild.build( {
entryPoints: srcFiles,
outdir: buildDir,
outbase: path.join( packageDir, 'src' ),
outbase: srcDir,
bundle: false,
platform: 'node',
format: 'cjs',
sourcemap: true,
target,
jsx: 'automatic',
jsxImportSource: 'react',
loader: {
'.js': 'jsx',
},
} )
);

// Copy JSON files to build directory
for ( const jsonFile of jsonFiles ) {
const relativePath = path.relative( srcDir, jsonFile );
const destPath = path.join( buildDir, relativePath );
const destDir = path.dirname( destPath );
builds.push(
mkdir( destDir, { recursive: true } ).then( () =>
copyFile( jsonFile, destPath )
)
);
}
}

// Only build ESM if package has 'module' property
// Build ESM and copy JSON files to build-module directory
if ( packageJson.module ) {
builds.push(
esbuild.build( {
entryPoints: srcFiles,
outdir: buildModuleDir,
outbase: path.join( packageDir, 'src' ),
outbase: srcDir,
bundle: false,
platform: 'neutral',
format: 'esm',
sourcemap: true,
target,
jsx: 'automatic',
jsxImportSource: 'react',
loader: {
'.js': 'jsx',
},
} )
);
}

await Promise.all( builds );
}

/**
* Transpile a single package's source files.
*
* @param {string} packageName Package name.
* @return {Promise<number>} Build time in milliseconds.
*/
async function transpilePackageFiles( packageName ) {
const startTime = Date.now();
const packageDir = path.join( PACKAGES_DIR, packageName );
const packageJsonPath = path.join( packageDir, 'package.json' );
const packageJson = JSON.parse( await readFile( packageJsonPath, 'utf8' ) );

const srcFiles = await glob(
normalizePath(
path.join( packageDir, `src/**/*.${ SOURCE_EXTENSIONS }` )
),
{
ignore: IGNORE_PATTERNS,
// Copy JSON files to build-module directory
for ( const jsonFile of jsonFiles ) {
const relativePath = path.relative( srcDir, jsonFile );
const destPath = path.join( buildModuleDir, relativePath );
const destDir = path.dirname( destPath );
builds.push(
mkdir( destDir, { recursive: true } ).then( () =>
copyFile( jsonFile, destPath )
)
);
}
);
}

await transpilePackage( packageDir, srcFiles, packageJson );
await Promise.all( builds );

return Date.now() - startTime;
}
Expand Down Expand Up @@ -631,7 +693,7 @@ async function buildAll() {
console.log( '📝 Phase 1: Transpiling packages...\n' );
await Promise.all(
V2_PACKAGES.map( async ( packageName ) => {
const buildTime = await transpilePackageFiles( packageName );
const buildTime = await transpilePackage( packageName );
console.log( `✔ Transpiled ${ packageName } (${ buildTime }ms)` );
} )
);
Expand Down Expand Up @@ -674,7 +736,7 @@ async function watchMode() {
try {
const startTime = Date.now();

await transpilePackageFiles( packageName );
await transpilePackage( packageName );
await bundlePackage( packageName );

const buildTime = Date.now() - startTime;
Expand Down
12 changes: 12 additions & 0 deletions bin/packages/v2-packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
*/
const V2_PACKAGES = [
'a11y',
'annotations',
'api-fetch',
'autop',
'blob',
'block-serialization-default-parser',
'blocks',
'compose',
'data',
'data-controls',
'date',
'deprecated',
'dom',
Expand All @@ -25,18 +30,25 @@ const V2_PACKAGES = [
'is-shallow-equal',
'jest-console',
'jest-puppeteer-axe',
'keyboard-shortcuts',
'keycodes',
'media-utils',
'notices',
'preferences-persistence',
'priority-queue',
'private-apis',
'react-i18n',
'redux-routine',
'report-flaky-tests',
'rich-text',
'router',
'shortcode',
'style-engine',
'sync',
'token-list',
'undo-manager',
'url',
'viewport',
'warning',
'wordcount',
];
Expand Down
Loading
Loading