@wordpress/dependency-extraction-webpack-plugin 3.2.0 → 3.2.3-next.33ec3857e2.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/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 3.2.2-next.0 (2021-12-20)
6
+
7
+ - Add the optional `externalizedReportFile` option ([#35106](https://github.com/WordPress/gutenberg/pull/35106)).
8
+
5
9
  ## 3.0.0 (2021-01-21)
6
10
 
7
11
  ### Breaking Changes
package/README.md CHANGED
@@ -107,6 +107,13 @@ module.exports = {
107
107
 
108
108
  The output format for the generated asset file. There are two options available: 'php' or 'json'.
109
109
 
110
+ ##### `outputFilename`
111
+
112
+ - Type: string | function
113
+ - Default: null
114
+
115
+ The filename for the generated asset file. Accepts the same values as the Webpack `output.filename` option.
116
+
110
117
  ##### `combineAssets`
111
118
 
112
119
  - Type: boolean
@@ -135,6 +142,14 @@ Pass `useDefaults: false` to disable the default request handling.
135
142
 
136
143
  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.
137
144
 
145
+ ##### `externalizedReport`
146
+
147
+ - Type: boolean | string
148
+ - Default: `false`
149
+
150
+ Report all externalized dependencies as an array in JSON format. It could be used for further manual or automated inspection.
151
+ You can provide a filename, or set it to `true` to report to a default `externalized-dependencies.json`.
152
+
138
153
  ##### `requestToExternal`
139
154
 
140
155
  - Type: function
package/lib/index.js CHANGED
@@ -7,6 +7,7 @@ const webpack = require( 'webpack' );
7
7
  // In webpack 5 there is a `webpack.sources` field but for webpack 4 we have to fallback to the `webpack-sources` package.
8
8
  const { RawSource } = webpack.sources || require( 'webpack-sources' );
9
9
  const json2php = require( 'json2php' );
10
+ const isWebpack4 = webpack.version.startsWith( '4.' );
10
11
 
11
12
  /**
12
13
  * Internal dependencies
@@ -16,14 +17,18 @@ const {
16
17
  defaultRequestToHandle,
17
18
  } = require( './util' );
18
19
 
20
+ const defaultExternalizedReportFileName = 'externalized-dependencies.json';
21
+
19
22
  class DependencyExtractionWebpackPlugin {
20
23
  constructor( options ) {
21
24
  this.options = Object.assign(
22
25
  {
23
26
  combineAssets: false,
24
27
  combinedOutputFile: null,
28
+ externalizedReport: false,
25
29
  injectPolyfill: false,
26
30
  outputFormat: 'php',
31
+ outputFilename: null,
27
32
  useDefaults: true,
28
33
  },
29
34
  options
@@ -41,7 +46,9 @@ class DependencyExtractionWebpackPlugin {
41
46
  // Offload externalization work to the ExternalsPlugin.
42
47
  this.externalsPlugin = new webpack.ExternalsPlugin(
43
48
  'window',
44
- this.externalizeWpDeps.bind( this )
49
+ isWebpack4
50
+ ? this.externalizeWpDeps.bind( this )
51
+ : this.externalizeWpDepsV5.bind( this )
45
52
  );
46
53
  }
47
54
 
@@ -70,6 +77,10 @@ class DependencyExtractionWebpackPlugin {
70
77
  return callback();
71
78
  }
72
79
 
80
+ externalizeWpDepsV5( { context, request }, callback ) {
81
+ return this.externalizeWpDeps( context, request, callback );
82
+ }
83
+
73
84
  mapRequestToDependency( request ) {
74
85
  // Handle via options.requestToHandle first
75
86
  if ( typeof this.options.requestToHandle === 'function' ) {
@@ -104,116 +115,170 @@ class DependencyExtractionWebpackPlugin {
104
115
  apply( compiler ) {
105
116
  this.externalsPlugin.apply( compiler );
106
117
 
107
- compiler.hooks.emit.tap( this.constructor.name, ( compilation ) => {
108
- const {
109
- combineAssets,
110
- combinedOutputFile,
111
- injectPolyfill,
112
- outputFormat,
113
- } = this.options;
114
-
115
- const combinedAssetsData = {};
116
-
117
- // Process each entry point independently.
118
- for ( const [
119
- entrypointName,
120
- entrypoint,
121
- ] of compilation.entrypoints.entries() ) {
122
- const entrypointExternalizedWpDeps = new Set();
123
- if ( injectPolyfill ) {
124
- entrypointExternalizedWpDeps.add( 'wp-polyfill' );
118
+ if ( isWebpack4 ) {
119
+ compiler.hooks.emit.tap( this.constructor.name, ( compilation ) =>
120
+ this.addAssets( compilation, compiler )
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:
130
+ compiler.webpack.Compilation
131
+ .PROCESS_ASSETS_STAGE_ADDITIONAL,
132
+ },
133
+ () => this.addAssets( compilation, compiler )
134
+ );
125
135
  }
136
+ );
137
+ }
138
+ }
126
139
 
127
- const processModule = ( { userRequest } ) => {
128
- if ( this.externalizedDeps.has( userRequest ) ) {
129
- const scriptDependency = this.mapRequestToDependency(
130
- userRequest
131
- );
132
- entrypointExternalizedWpDeps.add( scriptDependency );
133
- }
134
- };
135
-
136
- // Search for externalized modules in all chunks.
137
- for ( const chunk of entrypoint.chunks ) {
138
- for ( const chunkModule of chunk.modulesIterable ) {
139
- processModule( chunkModule );
140
- // loop through submodules of ConcatenatedModule
141
- if ( chunkModule.modules ) {
142
- for ( const concatModule of chunkModule.modules ) {
143
- processModule( concatModule );
144
- }
140
+ addAssets( compilation, compiler ) {
141
+ const {
142
+ combineAssets,
143
+ combinedOutputFile,
144
+ externalizedReport,
145
+ injectPolyfill,
146
+ outputFormat,
147
+ outputFilename,
148
+ } = this.options;
149
+
150
+ // Dump actually externalized dependencies to a report file.
151
+ if ( externalizedReport ) {
152
+ const externalizedReportFile =
153
+ typeof externalizedReport === 'string'
154
+ ? externalizedReport
155
+ : defaultExternalizedReportFileName;
156
+ compilation.emitAsset(
157
+ externalizedReportFile,
158
+ new RawSource(
159
+ JSON.stringify( Array.from( this.externalizedDeps ).sort() )
160
+ )
161
+ );
162
+ }
163
+
164
+ const combinedAssetsData = {};
165
+
166
+ // Process each entry point independently.
167
+ for ( const [
168
+ entrypointName,
169
+ entrypoint,
170
+ ] of compilation.entrypoints.entries() ) {
171
+ const entrypointExternalizedWpDeps = new Set();
172
+ if ( injectPolyfill ) {
173
+ entrypointExternalizedWpDeps.add( 'wp-polyfill' );
174
+ }
175
+
176
+ const processModule = ( { userRequest } ) => {
177
+ if ( this.externalizedDeps.has( userRequest ) ) {
178
+ const scriptDependency = this.mapRequestToDependency(
179
+ userRequest
180
+ );
181
+ entrypointExternalizedWpDeps.add( scriptDependency );
182
+ }
183
+ };
184
+
185
+ // Search for externalized modules in all chunks.
186
+ for ( const chunk of entrypoint.chunks ) {
187
+ const modulesIterable = isWebpack4
188
+ ? chunk.modulesIterable
189
+ : compilation.chunkGraph.getChunkModules( chunk );
190
+ for ( const chunkModule of modulesIterable ) {
191
+ processModule( chunkModule );
192
+ // loop through submodules of ConcatenatedModule
193
+ if ( chunkModule.modules ) {
194
+ for ( const concatModule of chunkModule.modules ) {
195
+ processModule( concatModule );
145
196
  }
146
197
  }
147
198
  }
199
+ }
148
200
 
149
- const runtimeChunk = entrypoint.getRuntimeChunk();
150
-
151
- const assetData = {
152
- // Get a sorted array so we can produce a stable, stringified representation.
153
- dependencies: Array.from(
154
- entrypointExternalizedWpDeps
155
- ).sort(),
156
- version: runtimeChunk.hash,
157
- };
158
-
159
- const assetString = this.stringify( assetData );
160
-
161
- // Determine a filename for the asset file.
162
- const [ filename, query ] = entrypointName.split( '?', 2 );
163
- const buildFilename = compilation.getPath(
164
- compiler.options.output.filename,
165
- {
166
- chunk: runtimeChunk,
167
- filename,
168
- query,
169
- basename: basename( filename ),
170
- contentHash: createHash( 'md4' )
171
- .update( assetString )
172
- .digest( 'hex' ),
173
- }
174
- );
175
-
176
- if ( combineAssets ) {
177
- combinedAssetsData[ buildFilename ] = assetData;
178
- continue;
201
+ const entrypointChunk = isWebpack4
202
+ ? entrypoint.chunks.find( ( c ) => c.name === entrypointName )
203
+ : entrypoint.getEntrypointChunk();
204
+
205
+ const assetData = {
206
+ // Get a sorted array so we can produce a stable, stringified representation.
207
+ dependencies: Array.from( entrypointExternalizedWpDeps ).sort(),
208
+ version: entrypointChunk.hash,
209
+ };
210
+
211
+ const assetString = this.stringify( assetData );
212
+
213
+ // Determine a filename for the asset file.
214
+ const [ filename, query ] = entrypointName.split( '?', 2 );
215
+ const buildFilename = compilation.getPath(
216
+ compiler.options.output.filename,
217
+ {
218
+ chunk: entrypointChunk,
219
+ filename,
220
+ query,
221
+ basename: basename( filename ),
222
+ contentHash: createHash( 'md4' )
223
+ .update( assetString )
224
+ .digest( 'hex' ),
179
225
  }
226
+ );
180
227
 
181
- const assetFilename = buildFilename.replace(
228
+ if ( combineAssets ) {
229
+ combinedAssetsData[ buildFilename ] = assetData;
230
+ continue;
231
+ }
232
+
233
+ let assetFilename;
234
+
235
+ if ( outputFilename ) {
236
+ assetFilename = compilation.getPath( outputFilename, {
237
+ chunk: entrypointChunk,
238
+ filename,
239
+ query,
240
+ basename: basename( filename ),
241
+ contentHash: createHash( 'md4' )
242
+ .update( assetString )
243
+ .digest( 'hex' ),
244
+ } );
245
+ } else {
246
+ assetFilename = buildFilename.replace(
182
247
  /\.js$/i,
183
248
  '.asset.' + ( outputFormat === 'php' ? 'php' : 'json' )
184
249
  );
185
-
186
- // Add source and file into compilation for webpack to output.
187
- compilation.assets[ assetFilename ] = new RawSource(
188
- assetString
189
- );
190
- runtimeChunk.files.push( assetFilename );
191
250
  }
192
251
 
193
- if ( combineAssets ) {
194
- // Assert the `string` type for output path.
195
- // The type indicates the option may be `undefined`.
196
- // However, at this point in compilation, webpack has filled the options in if
197
- // they were not provided.
198
- const outputFolder = /** @type {{path:string}} */ ( compiler
199
- .options.output ).path;
200
-
201
- const assetsFilePath = path.resolve(
202
- outputFolder,
203
- combinedOutputFile ||
204
- 'assets.' + ( outputFormat === 'php' ? 'php' : 'json' )
205
- );
206
- const assetsFilename = path.relative(
207
- outputFolder,
208
- assetsFilePath
209
- );
252
+ // Add source and file into compilation for webpack to output.
253
+ compilation.assets[ assetFilename ] = new RawSource( assetString );
254
+ entrypointChunk.files[ isWebpack4 ? 'push' : 'add' ](
255
+ assetFilename
256
+ );
257
+ }
210
258
 
211
- // Add source into compilation for webpack to output.
212
- compilation.assets[ assetsFilename ] = new RawSource(
213
- this.stringify( combinedAssetsData )
214
- );
215
- }
216
- } );
259
+ if ( combineAssets ) {
260
+ // Assert the `string` type for output path.
261
+ // The type indicates the option may be `undefined`.
262
+ // However, at this point in compilation, webpack has filled the options in if
263
+ // they were not provided.
264
+ const outputFolder = /** @type {{path:string}} */ ( compiler.options
265
+ .output ).path;
266
+
267
+ const assetsFilePath = path.resolve(
268
+ outputFolder,
269
+ combinedOutputFile ||
270
+ 'assets.' + ( outputFormat === 'php' ? 'php' : 'json' )
271
+ );
272
+ const assetsFilename = path.relative(
273
+ outputFolder,
274
+ assetsFilePath
275
+ );
276
+
277
+ // Add source into compilation for webpack to output.
278
+ compilation.assets[ assetsFilename ] = new RawSource(
279
+ this.stringify( combinedAssetsData )
280
+ );
281
+ }
217
282
  }
