@wordpress/dependency-extraction-webpack-plugin 4.30.0 → 5.0.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/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ## Gutenberg
2
2
 
3
- Copyright 2016-2023 by the contributors
3
+ Copyright 2016-2024 by the contributors
4
4
 
5
5
  **License for Contributions (on and after April 15, 2021)**
6
6
 
package/README.md CHANGED
@@ -2,11 +2,15 @@
2
2
 
3
3
  This webpack plugin serves two purposes:
4
4
 
5
- - Externalize dependencies that are available as script dependencies on modern WordPress sites.
6
- - Add an asset file for each entry point that declares an object with the list of WordPress script dependencies for the entry point. The asset file also contains the current version calculated for the current source code.
5
+ - Externalize dependencies that are available as shared scripts or modules on WordPress sites.
6
+ - Add an asset file for each entry point that declares an object with the list of WordPress script or module dependencies for the entry point. The asset file also contains the current version calculated for the current source code.
7
7
 
8
8
  This allows JavaScript bundles produced by webpack to leverage WordPress style dependency sharing without an error-prone process of manually maintaining a dependency list.
9
9
 
10
+ Version 5 of this plugin adds support for module bundling. [Webpack's `output.module` option](https://webpack.js.org/configuration/output/#outputmodule) should
11
+ be used to opt-in to this behavior. This plugin will adapt it's behavior based on the
12
+ `output.module` option, producing an asset file suitable for use with the WordPress Module API.
13
+
10
14
  Consult the [webpack website](https://webpack.js.org) for additional information on webpack concepts.
11
15
 
12
16
  ## Installation
@@ -17,7 +21,7 @@ Install the module
17
21
  npm install @wordpress/dependency-extraction-webpack-plugin --save-dev
18
22
  ```
19
23
 
20
- **Note**: This package requires Node.js 14.0.0 or later. It also requires webpack 4.8.3 and newer. It is not compatible with older versions.
24
+ **Note**: This package requires Node.js 18.0.0 or later. It also requires webpack 5.0.0 or newer. It is not compatible with older versions.
21
25
 
22
26
  ## Usage
23
27
 
@@ -39,7 +43,7 @@ module.exports = {
39
43
 
40
44
  ```js
41
45
  const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
42
- const config = {
46
+ const webpackConfig = {
43
47
  ...defaultConfig,
44
48
  plugins: [
45
49
  ...defaultConfig.plugins.filter(
@@ -56,7 +60,9 @@ const config = {
56
60
  };
57
61
  ```
58
62
 
59
- Each entry point in the webpack bundle will include an asset file that declares the WordPress script dependencies that should be enqueued. Such file also contains the unique version hash calculated based on the file content.
63
+ ### Behavior with scripts
64
+
65
+ Each entry point in the webpack bundle will include an asset file that declares the WordPress script dependencies that should be enqueued. This file also contains the unique version hash calculated based on the file content.
60
66
 
61
67
  For example:
62
68
 
@@ -88,6 +94,68 @@ By default, the following module requests are handled:
88
94
 
89
95
  This plugin is compatible with `externals`, but they may conflict. For example, adding `{ externals: { '@wordpress/blob': 'wp.blob' } }` to webpack configuration will effectively hide the `@wordpress/blob` module from the plugin and it will not be included in dependency lists.
90
96
 
97
+ ### Behavior with modules
98
+
99
+ **Warning:** Modules support is considered experimental at this time.
100
+
101
+ This section describes the behavior of this package to bundle ECMAScript modules and generate asset
102
+ files suitable for use with the WordPress Modules API.
103
+
104
+ Some of this plugin's options change, and webpack requires configuration to output modules. Refer to
105
+ [webpack's documentation](https://webpack.js.org/configuration/output/#outputmodule) for up-to-date details.
106
+
107
+ ```js
108
+ const webpackConfig = {
109
+ ...defaultConfig,
110
+
111
+ // These lines are necessary to enable module compilation at time-of-writing:
112
+ output: { module: true },
113
+ experiments: { outputModule: true },
114
+
115
+ plugins: [
116
+ ...defaultConfig.plugins.filter(
117
+ ( plugin ) =>
118
+ plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
119
+ ),
120
+ new DependencyExtractionWebpackPlugin( {
121
+ // With modules, we use `requestToExternalModule`:
122
+ requestToExternalModule( request ) {
123
+ if ( request === 'my-registered-module' ) {
124
+ return request;
125
+ }
126
+ },
127
+ } ),
128
+ ],
129
+ };
130
+ ```
131
+
132
+ Each entry point in the webpack bundle will include an asset file that declares the WordPress module dependencies that should be enqueued. This file also contains the unique version hash calculated based on the file content.
133
+
134
+ For example:
135
+
136
+ ```
137
+ // Source file entrypoint.js
138
+ import { store, getContext } from '@wordpress/interactivity';
139
+
140
+ // Webpack will produce the output output/entrypoint.js
141
+ /* bundled JavaScript output */
142
+
143
+ // Webpack will also produce output/entrypoint.asset.php declaring script dependencies
144
+ <?php return array('dependencies' => array('@wordpress/interactivity'), 'version' => 'dd4c2dc50d046ed9d4c063a7ca95702f');
145
+ ```
146
+
147
+ By default, the following module requests are handled:
148
+
149
+ | Request |
150
+ | ---------------------------- |
151
+ | `@wordpress/interactivity ` |
152
+
153
+ (`@wordpress/interactivity` is currently the only available WordPress module.)
154
+
155
+ **Note:** This plugin overlaps with the functionality provided by [webpack `externals`](https://webpack.js.org/configuration/externals). This plugin is intended to extract module handles from bundle compilation so that a list of module dependencies does not need to be manually maintained. If you don't need to extract a list of module dependencies, use the `externals` option directly.
156
+
157
+ This plugin is compatible with `externals`, but they may conflict. For example, adding `{ externals: { '@wordpress/blob': 'wp.blob' } }` to webpack configuration will effectively hide the `@wordpress/blob` module from the plugin and it will not be included in dependency lists.
158
+
91
159
  #### Options
92
160
 
93
161
  An object can be passed to the constructor to customize the behavior, for example:
@@ -142,6 +210,8 @@ Pass `useDefaults: false` to disable the default request handling.
142
210
 
143
211
  Force `wp-polyfill` to be included in each entry point's dependency list. This would be the same as adding `import '@wordpress/polyfill';` to each entry point.
144
212
 
213
+ **Note**: This option is not available with modules.
214
+
145
215
  ##### `externalizedReport`
146
216
 
147
217
  - Type: boolean | string
@@ -152,6 +222,8 @@ You can provide a filename, or set it to `true` to report to a default `external
152
222
 
153
223
  ##### `requestToExternal`
154
224
 
225
+ **Note**: This option is not available with modules. See [`requestToExternalModule`](#requestToExternalModule) for module usage.
226
+
155
227
  - Type: function
156
228
 
157
229
  `requestToExternal` allows the module handling to be customized. The function should accept a module request string and may return a string representing the global variable to use. An array of strings may be used to access globals via an object path, e.g. `wp.i18n` may be represented as `[ 'wp', 'i18n' ]`.
@@ -179,8 +251,46 @@ module.exports = {
179
251
  };
180
252
  ```
181
253
 
254
+ ##### `requestToExternalModule`
255
+
256
+ **Note**: This option is only available with modules. See [`requestToExternal`](#requestToExternal) for script usage.
257
+
258
+ - Type: function
259
+
260
+ `requestToExternalModule` allows the module handling to be customized. The function should accept a module request string and may return a string representing the module to use. Often, the module will have the same name.
261
+
262
+ `requestToExternalModule` provided via configuration has precedence over default external handling. Unhandled requests will be handled by the default unless `useDefaults` is set to `false`.
263
+
264
+ ```js
265
+ /**
266
+ * Externalize 'my-module'
267
+ *
268
+ * @param {string} request Requested module
269
+ *
270
+ * @return {(string|boolean|undefined)} Module ID
271
+ */
272
+ function requestToExternalModule( request ) {
273
+ // Handle imports like `import myModule from 'my-module'`
274
+ if ( request === 'my-module' ) {
275
+ // Import should be of the form `import { something } from "myModule";` in the final bundle.
276
+ return 'myModule';
277
+ }
278
+
279
+ // If the Module ID in source is the same as the external module, we can return `true`.
280
+ return request === 'external-module-id-no-change-required';
281
+ }
282
+
283
+ module.exports = {
284
+ plugins: [
285
+ new DependencyExtractionWebpackPlugin( { requestToExternalModule } ),
286
+ ],
287
+ };
288
+ ```
289
+
182
290
  ##### `requestToHandle`
183
291
 
292
+ **Note**: This option is not available with modules. It has no corresponding module configuration.
293
+
184
294
  - Type: function
185
295
 
186
296
  All of the external modules handled by the plugin are expected to be WordPress script dependencies
@@ -233,6 +343,19 @@ $script_url = plugins_url( $script_path, __FILE__ );
233
343
  wp_enqueue_script( 'script', $script_url, $script_asset['dependencies'], $script_asset['version'] );
234
344
  ```
235
345
 
346
+ Or with modules (the Module API is not yet stable):
347
+
348
+ ```php
349
+ $module_path = 'path/to/module.js';
350
+ $module_asset_path = 'path/to/module.asset.php';
351
+ $module_asset = file_exists( $module_asset_path )
352
+ ? require( $module_asset_path )
353
+ : array( 'dependencies' => array(), 'version' => filemtime( $module_path ) );
354
+ $module_url = plugins_url( $module_path, __FILE__ );
355
+ wp_register_module( 'my-module', $module_url, $module_asset['dependencies'], $module_asset['version'] );
356
+ wp_enqueue_module( 'my-module' );
357
+ ```
358
+
236
359
  ## Contributing to this package
237
360
 
238
361
  This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects.
@@ -1,6 +1,4 @@
1
1
  {
2
- // Use the default eslint parser. Prevent babel transforms.
3
- "parser": "espree",
4
2
  "env": {
5
3
  "node": true
6
4
  }
package/lib/index.js CHANGED
@@ -3,10 +3,7 @@
3
3
  */
4
4
  const path = require( 'path' );
5
5
  const webpack = require( 'webpack' );
6
- // In webpack 5 there is a `webpack.sources` field but for webpack 4 we have to fallback to the `webpack-sources` package.
7
- const { RawSource } = webpack.sources || require( 'webpack-sources' );
8
6
  const json2php = require( 'json2php' );
9
- const isWebpack4 = webpack.version.startsWith( '4.' );
10
7
  const { createHash } = webpack.util;
11
8
 
12
9
  /**
@@ -14,9 +11,13 @@ const { createHash } = webpack.util;
14
11
  */
15
12
  const {
16
13
  defaultRequestToExternal,
14
+ defaultRequestToExternalModule,
17
15
  defaultRequestToHandle,
18
16
  } = require( './util' );
19
17
 
18
+ const { RawSource } = webpack.sources;
19
+ const { AsyncDependenciesBlock } = webpack;
20
+
20
21
  const defaultExternalizedReportFileName = 'externalized-dependencies.json';
21
22
 
22
23
  class DependencyExtractionWebpackPlugin {
@@ -34,38 +35,65 @@ class DependencyExtractionWebpackPlugin {
34
35
  options
35
36
  );
36
37
 
37
- /*
38
+ /**
38
39
  * Track requests that are externalized.
39
40
  *
40
41
  * Because we don't have a closed set of dependencies, we need to track what has
41
42
  * been externalized so we can recognize them in a later phase when the dependency
42
43
  * lists are generated.
44
+ *
45
+ * @type {Set<string>}
43
46
  */
44
47
  this.externalizedDeps = new Set();
45
48
 
46
- // Offload externalization work to the ExternalsPlugin.
47
- this.externalsPlugin = new webpack.ExternalsPlugin(
48
- 'window',
49
- isWebpack4
50
- ? this.externalizeWpDeps.bind( this )
51
- : this.externalizeWpDepsV5.bind( this )
52
- );
49
+ /**
50
+ * Should we use modules. This will be set later to match webpack's
51
+ * output.module option.
52
+ *
53
+ * @type {boolean}
54
+ */
55
+ this.useModules = false;
53
56
  }
54
57
 
55
- externalizeWpDeps( _context, request, callback ) {
58
+ /**
59
+ * @param {webpack.ExternalItemFunctionData} data
60
+ * @param { ( err?: null | Error, result?: string | string[] ) => void } callback
61
+ */
62
+ externalizeWpDeps( { request }, callback ) {
56
63
  let externalRequest;
57
64
 
58
- // Handle via options.requestToExternal first.
59
- if ( typeof this.options.requestToExternal === 'function' ) {
60
- externalRequest = this.options.requestToExternal( request );
61
- }
65
+ try {
66
+ // Handle via options.requestToExternal(Module) first.
67
+ if ( this.useModules ) {
68
+ if (
69
+ typeof this.options.requestToExternalModule === 'function'
70
+ ) {
71
+ externalRequest =
72
+ this.options.requestToExternalModule( request );
73
+
74
+ // requestToExternalModule allows a boolean shorthand
75
+ if ( externalRequest === false ) {
76
+ externalRequest = undefined;
77
+ }
78
+ if ( externalRequest === true ) {
79
+ externalRequest = request;
80
+ }
81
+ }
82
+ } else if ( typeof this.options.requestToExternal === 'function' ) {
83
+ externalRequest = this.options.requestToExternal( request );
84
+ }
62
85
 
63
- // Cascade to default if unhandled and enabled.
64
- if (
65
- typeof externalRequest === 'undefined' &&
66
- this.options.useDefaults
67
- ) {
68
- externalRequest = defaultRequestToExternal( request );
86
+ // Cascade to default if unhandled and enabled.
87
+ if (
88
+ typeof externalRequest === 'undefined' &&
89
+ this.options.useDefaults
90
+ ) {
91
+ externalRequest = this.useModules
92
+ ? defaultRequestToExternalModule( request )
93
+ : defaultRequestToExternal( request );
94
+ }
95
+ } catch ( err ) {
96
+ return callback( err );
69
97
  }
70
98
 
71
99
  if ( externalRequest ) {
@@ -77,10 +105,10 @@ class DependencyExtractionWebpackPlugin {
77
105
  return callback();
78
106
  }
79
107
 
80
- externalizeWpDepsV5( { context, request }, callback ) {
81
- return this.externalizeWpDeps( context, request, callback );
82
- }
83
-
108
+ /**
109
+ * @param {string} request
110
+ * @return {string} Mapped dependency name
111
+ */
84
112
  mapRequestToDependency( request ) {
85
113
  // Handle via options.requestToHandle first.
86
114
  if ( typeof this.options.requestToHandle === 'function' ) {
@@ -102,6 +130,10 @@ class DependencyExtractionWebpackPlugin {
102
130
  return request;
103
131
  }
104
132
 
133
+ /**
134
+ * @param {any} asset Asset Data
135
+ * @return {string} Stringified asset data suitable for output
136
+ */
105
137
  stringify( asset ) {
106
138
  if ( this.options.outputFormat === 'php' ) {
107
139
  return `<?php return ${ json2php(
@@ -112,30 +144,37 @@ class DependencyExtractionWebpackPlugin {
112
144
  return JSON.stringify( asset );
113
145
  }
114
146
 
147
+ /** @type {webpack.WebpackPluginInstance['apply']} */
115
148
  apply( compiler ) {
149
+ this.useModules = Boolean( compiler.options.output?.module );
150
+
151
+ /**
152
+ * Offload externalization work to the ExternalsPlugin.
153
+ * @type {webpack.ExternalsPlugin}
154
+ */
155
+ this.externalsPlugin = new webpack.ExternalsPlugin(
156
+ this.useModules ? 'import' : 'window',
157
+ this.externalizeWpDeps.bind( this )
158
+ );
159
+
116
160
  this.externalsPlugin.apply( compiler );
117
161
 
118
- if ( isWebpack4 ) {
119
- compiler.hooks.emit.tap( this.constructor.name, ( compilation ) =>
120
- this.addAssets( compilation )
121
- );
122
- } else {
123
- compiler.hooks.thisCompilation.tap(
124
- this.constructor.name,
125
- ( compilation ) => {
126
- compilation.hooks.processAssets.tap(
127
- {
128
- name: this.constructor.name,
129
- stage: compiler.webpack.Compilation
130
- .PROCESS_ASSETS_STAGE_ANALYSE,
131
- },
132
- () => this.addAssets( compilation )
133
- );
134
- }
135
- );
136
- }
162
+ compiler.hooks.thisCompilation.tap(
163
+ this.constructor.name,
164
+ ( compilation ) => {
165
+ compilation.hooks.processAssets.tap(
166
+ {
167
+ name: this.constructor.name,
168
+ stage: compiler.webpack.Compilation
169
+ .PROCESS_ASSETS_STAGE_ANALYSE,
170
+ },
171
+ () => this.addAssets( compilation )
172
+ );
173
+ }
174
+ );
137
175
  }
138
176
 
177
+ /** @param {webpack.Compilation} compilation */
139
178
  addAssets( compilation ) {
140
179
  const {
141
180
  combineAssets,
@@ -174,28 +213,53 @@ class DependencyExtractionWebpackPlugin {
174
213
  for ( const chunk of entrypointChunks ) {
175
214
  const chunkFiles = Array.from( chunk.files );
176
215
 
177
- const chunkJSFile = chunkFiles.find( ( f ) => /\.js$/i.test( f ) );
216
+ const jsExtensionRegExp = this.useModules ? /\.m?js$/i : /\.js$/i;
217
+
218
+ const chunkJSFile = chunkFiles.find( ( f ) =>
219
+ jsExtensionRegExp.test( f )
220
+ );
178
221
  if ( ! chunkJSFile ) {
179
222
  // There's no JS file in this chunk, no work for us. Typically a `style.css` from cache group.
180
223
  continue;
181
224
  }
182
225
 
183
- const chunkDeps = new Set();
226
+ /** @type {Set<string>} */
227
+ const chunkStaticDeps = new Set();
228
+ /** @type {Set<string>} */
229
+ const chunkDynamicDeps = new Set();
230
+
184
231
  if ( injectPolyfill ) {
185
- chunkDeps.add( 'wp-polyfill' );
232
+ chunkStaticDeps.add( 'wp-polyfill' );
186
233
  }
187
234
 
188
- const processModule = ( { userRequest } ) => {
235
+ /**
236
+ * @param {webpack.Module} m
237
+ */
238
+ const processModule = ( m ) => {
239
+ const { userRequest } = m;
189
240
  if ( this.externalizedDeps.has( userRequest ) ) {
190
- chunkDeps.add( this.mapRequestToDependency( userRequest ) );
241
+ if ( this.useModules ) {
242
+ const isStatic =
243
+ DependencyExtractionWebpackPlugin.hasStaticDependencyPathToRoot(
244
+ compilation,
245
+ m
246
+ );
247
+
248
+ ( isStatic ? chunkStaticDeps : chunkDynamicDeps ).add(
249
+ m.request
250
+ );
251
+ } else {
252
+ chunkStaticDeps.add(
253
+ this.mapRequestToDependency( userRequest )
254
+ );
255
+ }
191
256
  }
192
257
  };
193
258
 
194
259
  // Search for externalized modules in all chunks.
195
- const modulesIterable = isWebpack4
196
- ? chunk.modulesIterable
197
- : compilation.chunkGraph.getChunkModules( chunk );
198
- for ( const chunkModule of modulesIterable ) {
260
+ for ( const chunkModule of compilation.chunkGraph.getChunkModulesIterable(
261
+ chunk
262
+ ) ) {
199
263
  processModule( chunkModule );
200
264
  // Loop through submodules of ConcatenatedModule.
201
265
  if ( chunkModule.modules ) {
@@ -224,11 +288,20 @@ class DependencyExtractionWebpackPlugin {
224
288
  .slice( 0, hashDigestLength );
225
289
 
226
290
  const assetData = {
227
- // Get a sorted array so we can produce a stable, stringified representation.
228
- dependencies: Array.from( chunkDeps ).sort(),
291
+ dependencies: [
292
+ // Sort these so we can produce a stable, stringified representation.
293
+ ...Array.from( chunkStaticDeps ).sort(),
294
+ ...Array.from( chunkDynamicDeps )
295
+ .sort()
296
+ .map( ( id ) => ( { id, type: 'dynamic' } ) ),
297
+ ],
229
298
  version: contentHash,
230
299
  };
231
300
 
301
+ if ( this.useModules ) {
302
+ assetData.type = 'module';
303
+ }
304
+
232
305
  if ( combineAssets ) {
233
306
  combinedAssetsData[ chunkJSFile ] = assetData;
234
307
  continue;
@@ -246,14 +319,14 @@ class DependencyExtractionWebpackPlugin {
246
319
  '.asset.' + ( outputFormat === 'php' ? 'php' : 'json' );
247
320
  assetFilename = compilation
248
321
  .getPath( '[file]', { filename: chunkJSFile } )
249
- .replace( /\.js$/i, suffix );
322
+ .replace( /\.m?js$/i, suffix );
250
323
  }
251
324
 
252
325
  // Add source and file into compilation for webpack to output.
253
326
  compilation.assets[ assetFilename ] = new RawSource(
254
327
  this.stringify( assetData )
255
328
  );
256
- chunk.files[ isWebpack4 ? 'push' : 'add' ]( assetFilename );
329
+ chunk.files.add( assetFilename );
257
330
  }
258
331
 
259
332
  if ( combineAssets ) {
@@ -275,6 +348,58 @@ class DependencyExtractionWebpackPlugin {
275
348
  );
276
349
  }
277
350
  }
351
+
352
+ /**
353
+ * Can we trace a line of static dependencies from an entry to a module
354
+ *
355
+ * @param {webpack.Compilation} compilation
356
+ * @param {webpack.DependenciesBlock} block
357
+ *
358
+ * @return {boolean} True if there is a static import path to the root
359
+ */
360
+ static hasStaticDependencyPathToRoot( compilation, block ) {
361
+ const incomingConnections = [
362
+ ...compilation.moduleGraph.getIncomingConnections( block ),
363
+ ].filter(
364
+ ( connection ) =>
365
+ // Library connections don't have a dependency, this is a root
366
+ connection.dependency &&
367
+ // Entry dependencies are another root
368
+ connection.dependency.constructor.name !== 'EntryDependency'
369
+ );
370
+
371
+ // If we don't have non-entry, non-library incoming connections,
372
+ // we've reached a root of
373
+ if ( ! incomingConnections.length ) {
374
+ return true;
375
+ }
376
+
377
+ const staticDependentModules = incomingConnections.flatMap(
378
+ ( connection ) => {
379
+ const { dependency } = connection;
380
+ const parentBlock =
381
+ compilation.moduleGraph.getParentBlock( dependency );
382
+
383
+ return parentBlock.constructor.name !==
384
+ AsyncDependenciesBlock.name
385
+ ? [ compilation.moduleGraph.getParentModule( dependency ) ]
386
+ : [];
387
+ }
388
+ );
389
+
390
+ // All the dependencies were Async, the module was reached via a dynamic import
391
+ if ( ! staticDependentModules.length ) {
392
+ return false;
393
+ }
394
+
395
+ // Continue to explore any static dependencies
396
+ return staticDependentModules.some( ( parentStaticDependentModule ) =>
397
+ DependencyExtractionWebpackPlugin.hasStaticDependencyPathToRoot(
398
+ compilation,
399
+ parentStaticDependentModule
400
+ )
401
+ );
402
+ }
278
403
  }
279
404
 
280
405
  module.exports = DependencyExtractionWebpackPlugin;
package/lib/types.d.ts CHANGED
@@ -13,6 +13,9 @@ declare interface DependencyExtractionWebpackPluginOptions {
13
13
  outputFormat?: 'php' | 'json';
14
14
  outputFilename?: string | Function;
15
15
  requestToExternal?: ( request: string ) => string | string[] | undefined;
16
+ requestToExternalModule?: (
17
+ request: string
18
+ ) => string | boolean | undefined;
16
19
  requestToHandle?: ( request: string ) => string | undefined;
17
20
  combinedOutputFile?: string | null;
18
21
  combineAssets?: boolean;
package/lib/util.js CHANGED
@@ -1,9 +1,10 @@
1
1
  const WORDPRESS_NAMESPACE = '@wordpress/';
2
2
  const BUNDLED_PACKAGES = [
3
+ '@wordpress/dataviews',
3
4
  '@wordpress/icons',
4
5
  '@wordpress/interface',
5
- '@wordpress/undo-manager',
6
6
  '@wordpress/sync',
7
+ '@wordpress/undo-manager',
7
8
  ];
8
9
 
9
10
  /**
@@ -55,6 +56,37 @@ function defaultRequestToExternal( request ) {
55
56
  }
56
57
  }
57
58
 
59
+ /**
60
+ * Default request to external module transformation
61
+ *
62
+ * Currently only @wordpress/interactivity
63
+ *
64
+ * Do not use the boolean shorthand here, it's only handled for the `requestToExternalModule` option.
65
+ *
66
+ * @param {string} request Module request (the module name in `import from`) to be transformed
67
+ * @return {string|Error|undefined} The resulting external definition.
68
+ * - Return `undefined` to ignore the request (do not externalize).
69
+ * - Return `string` to map the request to an external.
70
+ * - Return `Error` to emit an error.
71
+ */
72
+ function defaultRequestToExternalModule( request ) {
73
+ if ( request === '@wordpress/interactivity' ) {
74
+ // This is a special case. Interactivity does not support dynamic imports at this
75
+ // time. We add the external "module" type to indicate that webpack should
76
+ // externalize this as a module (instead of our default `import()` external type)
77
+ // which forces @wordpress/interactivity imports to be hoisted to static imports.
78
+ return `module ${ request }`;
79
+ }
80
+
81
+ const isWordPressScript = Boolean( defaultRequestToExternal( request ) );
82
+
83
+ if ( isWordPressScript ) {
84
+ throw new Error(
85
+ `Attempted to use WordPress script in a module: ${ request }, which is not supported yet.`
86
+ );
87
+ }
88
+ }
89
+
58
90
  /**
59
91
  * Default request to WordPress script handle transformation
60
92
  *
@@ -100,5 +132,6 @@ function camelCaseDash( string ) {
100
132
  module.exports = {
101
133
  camelCaseDash,
102
134
  defaultRequestToExternal,
135
+ defaultRequestToExternalModule,
103
136
  defaultRequestToHandle,
104
137
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/dependency-extraction-webpack-plugin",
3
- "version": "4.30.0",
3
+ "version": "5.0.0",
4
4
  "description": "Extract WordPress script dependencies from webpack bundles.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -20,7 +20,7 @@
20
20
  "url": "https://github.com/WordPress/gutenberg/issues"
21
21
  },
22
22
  "engines": {
23
- "node": ">=14"
23
+ "node": ">=18"
24
24
  },
25
25
  "files": [
26
26
  "lib",
@@ -29,14 +29,13 @@
29
29
  "main": "lib/index.js",
30
30
  "types": "lib/types.d.ts",
31
31
  "dependencies": {
32
- "json2php": "^0.0.7",
33
- "webpack-sources": "^3.2.2"
32
+ "json2php": "^0.0.7"
34
33
  },
35
34
  "peerDependencies": {
36
- "webpack": "^4.8.3 || ^5.0.0"
35
+ "webpack": "^5.0.0"
37
36
  },
38
37
  "publishConfig": {
39
38
  "access": "public"
40
39
  },
41
- "gitHead": "d98dff8ea96f29cfea045bf964269f46f040d539"
40
+ "gitHead": "5e6f9caa205d3bfdbac131952b7bf9c6ec60569b"
42
41
  }