1
1
/* eslint-disable class-methods-use-this */
2
2
3
- import webpack from 'webpack' ;
3
+ import webpack , { version as webpackVersion } from 'webpack' ;
4
+
4
5
import validateOptions from 'schema-utils' ;
5
6
6
7
import CssDependency from './CssDependency' ;
@@ -16,6 +17,8 @@ const {
16
17
util : { createHash } ,
17
18
} = webpack ;
18
19
20
+ const isWebpack4 = webpackVersion [ 0 ] === '4' ;
21
+
19
22
const MODULE_TYPE = 'css/mini-extract' ;
20
23
21
24
const pluginName = 'mini-css-extract-plugin' ;
@@ -26,6 +29,19 @@ const REGEXP_NAME = /\[name\]/i;
26
29
const REGEXP_PLACEHOLDERS = / \[ ( n a m e | i d | c h u n k h a s h ) \] / g;
27
30
const DEFAULT_FILENAME = '[name].css' ;
28
31
32
+ const compareIds = ( a , b ) => {
33
+ if ( typeof a !== typeof b ) {
34
+ return typeof a < typeof b ? - 1 : 1 ;
35
+ }
36
+ if ( a < b ) return - 1 ;
37
+ if ( a > b ) return 1 ;
38
+ return 0 ;
39
+ } ;
40
+
41
+ const compareModulesByIdentifier = ( a , b ) => {
42
+ return compareIds ( a . identifier ( ) , b . identifier ( ) ) ;
43
+ } ;
44
+
29
45
class CssDependencyTemplate {
30
46
apply ( ) { }
31
47
}
@@ -85,8 +101,8 @@ class CssModule extends webpack.Module {
85
101
callback ( ) ;
86
102
}
87
103
88
- updateHash ( hash ) {
89
- super . updateHash ( hash ) ;
104
+ updateHash ( hash , context ) {
105
+ super . updateHash ( hash , context ) ;
90
106
91
107
hash . update ( this . content ) ;
92
108
hash . update ( this . media || '' ) ;
@@ -141,94 +157,151 @@ class MiniCssExtractPlugin {
141
157
new CssDependencyTemplate ( )
142
158
) ;
143
159
144
- compilation . mainTemplate . hooks . renderManifest . tap (
145
- pluginName ,
146
- ( result , { chunk } ) => {
147
- const renderedModules = Array . from ( chunk . modulesIterable ) . filter (
148
- ( module ) => module . type === MODULE_TYPE
149
- ) ;
150
-
151
- if ( renderedModules . length > 0 ) {
152
- result . push ( {
153
- render : ( ) =>
154
- this . renderContentAsset (
155
- compilation ,
160
+ if ( isWebpack4 ) {
161
+ compilation . mainTemplate . hooks . renderManifest . tap (
162
+ pluginName ,
163
+ ( result , { chunk } ) => {
164
+ const { chunkGraph } = compilation ;
165
+
166
+ const renderedModules = Array . from (
167
+ this . getChunkModules ( chunk , chunkGraph )
168
+ ) . filter ( ( module ) => module . type === MODULE_TYPE ) ;
169
+
170
+ const filenameTemplate =
171
+ chunk . filenameTemplate ||
172
+ ( ( { chunk : chunkData } ) =>
173
+ this . options . moduleFilename ( chunkData ) ) ;
174
+
175
+ if ( renderedModules . length > 0 ) {
176
+ result . push ( {
177
+ render : ( ) =>
178
+ this . renderContentAsset (
179
+ compilation ,
180
+ chunk ,
181
+ renderedModules ,
182
+ compilation . runtimeTemplate . requestShortener
183
+ ) ,
184
+ filenameTemplate,
185
+ pathOptions : {
156
186
chunk,
157
- renderedModules ,
158
- compilation . runtimeTemplate . requestShortener
159
- ) ,
160
- filenameTemplate : ( { chunk : chunkData } ) =>
161
- this . options . moduleFilename ( chunkData ) ,
162
- pathOptions : {
163
- chunk,
164
- contentHashType : MODULE_TYPE ,
165
- } ,
166
- identifier : `${ pluginName } .${ chunk . id } ` ,
167
- hash : chunk . contentHash [ MODULE_TYPE ] ,
168
- } ) ;
187
+ contentHashType : MODULE_TYPE ,
188
+ } ,
189
+ identifier : `${ pluginName } .${ chunk . id } ` ,
190
+ hash : chunk . contentHash [ MODULE_TYPE ] ,
191
+ } ) ;
192
+ }
169
193
}
170
- }
171
- ) ;
172
-
173
- compilation . chunkTemplate . hooks . renderManifest . tap (
174
- pluginName ,
175
- ( result , { chunk } ) => {
176
- const renderedModules = Array . from ( chunk . modulesIterable ) . filter (
177
- ( module ) => module . type === MODULE_TYPE
178
- ) ;
194
+ ) ;
179
195
180
- if ( renderedModules . length > 0 ) {
181
- result . push ( {
182
- render : ( ) =>
183
- this . renderContentAsset (
184
- compilation ,
196
+ compilation . chunkTemplate . hooks . renderManifest . tap (
197
+ pluginName ,
198
+ ( result , { chunk } ) => {
199
+ const { chunkGraph } = compilation ;
200
+
201
+ const renderedModules = Array . from (
202
+ this . getChunkModules ( chunk , chunkGraph )
203
+ ) . filter ( ( module ) => module . type === MODULE_TYPE ) ;
204
+
205
+ const filenameTemplate =
206
+ chunk . filenameTemplate || this . options . chunkFilename ;
207
+
208
+ if ( renderedModules . length > 0 ) {
209
+ result . push ( {
210
+ render : ( ) =>
211
+ this . renderContentAsset (
212
+ compilation ,
213
+ chunk ,
214
+ renderedModules ,
215
+ compilation . runtimeTemplate . requestShortener
216
+ ) ,
217
+ filenameTemplate,
218
+ pathOptions : {
185
219
chunk,
186
- renderedModules ,
187
- compilation . runtimeTemplate . requestShortener
188
- ) ,
189
- filenameTemplate : this . options . chunkFilename ,
190
- pathOptions : {
191
- chunk,
192
- contentHashType : MODULE_TYPE ,
193
- } ,
194
- identifier : `${ pluginName } .${ chunk . id } ` ,
195
- hash : chunk . contentHash [ MODULE_TYPE ] ,
196
- } ) ;
220
+ contentHashType : MODULE_TYPE ,
221
+ } ,
222
+ identifier : `${ pluginName } .${ chunk . id } ` ,
223
+ hash : chunk . contentHash [ MODULE_TYPE ] ,
224
+ } ) ;
225
+ }
197
226
}
198
- }
199
- ) ;
200
-
201
- compilation . mainTemplate . hooks . hashForChunk . tap (
202
- pluginName ,
203
- ( hash , chunk ) => {
204
- const { chunkFilename } = this . options ;
205
-
206
- if ( REGEXP_CHUNKHASH . test ( chunkFilename ) ) {
207
- hash . update ( JSON . stringify ( chunk . getChunkMaps ( true ) . hash ) ) ;
227
+ ) ;
228
+ } else {
229
+ compilation . hooks . renderManifest . tap (
230
+ pluginName ,
231
+ ( result , { chunk } ) => {
232
+ const { chunkGraph } = compilation ;
233
+
234
+ const renderedModules = Array . from (
235
+ this . getChunkModules ( chunk , chunkGraph )
236
+ ) . filter ( ( module ) => module . type === MODULE_TYPE ) ;
237
+
238
+ const filenameTemplate =
239
+ chunk . filenameTemplate ||
240
+ chunk . hasRuntime ( ) ||
241
+ chunk . isOnlyInitial ( )
242
+ ? ( { chunk : chunkData } ) =>
243
+ this . options . moduleFilename ( chunkData )
244
+ : this . options . chunkFilename ;
245
+
246
+ if ( renderedModules . length > 0 ) {
247
+ result . push ( {
248
+ render : ( ) =>
249
+ this . renderContentAsset (
250
+ compilation ,
251
+ chunk ,
252
+ renderedModules ,
253
+ compilation . runtimeTemplate . requestShortener
254
+ ) ,
255
+ filenameTemplate,
256
+ pathOptions : {
257
+ chunk,
258
+ contentHashType : MODULE_TYPE ,
259
+ } ,
260
+ identifier : `${ pluginName } .${ chunk . id } ` ,
261
+ hash : chunk . contentHash [ MODULE_TYPE ] ,
262
+ } ) ;
263
+ }
208
264
}
265
+ ) ;
266
+ }
209
267
210
- if ( REGEXP_CONTENTHASH . test ( chunkFilename ) ) {
211
- hash . update (
212
- JSON . stringify (
213
- chunk . getChunkMaps ( true ) . contentHash [ MODULE_TYPE ] || { }
214
- )
215
- ) ;
216
- }
268
+ /*
269
+ * For webpack 5 this will be unneeded once the logic uses a RuntimeModule
270
+ * as the content of runtime modules is hashed and added to the chunk hash automatically
271
+ * */
272
+ if ( isWebpack4 ) {
273
+ compilation . mainTemplate . hooks . hashForChunk . tap (
274
+ pluginName ,
275
+ ( hash , chunk ) => {
276
+ const { chunkFilename } = this . options ;
277
+
278
+ if ( REGEXP_CHUNKHASH . test ( chunkFilename ) ) {
279
+ hash . update ( JSON . stringify ( chunk . getChunkMaps ( true ) . hash ) ) ;
280
+ }
281
+
282
+ if ( REGEXP_CONTENTHASH . test ( chunkFilename ) ) {
283
+ hash . update (
284
+ JSON . stringify (
285
+ chunk . getChunkMaps ( true ) . contentHash [ MODULE_TYPE ] || { }
286
+ )
287
+ ) ;
288
+ }
217
289
218
- if ( REGEXP_NAME . test ( chunkFilename ) ) {
219
- hash . update ( JSON . stringify ( chunk . getChunkMaps ( true ) . name ) ) ;
290
+ if ( REGEXP_NAME . test ( chunkFilename ) ) {
291
+ hash . update ( JSON . stringify ( chunk . getChunkMaps ( true ) . name ) ) ;
292
+ }
220
293
}
221
- }
222
- ) ;
294
+ ) ;
295
+ }
223
296
224
297
compilation . hooks . contentHash . tap ( pluginName , ( chunk ) => {
225
- const { outputOptions } = compilation ;
298
+ const { outputOptions, chunkGraph } = compilation ;
226
299
const { hashFunction, hashDigest, hashDigestLength } = outputOptions ;
227
300
const hash = createHash ( hashFunction ) ;
228
301
229
- for ( const m of chunk . modulesIterable ) {
302
+ for ( const m of this . getChunkModules ( chunk , chunkGraph ) ) {
230
303
if ( m . type === MODULE_TYPE ) {
231
- m . updateHash ( hash ) ;
304
+ m . updateHash ( hash , { chunkGraph } ) ;
232
305
}
233
306
}
234
307
@@ -242,7 +315,7 @@ class MiniCssExtractPlugin {
242
315
const { mainTemplate } = compilation ;
243
316
244
317
mainTemplate . hooks . localVars . tap ( pluginName , ( source , chunk ) => {
245
- const chunkMap = this . getCssChunkObject ( chunk ) ;
318
+ const chunkMap = this . getCssChunkObject ( chunk , compilation ) ;
246
319
247
320
if ( Object . keys ( chunkMap ) . length > 0 ) {
248
321
return Template . asString ( [
@@ -263,17 +336,25 @@ class MiniCssExtractPlugin {
263
336
mainTemplate . hooks . requireEnsure . tap (
264
337
pluginName ,
265
338
( source , chunk , hash ) => {
266
- const chunkMap = this . getCssChunkObject ( chunk ) ;
339
+ const chunkMap = this . getCssChunkObject ( chunk , compilation ) ;
267
340
268
341
if ( Object . keys ( chunkMap ) . length > 0 ) {
342
+ const maintemplateObject = isWebpack4 ? mainTemplate : compilation ;
269
343
const chunkMaps = chunk . getChunkMaps ( ) ;
270
- const { crossOriginLoading } = mainTemplate . outputOptions ;
271
- const linkHrefPath = mainTemplate . getAssetPath (
344
+ const { crossOriginLoading } = maintemplateObject . outputOptions ;
345
+ const linkHrefPath = maintemplateObject . getAssetPath (
272
346
JSON . stringify ( this . options . chunkFilename ) ,
273
347
{
274
- hash : `" + ${ mainTemplate . renderCurrentHashCode ( hash ) } + "` ,
348
+ hash : isWebpack4
349
+ ? `" + ${ mainTemplate . renderCurrentHashCode ( hash ) } + "`
350
+ : `" + ${ webpack . RuntimeGlobals . getFullHash } + "` ,
275
351
hashWithLength : ( length ) =>
276
- `" + ${ mainTemplate . renderCurrentHashCode ( hash , length ) } + "` ,
352
+ isWebpack4
353
+ ? `" + ${ mainTemplate . renderCurrentHashCode (
354
+ hash ,
355
+ length
356
+ ) } + "`
357
+ : `" + ${ webpack . RuntimeGlobals . getFullHash } + "` ,
277
358
chunk : {
278
359
id : '" + chunkId + "' ,
279
360
hash : `" + ${ JSON . stringify ( chunkMaps . hash ) } [chunkId] + "` ,
@@ -334,7 +415,11 @@ class MiniCssExtractPlugin {
334
415
'promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {' ,
335
416
Template . indent ( [
336
417
`var href = ${ linkHrefPath } ;` ,
337
- `var fullhref = ${ mainTemplate . requireFn } .p + href;` ,
418
+ `var fullhref = ${
419
+ isWebpack4
420
+ ? mainTemplate . requireFn
421
+ : webpack . RuntimeGlobals . require
422
+ } .p + href;`,
338
423
'var existingLinkTags = document.getElementsByTagName("link");' ,
339
424
'for(var i = 0; i < existingLinkTags.length; i++) {' ,
340
425
Template . indent ( [
@@ -395,11 +480,21 @@ class MiniCssExtractPlugin {
395
480
} ) ;
396
481
}
397
482
398
- getCssChunkObject ( mainChunk ) {
483
+ getChunkModules ( chunk , chunkGraph ) {
484
+ return typeof chunkGraph !== 'undefined'
485
+ ? chunkGraph . getOrderedChunkModulesIterable (
486
+ chunk ,
487
+ compareModulesByIdentifier
488
+ )
489
+ : chunk . modulesIterable ;
490
+ }
491
+
492
+ getCssChunkObject ( mainChunk , compilation ) {
399
493
const obj = { } ;
494
+ const { chunkGraph } = compilation ;
400
495
401
496
for ( const chunk of mainChunk . getAllAsyncChunks ( ) ) {
402
- for ( const module of chunk . modulesIterable ) {
497
+ for ( const module of this . getChunkModules ( chunk , chunkGraph ) ) {
403
498
if ( module . type === MODULE_TYPE ) {
404
499
obj [ chunk . id ] = 1 ;
405
500
break ;
@@ -414,8 +509,12 @@ class MiniCssExtractPlugin {
414
509
let usedModules ;
415
510
416
511
const [ chunkGroup ] = chunk . groupsIterable ;
512
+ const moduleIndexFunctionName =
513
+ typeof compilation . chunkGraph !== 'undefined'
514
+ ? 'getModulePostOrderIndex'
515
+ : 'getModuleIndex2' ;
417
516
418
- if ( typeof chunkGroup . getModuleIndex2 === 'function' ) {
517
+ if ( typeof chunkGroup [ moduleIndexFunctionName ] === 'function' ) {
419
518
// Store dependencies for modules
420
519
const moduleDependencies = new Map ( modules . map ( ( m ) => [ m , new Set ( ) ] ) ) ;
421
520
const moduleDependenciesReasons = new Map (
@@ -430,7 +529,7 @@ class MiniCssExtractPlugin {
430
529
. map ( ( m ) => {
431
530
return {
432
531
module : m ,
433
- index : cg . getModuleIndex2 ( m ) ,
532
+ index : cg [ moduleIndexFunctionName ] ( m ) ,
434
533
} ;
435
534
} )
436
535
// eslint-disable-next-line no-undefined
0 commit comments