218
283
  }
219
284
 
package/lib/types.d.ts CHANGED
@@ -11,8 +11,10 @@ declare interface DependencyExtractionWebpackPluginOptions {
11
11
  injectPolyfill?: boolean;
12
12
  useDefaults?: boolean;
13
13
  outputFormat?: 'php' | 'json';
14
+ outputFilename?: string | Function,
14
15
  requestToExternal?: ( request: string ) => string | string[] | undefined;
15
16
  requestToHandle?: ( request: string ) => string | undefined;
16
17
  combinedOutputFile?: string | null;
17
18
  combineAssets?: boolean;
19
+ externalizedReportFile?: string | undefined;
18
20
  }
package/lib/util.js CHANGED
@@ -34,6 +34,10 @@ function defaultRequestToExternal( request ) {
34
34
  return 'ReactDOM';
35
35
  }
36
36
 
37
+ if ( request.includes( 'react-refresh/runtime' ) ) {
38
+ return 'ReactRefreshRuntime';
39
+ }
40
+
37
41
  if ( BUNDLED_PACKAGES.includes( request ) ) {
38
42
  return undefined;
39
43
  }
@@ -66,6 +70,10 @@ function defaultRequestToHandle( request ) {
66
70
  return 'lodash';
67
71
  }
68
72
 
73
+ if ( request.includes( 'react-refresh/runtime' ) ) {
74
+ return 'wp-react-refresh-runtime';
75
+ }
76
+
69
77
  if ( request.startsWith( WORDPRESS_NAMESPACE ) ) {
70
78
  return 'wp-' + request.substring( WORDPRESS_NAMESPACE.length );
71
79
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/dependency-extraction-webpack-plugin",
3
- "version": "3.2.0",
3
+ "version": "3.2.3-next.33ec3857e2.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",
@@ -30,7 +30,7 @@
30
30
  "types": "lib/types.d.ts",
31
31
  "dependencies": {
32
32
  "json2php": "^0.0.4",
33
- "webpack-sources": "^2.2.0"
33
+ "webpack-sources": "^3.2.2"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "webpack": "^4.8.3 || ^5.0.0"
@@ -38,5 +38,5 @@
38
38
  "publishConfig": {
39
39
  "access": "public"
40
40
  },
41
- "gitHead": "743b70f86f1e75fd66a583bf659f2b2fe5daf1cc"
41
+ "gitHead": "51c7917ea7fac72953702f24d6daac87d99e7617"
42
42
  }