Commit 61980b2bd23 for woocommerce

commit 61980b2bd233374df53a836533ae619ca31a198d
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date:   Mon Sep 21 13:37:54 2026 +0300

    [dev] Fix blocks lint, dev and start scripts crashing on every run (#68836)

    * fix(blocks): Accept either webpack config shape from wp-scripts

    The interactivity blocks config destructured
    `@wordpress/scripts/config/webpack.config` as an array. That module
    only exports an array when `WP_EXPERIMENTAL_MODULES` is set, and a
    bare object otherwise, so loading `webpack.config.js` without the
    variable threw `TypeError: require is not a function or its return
    value is not iterable`. Every entry point that reaches this config
    was affected, including ESLint, whose flat config resolves imports
    through the webpack resolver.

    Since #56758 introduced the destructure, five pull requests have
    each set the variable at one more call site rather than changing the
    assumption. The variable is not needed: the only value read from the
    export is `module.rules`, and both of wp-scripts' configs take it
    from the same `baseConfig` object. With the flag set they are the
    same object by identity, and a production build is byte-identical
    either way.

    Read `module.rules` through an `Array.isArray` branch so the config
    loads whatever shape wp-scripts exports, and name the one value it
    depends on so a later reader does not take `output` or `experiments`
    from the fallback, where the two configs do differ.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    * fix(blocks): Pass a RegExp to CircularDependencyPlugin

    CircularDependencyPlugin calls `exclude.test()` on the option directly,
    and its own default is a RegExp. The option was an array holding one
    RegExp, which has no `test` method, so the `start` script died with
    `TypeError: plugin.options.exclude.test is not a function` as soon as
    the config loaded far enough to build.

    `CHECK_CIRCULAR_DEPS` is set only by `start`, so this never fired
    anywhere else and stayed hidden behind the config load error.

    The plugin is constructed once, in `getSharedPlugins`, which every
    caller including the unified editor assets config goes through, so one
    change covers all of them. The other `exclude` options in this file are
    webpack module rules, where a `RuleSetCondition` array is valid, and are
    left alone.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    * chore(blocks): Add changelog entry for the webpack config fixes

    A `dev` entry with a comment and no message, so nothing lands in the
    published changelog. `.distignore` excludes `/client/` and
    `package.json` from the release build, so none of this reaches
    merchants.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---------

    Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

diff --git a/plugins/woocommerce/client/blocks/bin/webpack-config-interactive-blocks.js b/plugins/woocommerce/client/blocks/bin/webpack-config-interactive-blocks.js
index 47c691ff726..2250ee96bc2 100644
--- a/plugins/woocommerce/client/blocks/bin/webpack-config-interactive-blocks.js
+++ b/plugins/woocommerce/client/blocks/bin/webpack-config-interactive-blocks.js
@@ -3,10 +3,14 @@
  */
 const path = require( 'path' );
 const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' );
-const [
-	,
-	moduleConfig,
-] = require( '@wordpress/scripts/config/webpack.config' );
+// wp-scripts exports [ scriptConfig, moduleConfig ] when WP_EXPERIMENTAL_MODULES
+// is set, and a bare scriptConfig otherwise. Both carry the same module.rules,
+// which is the only thing taken from it here, so read that one value instead of
+// depending on the export's shape.
+const wpScriptsConfig = require( '@wordpress/scripts/config/webpack.config' );
+const {
+	module: { rules: wpScriptsModuleRules },
+} = Array.isArray( wpScriptsConfig ) ? wpScriptsConfig[ 1 ] : wpScriptsConfig;
 const DependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );
 const {
 	WebpackRTLPlugin,
@@ -99,7 +103,7 @@ module.exports = {
 	],
 	module: {
 		rules: [
-			...moduleConfig.module.rules.filter(
+			...wpScriptsModuleRules.filter(
 				( rule ) =>
 					! rule.test.test( '.css' ) &&
 					! rule.test.test( '.scss' ) &&
diff --git a/plugins/woocommerce/client/blocks/bin/webpack-configs.js b/plugins/woocommerce/client/blocks/bin/webpack-configs.js
index eae229beb69..d65028ae9ab 100644
--- a/plugins/woocommerce/client/blocks/bin/webpack-configs.js
+++ b/plugins/woocommerce/client/blocks/bin/webpack-configs.js
@@ -58,7 +58,9 @@ const getSharedPlugins = ( {
 	[
 		CHECK_CIRCULAR_DEPS === 'true' && checkCircularDeps !== false
 			? new CircularDependencyPlugin( {
-					exclude: [ /[\/\\](node_modules|build|docs|vendor)[\/\\]/ ],
+					// This plugin calls exclude.test() directly, so it must be a
+					// single RegExp, not the array webpack's module rules accept.
+					exclude: /[\/\\](node_modules|build|docs|vendor)[\/\\]/,
 					cwd: process.cwd(),
 					failOnError: 'warn',
 			  } )
diff --git a/plugins/woocommerce/client/blocks/changelog/fix-blocks-webpack-config-export-shape b/plugins/woocommerce/client/blocks/changelog/fix-blocks-webpack-config-export-shape
new file mode 100644
index 00000000000..933870847d2
--- /dev/null
+++ b/plugins/woocommerce/client/blocks/changelog/fix-blocks-webpack-config-export-shape
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Load the blocks webpack config whatever shape @wordpress/scripts exports, so it no longer needs WP_EXPERIMENTAL_MODULES, and pass CircularDependencyPlugin a RegExp so the start script builds; developer tooling only, no production change.