22
33import path from 'path' ;
44import { fileURLToPath } from 'url' ;
5+ import { readFile , writeFile , mkdir } from 'fs/promises' ;
56import esbuild from 'esbuild' ;
67
78const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
@@ -14,27 +15,75 @@ const VENDOR_SCRIPTS = [
1415 name : 'react' ,
1516 global : 'React' ,
1617 handle : 'react' ,
18+ dependencies : [ 'wp-polyfill' ] ,
1719 } ,
1820 {
1921 name : 'react-dom' ,
2022 global : 'ReactDOM' ,
2123 handle : 'react-dom' ,
24+ dependencies : [ 'react' ] ,
2225 } ,
2326 {
2427 name : 'react/jsx-runtime' ,
2528 global : 'ReactJSXRuntime' ,
2629 handle : 'react-jsx-runtime' ,
30+ dependencies : [ 'react' ] ,
2731 } ,
2832] ;
2933
34+ /**
35+ * Read the version from a package's package.json in node_modules.
36+ *
37+ * @param {string } packageName npm package name (e.g., 'react', 'react-dom').
38+ * @return {Promise<string> } The package version string.
39+ */
40+ async function getPackageVersion ( packageName ) {
41+ const packageJsonPath = path . join (
42+ ROOT_DIR ,
43+ 'node_modules' ,
44+ packageName ,
45+ 'package.json'
46+ ) ;
47+ const packageJson = JSON . parse (
48+ await readFile ( packageJsonPath , 'utf-8' )
49+ ) ;
50+ return packageJson . version ;
51+ }
52+
53+ /**
54+ * Generate a .asset.php file for a vendor script.
55+ *
56+ * @param {Object } config Vendor script configuration.
57+ * @param {string } config.handle WordPress script handle.
58+ * @param {string } config.name Package name (e.g., 'react', 'react/jsx-runtime').
59+ * @param {string[] } config.dependencies WordPress script dependencies.
60+ */
61+ async function generateAssetFile ( config ) {
62+ const { handle, name, dependencies } = config ;
63+
64+ // The npm package name is the first segment of the name (e.g., 'react/jsx-runtime' -> 'react').
65+ const packageName = name . split ( '/' ) [ 0 ] ;
66+ const version = await getPackageVersion ( packageName ) ;
67+
68+ const dependenciesString = dependencies
69+ . map ( ( dep ) => `'${ dep } '` )
70+ . join ( ', ' ) ;
71+ const assetContent = `<?php return array('dependencies' => array(${ dependenciesString } ), 'version' => '${ version } ');` ;
72+
73+ const assetFilePath = path . join ( VENDORS_DIR , `${ handle } .min.asset.php` ) ;
74+ await mkdir ( path . dirname ( assetFilePath ) , { recursive : true } ) ;
75+ await writeFile ( assetFilePath , assetContent ) ;
76+ }
77+
3078/**
3179 * Bundle a vendor script from node_modules into an IIFE script.
3280 * This is used to build packages like React that don't ship UMD builds.
3381 *
34- * @param {Object } config Vendor script configuration.
35- * @param {string } config.name Package name (e.g., 'react', 'react-dom', 'react/jsx-runtime').
36- * @param {string } config.global Global variable name (e.g., 'React', 'ReactDOM').
37- * @param {string } config.handle WordPress script handle (e.g., 'react', 'react-dom').
82+ * @param {Object } config Vendor script configuration.
83+ * @param {string } config.name Package name (e.g., 'react', 'react-dom', 'react/jsx-runtime').
84+ * @param {string } config.global Global variable name (e.g., 'React', 'ReactDOM').
85+ * @param {string } config.handle WordPress script handle (e.g., 'react', 'react-dom').
86+ * @param {string[] } config.dependencies WordPress script dependencies.
3887 * @return {Promise<void> } Promise that resolves when all builds are finished.
3988 */
4089async function bundleVendorScript ( config ) {
@@ -64,23 +113,29 @@ async function bundleVendorScript( config ) {
64113 } ,
65114 } ;
66115
67- // Build both minified and non-minified versions
68- await Promise . all (
69- [ false , true ] . map ( ( production ) => {
70- const outputFile = handle + ( production ? '.min.js' : '.js' ) ;
71- return esbuild . build ( {
72- entryPoints : [ name ] ,
73- outfile : path . join ( VENDORS_DIR , outputFile ) ,
74- bundle : true ,
75- format : 'iife' ,
76- globalName : global ,
77- minify : production ,
78- target : 'esnext' , // Don't transpile, just bundle.
79- platform : 'browser' ,
80- plugins : [ reactExternalPlugin ] ,
81- } ) ;
82- } )
83- ) ;
116+ const esbuildOptions = {
117+ entryPoints : [ name ] ,
118+ bundle : true ,
119+ format : 'iife' ,
120+ globalName : global ,
121+ target : 'esnext' ,
122+ platform : 'browser' ,
123+ plugins : [ reactExternalPlugin ] ,
124+ } ;
125+
126+ await Promise . all ( [
127+ esbuild . build ( {
128+ ...esbuildOptions ,
129+ outfile : path . join ( VENDORS_DIR , handle + '.js' ) ,
130+ minify : false ,
131+ } ) ,
132+ esbuild . build ( {
133+ ...esbuildOptions ,
134+ outfile : path . join ( VENDORS_DIR , handle + '.min.js' ) ,
135+ minify : true ,
136+ } ) ,
137+ generateAssetFile ( config ) ,
138+ ] ) ;
84139}
85140
86141/**
0 commit comments