@wordpress/build 0.8.1-next.v.202602241322.0 → 0.8.1

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,13 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### Enhancements
6
+
7
+ - Avoid unexpected results when typecasting `IS_GUTENBERG_PLUGIN` and `IS_WORDPRESS_CORE` values to Booleans ([#75844](https://github.com/WordPress/gutenberg/pull/75844)).
8
+ - Skip PHP transforms during builds when building for WordPress Core ([#75844](https://github.com/WordPress/gutenberg/pull/75844)).
9
+
10
+ ## 0.9.0 (2026-03-04)
11
+
5
12
  ## 0.8.0 (2026-02-18)
6
13
 
7
14
  ## 0.7.0 (2026-01-29)
package/lib/build.mjs CHANGED
@@ -21,6 +21,26 @@ import babel from 'esbuild-plugin-babel';
21
21
  import { camelCase } from 'change-case';
22
22
  import { NodePackageImporter } from 'sass-embedded';
23
23
 
24
+ // Optional dependency: @wordpress/theme provides plugins that inject fallback
25
+ // values for design system tokens. Fails gracefully when the package is not
26
+ // installed (it is an optional peerDependency).
27
+ let dsTokenFallbacks;
28
+ let dsTokenFallbacksJs;
29
+ try {
30
+ const { default: postcssPlugin } = await import(
31
+ // eslint-disable-next-line import/no-unresolved
32
+ '@wordpress/theme/postcss-plugins/postcss-ds-token-fallbacks'
33
+ );
34
+ const { default: esbuildPlugin } = await import(
35
+ // eslint-disable-next-line import/no-unresolved
36
+ '@wordpress/theme/esbuild-plugins/esbuild-ds-token-fallbacks'
37
+ );
38
+ dsTokenFallbacks = postcssPlugin;
39
+ dsTokenFallbacksJs = esbuildPlugin;
40
+ } catch {
41
+ // @wordpress/theme is optional; skip token fallbacks if not available.
42
+ }
43
+
24
44
  /**
25
45
  * Internal dependencies
26
46
  */
@@ -93,12 +113,32 @@ const HANDLE_PREFIX = WP_PLUGIN_CONFIG.handlePrefix || PACKAGE_NAMESPACE;
93
113
  const EXTERNAL_NAMESPACES = WP_PLUGIN_CONFIG.externalNamespaces || {};
94
114
  const PAGES = WP_PLUGIN_CONFIG.pages || [];
95
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
+
96
130
  const baseDefine = {
97
131
  'globalThis.IS_GUTENBERG_PLUGIN': JSON.stringify(
98
- 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
99
137
  ),
100
138
  'globalThis.IS_WORDPRESS_CORE': JSON.stringify(
101
- 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
102
142
  ),
103
143
  };
104
144
  const getDefine = ( scriptDebug ) => ( {
@@ -150,8 +190,9 @@ function compileInlineStyle( { cssModules = false, minify = true } = {} ) {
150
190
 
151
191
  let moduleExports = null;
152
192
 
153
- // Transform the code: CSS modules and minification.
193
+ // Transform the code: token fallbacks, CSS modules and minification.
154
194
  const plugins = [
195
+ dsTokenFallbacks,
155
196
  cssModules &&
156
197
  postcssModules( {
157
198
  generateScopedName: '[contenthash]__[local]',
@@ -207,6 +248,7 @@ function createStyleBundlingPlugins( workingDir ) {
207
248
  // Handle CSS modules (.module.css and .module.scss)
208
249
  sassPlugin( {
209
250
  embedded: true,
251
+ sourceMap: false,
210
252
  filter: /\.module\.(css|scss)$/,
211
253
  transform: compileInlineStyle( { cssModules: true } ),
212
254
  type: inlineStyle,
@@ -216,6 +258,7 @@ function createStyleBundlingPlugins( workingDir ) {
216
258
  // Note: .module.css and .module.scss already handled by plugin above
217
259
  sassPlugin( {
218
260
  embedded: true,
261
+ sourceMap: false,
219
262
  filter: /\.(css|scss)$/,
220
263
  transform: compileInlineStyle(),
221
264
  type: inlineStyle,
@@ -243,8 +286,11 @@ const wasmInlinePlugin = {
243
286
  try {
244
287
  const resolved = require.resolve( args.path );
245
288
  return {
246
- path: resolved,
289
+ path: normalizePath(
290
+ path.relative( ROOT_DIR, resolved )
291
+ ),
247
292
  namespace: 'wasm-inline',
293
+ pluginData: { resolvedPath: resolved },
248
294
  };
249
295
  } catch {
250
296
  // If resolution fails, let other plugins handle it.
@@ -258,7 +304,9 @@ const wasmInlinePlugin = {
258
304
  build.onLoad(
259
305
  { filter: /.*/, namespace: 'wasm-inline' },
260
306
  async ( args ) => {
261
- const wasmBuffer = await readFile( args.path );
307
+ const wasmBuffer = await readFile(
308
+ args.pluginData.resolvedPath
309
+ );
262
310
  const base64 = wasmBuffer.toString( 'base64' );
263
311
  const dataUrl = `data:application/wasm;base64,${ base64 }`;
264
312
 
@@ -292,6 +340,19 @@ function transformPhpContent( content, transforms ) {
292
340
 
293
341
  content = content.toString();
294
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
+
295
356
  if ( prefixFunctions.length ) {
296
357
  content = content.replace(
297
358
  new RegExp( prefixFunctions.join( '|' ), 'g' ),
@@ -530,6 +591,15 @@ async function bundlePackage( packageName, options = {} ) {
530
591
  const entryPoint = path.join( packageDir, exportPath );
531
592
  const baseFileName = path.basename( fileName );
532
593
 
594
+ // Skip non-minified build for WASM-inlined workers (e.g., vips).
595
+ // These are ~16MB of base64-encoded WASM with no debugging value
596
+ // over the minified version.
597
+ const isWasmWorker =
598
+ packageJson.wpWorkers &&
599
+ Object.keys( packageJson.wpWorkers ).some(
600
+ ( key ) => key.replace( /^\.\//, '' ) === fileName
601
+ );
602
+
533
603
  builds.push(
534
604
  esbuild.build( {
535
605
  entryPoints: [ entryPoint ],
@@ -552,31 +622,36 @@ async function bundlePackage( packageName, options = {} ) {
552
622
  true // Generate asset file for minified build
553
623
  ),
554
624
  ],
555
- } ),
556
- esbuild.build( {
557
- entryPoints: [ entryPoint ],
558
- outfile: path.join(
559
- rootBuildModuleDir,
560
- `${ fileName }.js`
561
- ),
562
- bundle: true,
563
- sourcemap: true,
564
- format: 'esm',
565
- target,
566
- platform: 'browser',
567
- minify: false,
568
- define: getDefine( true ),
569
- plugins: [
570
- wordpressExternalsPlugin(
571
- `${ baseFileName }.min`,
572
- 'esm',
573
- [],
574
- false // Skip asset file for non-minified build
575
- ),
576
- ],
577
625
  } )
578
626
  );
579
627
 
628
+ if ( ! isWasmWorker ) {
629
+ builds.push(
630
+ esbuild.build( {
631
+ entryPoints: [ entryPoint ],
632
+ outfile: path.join(
633
+ rootBuildModuleDir,
634
+ `${ fileName }.js`
635
+ ),
636
+ bundle: true,
637
+ sourcemap: true,
638
+ format: 'esm',
639
+ target,
640
+ platform: 'browser',
641
+ minify: false,
642
+ define: getDefine( true ),
643
+ plugins: [
644
+ wordpressExternalsPlugin(
645
+ `${ baseFileName }.min`,
646
+ 'esm',
647
+ [],
648
+ false // Skip asset file for non-minified build
649
+ ),
650
+ ],
651
+ } )
652
+ );
653
+ }
654
+
580
655
  const scriptModuleId =
581
656
  exportName === '.'
582
657
  ? `@${ packageNamespace }/${ packageName }`
@@ -586,6 +661,7 @@ async function bundlePackage( packageName, options = {} ) {
586
661
  id: scriptModuleId,
587
662
  path: `${ packageName }/${ fileName }`,
588
663
  asset: `${ packageName }/${ fileName }.min.asset.php`,
664
+ min_only: isWasmWorker,
589
665
  } );
590
666
  }
591
667
  }
@@ -848,6 +924,7 @@ async function generateModuleRegistrationPhp( modules, replacements ) {
848
924
  `\t\t'id' => '${ module.id }',\n` +
849
925
  `\t\t'path' => '${ module.path }',\n` +
850
926
  `\t\t'asset' => '${ module.asset }',\n` +
927
+ ( module.min_only ? `\t\t'min_only' => true,\n` : '' ) +
851
928
  `\t),`
852
929
  )
853
930
  .join( '\n' );
@@ -1251,6 +1328,11 @@ async function transpilePackage( packageName ) {
1251
1328
  },
1252
1329
  };
1253
1330
  const plugins = [
1331
+ // Note: dsTokenFallbacksJs and emotionPlugin both use esbuild's onLoad
1332
+ // hook, which is non-composable — the first to return contents wins. If a
1333
+ // file contains --wpds-* tokens, the Emotion transform will be skipped.
1334
+ // Avoid using design tokens in Emotion styles until Emotion is removed.
1335
+ dsTokenFallbacksJs,
1254
1336
  needsEmotionPlugin && emotionPlugin,
1255
1337
  wasmInlinePlugin,
1256
1338
  externalizeAllExceptCssPlugin,
@@ -1408,12 +1490,13 @@ async function compileStyles( packageName ) {
1408
1490
  embedded: true,
1409
1491
  ...getSassOptions( packageDir ),
1410
1492
  async transform( source ) {
1411
- // Process with autoprefixer for LTR version
1412
- const ltrResult = await postcss( [
1413
- autoprefixer( { grid: true } ),
1414
- ] ).process( source, { from: undefined } );
1493
+ const ltrResult = await postcss(
1494
+ [
1495
+ dsTokenFallbacks,
1496
+ autoprefixer( { grid: true } ),
1497
+ ].filter( Boolean )
1498
+ ).process( source, { from: undefined } );
1415
1499
 
1416
- // Process with rtlcss for RTL version
1417
1500
  const rtlResult = await postcss( [
1418
1501
  rtlcss(),
1419
1502
  ] ).process( ltrResult.css, { from: undefined } );
@@ -1742,11 +1825,23 @@ async function buildAll( baseUrlExpression ) {
1742
1825
  id: page.id,
1743
1826
  init: page.init || [],
1744
1827
  title: page.title || undefined,
1828
+ experimental: page.experimental || false,
1745
1829
  };
1746
1830
  } );
1747
1831
 
1748
- const pageData = normalizedPages.map( ( page ) => {
1749
- const pageRoutes = routes.filter( ( r ) => r.page === page.id );
1832
+ // When building for WordPress Core, exclude experimental pages.
1833
+ const isCoreBuild =
1834
+ boolConfigVal( process.env.IS_WORDPRESS_CORE ) ??
1835
+ boolConfigVal( process.env.npm_package_config_IS_WORDPRESS_CORE );
1836
+ const activePages = isCoreBuild
1837
+ ? normalizedPages.filter( ( page ) => ! page.experimental )
1838
+ : normalizedPages;
1839
+
1840
+ const activePageIds = new Set( activePages.map( ( p ) => p.id ) );
1841
+ const activeRoutes = routes.filter( ( r ) => activePageIds.has( r.page ) );
1842
+
1843
+ const pageData = activePages.map( ( page ) => {
1844
+ const pageRoutes = activeRoutes.filter( ( r ) => r.page === page.id );
1750
1845
  return {
1751
1846
  slug: page.id,
1752
1847
  routes: pageRoutes,
@@ -1811,8 +1906,8 @@ async function buildAll( baseUrlExpression ) {
1811
1906
  generateScriptRegistrationPhp( scripts, phpReplacements ),
1812
1907
  generateStyleRegistrationPhp( styles, phpReplacements ),
1813
1908
  generateConstantsPhp( phpReplacements ),
1814
- generateRoutesRegistry( routes, phpReplacements ),
1815
- generateRoutesPhp( routes, phpReplacements ),
1909
+ generateRoutesRegistry( activeRoutes, phpReplacements ),
1910
+ generateRoutesPhp( activeRoutes, phpReplacements ),
1816
1911
  generatePagesPhp( pageData, phpReplacements ),
1817
1912
  ] );
1818
1913
  console.log( ' ✔ Generated build/build.php' );
@@ -2101,7 +2196,13 @@ async function main() {
2101
2196
  },
2102
2197
  'base-url': {
2103
2198
  type: 'string',
2104
- default: 'plugin_dir_url( __FILE__ )',
2199
+ default:
2200
+ boolConfigVal( process.env.IS_WORDPRESS_CORE ) ??
2201
+ boolConfigVal(
2202
+ process.env.npm_package_config_IS_WORDPRESS_CORE
2203
+ )
2204
+ ? "includes_url( 'build/' )"
2205
+ : 'plugin_dir_url( __FILE__ )',
2105
2206
  },
2106
2207
  },
2107
2208
  strict: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/build",
3
- "version": "0.8.1-next.v.202602241322.0+bce7cff88",
3
+ "version": "0.8.1",
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": "943dde7f0b600ce238726c36284bc9f70ce0ffa4"
80
+ "gitHead": "adb6623c9f32490cfc73c7ac7f122578c1f10c65"
81
81
  }
@@ -6,40 +6,46 @@
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
- wp_register_script_module(
32
- $module['id'],
33
- $base_url . $module['path'] . $extension,
34
- $asset['module_dependencies'] ?? array(),
35
- $asset['version'] ?? false,
36
- array(
37
- 'fetchpriority' => 'low',
38
- 'in_footer' => true,
39
- )
40
- );
41
- }
9
+ /**
10
+ * Register all script modules.
11
+ */
12
+ function {{PREFIX}}_register_script_modules() {
13
+ // Load build constants
14
+ $build_constants = require __DIR__ . '/constants.php';
15
+ $modules_dir = __DIR__ . '/modules';
16
+ $modules_file = $modules_dir . '/registry.php';
17
+
18
+ if ( ! file_exists( $modules_file ) ) {
19
+ return;
42
20
  }
43
21
 
44
- add_action( 'wp_default_scripts', '{{PREFIX}}_register_script_modules' );
22
+ $modules = require $modules_file;
23
+ $base_url = $build_constants['build_url'] . 'modules/';
24
+
25
+ foreach ( $modules as $module ) {
26
+ // WASM-only modules (e.g., vips worker) only have .min.js; use it even when SCRIPT_DEBUG is `true`.
27
+ $extension = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && empty( $module['min_only'] ) )
28
+ ? '.js'
29
+ : '.min.js';
30
+
31
+ $asset_path = $modules_dir . '/' . $module['asset'];
32
+ $asset = file_exists( $asset_path ) ? require $asset_path : array();
33
+
34
+ // Deregister first to override any previously registered version
35
+ // (e.g., Core's default modules when running as a plugin).
36
+ wp_deregister_script_module( $module['id'] );
37
+
38
+ wp_register_script_module(
39
+ $module['id'],
40
+ $base_url . $module['path'] . $extension,
41
+ $asset['module_dependencies'] ?? array(),
42
+ $asset['version'] ?? false,
43
+ array(
44
+ 'fetchpriority' => 'low',
45
+ 'in_footer' => true,
46
+ )
47
+ );
48
+ }
45
49
  }
50
+
51
+ add_action( 'wp_default_scripts', '{{PREFIX}}_register_script_modules' );