@wordpress/build 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.cjs CHANGED
@@ -4,5 +4,11 @@ module.exports = {
4
4
  rules: {
5
5
  // Console should be allowed in a build tool
6
6
  'no-console': 'off',
7
+ /*
8
+ * These rules are designed for source files processed by esbuild, not for the build script itself,
9
+ * which runs directly in Node.js.
10
+ */
11
+ '@wordpress/no-wp-process-env': 'off',
12
+ '@wordpress/wp-global-usage': 'off',
7
13
  },
8
14
  };
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.10.0 (2026-03-18)
6
+
7
+ ### Breaking Changes
8
+
9
+ - `@wordpress/boot`, `@wordpress/route`, `@wordpress/theme`, and `@wordpress/private-apis` are no longer bundled. They are now expected to be provided by WordPress Core (7.0+) or the Gutenberg plugin.
10
+
11
+ ### Enhancements
12
+
13
+ - Avoid unexpected results when typecasting `IS_GUTENBERG_PLUGIN` and `IS_WORDPRESS_CORE` values to Booleans ([#75844](https://github.com/WordPress/gutenberg/pull/75844)).
14
+ - Skip PHP transforms during builds when building for WordPress Core ([#75844](https://github.com/WordPress/gutenberg/pull/75844)).
15
+
5
16
  ## 0.9.0 (2026-03-04)
6
17
 
7
18
  ## 0.8.0 (2026-02-18)
package/lib/build.mjs CHANGED
@@ -113,12 +113,32 @@ const HANDLE_PREFIX = WP_PLUGIN_CONFIG.handlePrefix || PACKAGE_NAMESPACE;
113
113
  const EXTERNAL_NAMESPACES = WP_PLUGIN_CONFIG.externalNamespaces || {};
114
114
  const PAGES = WP_PLUGIN_CONFIG.pages || [];
115
115
 
116
+ /**
117
+ * Interprets a configuration value as a boolean, where `"true"` and `"1"`
118
+ * are considered true while all other values are false.
119
+ *
120
+ * @param {string|undefined} value The configuration value to interpret.
121
+ * @return {boolean|undefined} Boolean interpretation of the given configuration value, or undefined if not set.
122
+ */
123
+ const boolConfigVal = ( value ) => {
124
+ if ( value === undefined ) {
125
+ return undefined;
126
+ }
127
+ return [ 'true', '1' ].includes( value.toLowerCase() );
128
+ };
129
+
116
130
  const baseDefine = {
117
131
  'globalThis.IS_GUTENBERG_PLUGIN': JSON.stringify(
118
- Boolean( process.env.npm_package_config_IS_GUTENBERG_PLUGIN )
132
+ boolConfigVal( process.env.IS_GUTENBERG_PLUGIN ) ??
133
+ boolConfigVal(
134
+ process.env.npm_package_config_IS_GUTENBERG_PLUGIN
135
+ ) ??
136
+ false
119
137
  ),
120
138
  'globalThis.IS_WORDPRESS_CORE': JSON.stringify(
121
- Boolean( process.env.npm_package_config_IS_WORDPRESS_CORE )
139
+ boolConfigVal( process.env.IS_WORDPRESS_CORE ) ??
140
+ boolConfigVal( process.env.npm_package_config_IS_WORDPRESS_CORE ) ??
141
+ false
122
142
  ),
123
143
  };
124
144
  const getDefine = ( scriptDebug ) => ( {
@@ -266,8 +286,11 @@ const wasmInlinePlugin = {
266
286
  try {
267
287
  const resolved = require.resolve( args.path );
268
288
  return {
269
- path: resolved,
289
+ path: normalizePath(
290
+ path.relative( ROOT_DIR, resolved )
291
+ ),
270
292
  namespace: 'wasm-inline',
293
+ pluginData: { resolvedPath: resolved },
271
294
  };
272
295
  } catch {
273
296
  // If resolution fails, let other plugins handle it.
@@ -281,7 +304,9 @@ const wasmInlinePlugin = {
281
304
  build.onLoad(
282
305
  { filter: /.*/, namespace: 'wasm-inline' },
283
306
  async ( args ) => {
284
- const wasmBuffer = await readFile( args.path );
307
+ const wasmBuffer = await readFile(
308
+ args.pluginData.resolvedPath
309
+ );
285
310
  const base64 = wasmBuffer.toString( 'base64' );
286
311
  const dataUrl = `data:application/wasm;base64,${ base64 }`;
287
312
 
@@ -315,6 +340,19 @@ function transformPhpContent( content, transforms ) {
315
340
 
316
341
  content = content.toString();
317
342
 
343
+ /*
344
+ * Transforms are used to modify PHP files that are committed to version
345
+ * control in their wordpress-develop state (`wp_` function prefixes, `WP_`
346
+ * class prefixes, etc.). When building for WordPress Core, it's not
347
+ * necessary to perform these steps.
348
+ */
349
+ if (
350
+ boolConfigVal( process.env.IS_WORDPRESS_CORE ) ??
351
+ boolConfigVal( process.env.npm_package_config_IS_WORDPRESS_CORE )
352
+ ) {
353
+ return content;
354
+ }
355
+
318
356
  if ( prefixFunctions.length ) {
319
357
  content = content.replace(
320
358
  new RegExp( prefixFunctions.join( '|' ), 'g' ),
@@ -1771,11 +1809,23 @@ async function buildAll( baseUrlExpression ) {
1771
1809
  id: page.id,
1772
1810
  init: page.init || [],
1773
1811
  title: page.title || undefined,
1812
+ experimental: page.experimental || false,
1774
1813
  };
1775
1814
  } );
1776
1815
 
1777
- const pageData = normalizedPages.map( ( page ) => {
1778
- const pageRoutes = routes.filter( ( r ) => r.page === page.id );
1816
+ // When building for WordPress Core, exclude experimental pages.
1817
+ const isCoreBuild =
1818
+ boolConfigVal( process.env.IS_WORDPRESS_CORE ) ??
1819
+ boolConfigVal( process.env.npm_package_config_IS_WORDPRESS_CORE );
1820
+ const activePages = isCoreBuild
1821
+ ? normalizedPages.filter( ( page ) => ! page.experimental )
1822
+ : normalizedPages;
1823
+
1824
+ const activePageIds = new Set( activePages.map( ( p ) => p.id ) );
1825
+ const activeRoutes = routes.filter( ( r ) => activePageIds.has( r.page ) );
1826
+
1827
+ const pageData = activePages.map( ( page ) => {
1828
+ const pageRoutes = activeRoutes.filter( ( r ) => r.page === page.id );
1779
1829
  return {
1780
1830
  slug: page.id,
1781
1831
  routes: pageRoutes,
@@ -1784,51 +1834,6 @@ async function buildAll( baseUrlExpression ) {
1784
1834
  };
1785
1835
  } );
1786
1836
 
1787
- // Bundle boot, route, and theme packages from node_modules when pages exist
1788
- if ( pageData.length > 0 ) {
1789
- try {
1790
- const { createRequire } = await import( 'module' );
1791
- const require = createRequire( import.meta.url );
1792
-
1793
- // Resolve the @wordpress packages directory from node_modules
1794
- const bootPackageJson = require.resolve(
1795
- '@wordpress/boot/package.json',
1796
- { paths: [ ROOT_DIR ] }
1797
- );
1798
- const wordpressPackagesDir = path.dirname(
1799
- path.dirname( bootPackageJson )
1800
- );
1801
-
1802
- // Bundle boot, route, theme, and private-apis packages
1803
- const externalPackages = [
1804
- 'boot',
1805
- 'route',
1806
- 'theme',
1807
- 'private-apis',
1808
- ];
1809
- for ( const pkgName of externalPackages ) {
1810
- const result = await bundlePackage( pkgName, {
1811
- sourceDir: wordpressPackagesDir,
1812
- handlePrefix: 'wp',
1813
- scriptGlobal: 'wp',
1814
- packageNamespace: 'wordpress',
1815
- } );
1816
-
1817
- if ( result && result.modules ) {
1818
- modules.push( ...result.modules );
1819
- }
1820
- if ( result && result.scripts ) {
1821
- scripts.push( ...result.scripts );
1822
- }
1823
- }
1824
- } catch ( error ) {
1825
- console.warn(
1826
- '\n⚠️ Warning: Could not bundle WordPress packages for pages:',
1827
- error.message
1828
- );
1829
- }
1830
- }
1831
-
1832
1837
  console.log( '\n📄 Generating PHP registration files...\n' );
1833
1838
  const phpReplacements = await getPhpReplacements(
1834
1839
  ROOT_DIR,
@@ -1840,8 +1845,8 @@ async function buildAll( baseUrlExpression ) {
1840
1845
  generateScriptRegistrationPhp( scripts, phpReplacements ),
1841
1846
  generateStyleRegistrationPhp( styles, phpReplacements ),
1842
1847
  generateConstantsPhp( phpReplacements ),
1843
- generateRoutesRegistry( routes, phpReplacements ),
1844
- generateRoutesPhp( routes, phpReplacements ),
1848
+ generateRoutesRegistry( activeRoutes, phpReplacements ),
1849
+ generateRoutesPhp( activeRoutes, phpReplacements ),
1845
1850
  generatePagesPhp( pageData, phpReplacements ),
1846
1851
  ] );
1847
1852
  console.log( ' ✔ Generated build/build.php' );
@@ -2130,7 +2135,13 @@ async function main() {
2130
2135
  },
2131
2136
  'base-url': {
2132
2137
  type: 'string',
2133
- default: 'plugin_dir_url( __FILE__ )',
2138
+ default:
2139
+ boolConfigVal( process.env.IS_WORDPRESS_CORE ) ??
2140
+ boolConfigVal(
2141
+ process.env.npm_package_config_IS_WORDPRESS_CORE
2142
+ )
2143
+ ? "includes_url( 'build/' )"
2144
+ : 'plugin_dir_url( __FILE__ )',
2134
2145
  },
2135
2146
  },
2136
2147
  strict: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/build",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Build tool for WordPress plugins.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -77,5 +77,5 @@
77
77
  "publishConfig": {
78
78
  "access": "public"
79
79
  },
80
- "gitHead": "8bfc179b9aed74c0a6dd6e8edf7a49e40e4f87cc"
80
+ "gitHead": "c20787b1778ae64c2db65643b1c236309d68e6ba"
81
81
  }
@@ -6,44 +6,52 @@
6
6
  * @package {{PREFIX}}
7
7
  */
8
8
 
9
- if ( ! function_exists( '{{PREFIX}}_register_script_modules' ) ) {
10
- /**
11
- * Register all script modules.
12
- */
13
- function {{PREFIX}}_register_script_modules() {
14
- // Load build constants
15
- $build_constants = require __DIR__ . '/constants.php';
16
- $modules_dir = __DIR__ . '/modules';
17
- $modules_file = $modules_dir . '/registry.php';
18
-
19
- if ( ! file_exists( $modules_file ) ) {
20
- return;
21
- }
22
-
23
- $modules = require $modules_file;
24
- $base_url = $build_constants['build_url'] . 'modules/';
25
- $extension = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.js' : '.min.js';
26
-
27
- foreach ( $modules as $module ) {
28
- $asset_path = $modules_dir . '/' . $module['asset'];
29
- $asset = file_exists( $asset_path ) ? require $asset_path : array();
30
-
31
- // Deregister first to override any previously registered version
32
- // (e.g., Core's default modules when running as a plugin).
33
- wp_deregister_script_module( $module['id'] );
34
-
35
- wp_register_script_module(
36
- $module['id'],
37
- $base_url . $module['path'] . $extension,
38
- $asset['module_dependencies'] ?? array(),
39
- $asset['version'] ?? false,
40
- array(
41
- 'fetchpriority' => 'low',
42
- 'in_footer' => true,
43
- )
44
- );
45
- }
9
+ /**
10
+ * Register all script modules.
11
+ */
12
+ function {{PREFIX}}_register_script_modules() {
13
+ // Ensure this only runs once. wp_default_scripts can fire multiple times,
14
+ // and each wp_deregister_script_module() call also dequeues the module.
15
+ // If a module was enqueued between calls, repeated deregister/register
16
+ // cycles would lose the enqueue state.
17
+ static $already_registered = false;
18
+ if ( $already_registered ) {
19
+ return;
20
+ }
21
+ $already_registered = true;
22
+
23
+ // Load build constants
24
+ $build_constants = require __DIR__ . '/constants.php';
25
+ $modules_dir = __DIR__ . '/modules';
26
+ $modules_file = $modules_dir . '/registry.php';
27
+
28
+ if ( ! file_exists( $modules_file ) ) {
29
+ return;
46
30
  }
47
31
 
48
- add_action( 'wp_default_scripts', '{{PREFIX}}_register_script_modules' );
32
+ $modules = require $modules_file;
33
+ $base_url = $build_constants['build_url'] . 'modules/';
34
+ $extension = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.js' : '.min.js';
35
+
36
+ foreach ( $modules as $module ) {
37
+ $asset_path = $modules_dir . '/' . $module['asset'];
38
+ $asset = file_exists( $asset_path ) ? require $asset_path : array();
39
+
40
+ // Deregister first to override any previously registered version
41
+ // (e.g., Core's default modules when running as a plugin).
42
+ wp_deregister_script_module( $module['id'] );
43
+
44
+ wp_register_script_module(
45
+ $module['id'],
46
+ $base_url . $module['path'] . $extension,
47
+ $asset['module_dependencies'] ?? array(),
48
+ $asset['version'] ?? false,
49
+ array(
50
+ 'fetchpriority' => 'low',
51
+ 'in_footer' => true,
52
+ )
53
+ );
54
+ }
49
55
  }
56
+
57
+ add_action( 'wp_default_scripts', '{{PREFIX}}_register_script_modules' );