@@ -5,7 +5,10 @@ import webpack from 'webpack';
5
5
import sources from 'webpack-sources' ;
6
6
7
7
const { ConcatSource, SourceMapSource, OriginalSource } = sources ;
8
- const { Template, util : { createHash } } = webpack ;
8
+ const {
9
+ Template,
10
+ util : { createHash } ,
11
+ } = webpack ;
9
12
10
13
const NS = path . dirname ( fs . realpathSync ( __filename ) ) ;
11
14
@@ -97,7 +100,12 @@ class CssModule extends webpack.Module {
97
100
}
98
101
99
102
class CssModuleFactory {
100
- create ( { dependencies : [ dependency ] } , callback ) {
103
+ create (
104
+ {
105
+ dependencies : [ dependency ] ,
106
+ } ,
107
+ callback
108
+ ) {
101
109
callback ( null , new CssModule ( dependency ) ) ;
102
110
}
103
111
}
@@ -107,6 +115,8 @@ class MiniCssExtractPlugin {
107
115
this . options = Object . assign (
108
116
{
109
117
filename : '[name].css' ,
118
+ checkCssChunk : true ,
119
+ forceHookRuntime : false ,
110
120
} ,
111
121
options
112
122
) ;
@@ -241,9 +251,60 @@ class MiniCssExtractPlugin {
241
251
. substring ( 0 , hashDigestLength ) ;
242
252
} ) ;
243
253
const { mainTemplate } = compilation ;
244
- mainTemplate . hooks . localVars . tap ( pluginName , ( source , chunk ) => {
254
+ mainTemplate . hooks . localVars . tap ( pluginName , ( source , chunk , hash ) => {
245
255
const chunkMap = this . getCssChunkObject ( chunk ) ;
246
- if ( Object . keys ( chunkMap ) . length > 0 ) {
256
+ if ( this . options . forceHookRuntime || Object . keys ( chunkMap ) . length > 0 ) {
257
+ const chunkMaps = chunk . getChunkMaps ( ) ;
258
+ const linkHrefPath = mainTemplate . getAssetPath (
259
+ JSON . stringify ( this . options . chunkFilename ) ,
260
+ {
261
+ hash : `" + ${ mainTemplate . renderCurrentHashCode ( hash ) } + "` ,
262
+ hashWithLength : ( length ) =>
263
+ `" + ${ mainTemplate . renderCurrentHashCode ( hash , length ) } + "` ,
264
+ chunk : {
265
+ id : '" + chunkId + "' ,
266
+ hash : `" + ${ JSON . stringify ( chunkMaps . hash ) } [chunkId] + "` ,
267
+ hashWithLength ( length ) {
268
+ const shortChunkHashMap = Object . create ( null ) ;
269
+ for ( const chunkId of Object . keys ( chunkMaps . hash ) ) {
270
+ if ( typeof chunkMaps . hash [ chunkId ] === 'string' ) {
271
+ shortChunkHashMap [ chunkId ] = chunkMaps . hash [
272
+ chunkId
273
+ ] . substring ( 0 , length ) ;
274
+ }
275
+ }
276
+ return `" + ${ JSON . stringify (
277
+ shortChunkHashMap
278
+ ) } [chunkId] + "`;
279
+ } ,
280
+ contentHash : {
281
+ [ NS ] : `" + ${ JSON . stringify (
282
+ chunkMaps . contentHash [ NS ]
283
+ ) } [chunkId] + "`,
284
+ } ,
285
+ contentHashWithLength : {
286
+ [ NS ] : ( length ) => {
287
+ const shortContentHashMap = { } ;
288
+ const contentHash = chunkMaps . contentHash [ NS ] ;
289
+ for ( const chunkId of Object . keys ( contentHash ) ) {
290
+ if ( typeof contentHash [ chunkId ] === 'string' ) {
291
+ shortContentHashMap [ chunkId ] = contentHash [
292
+ chunkId
293
+ ] . substring ( 0 , length ) ;
294
+ }
295
+ }
296
+ return `" + ${ JSON . stringify (
297
+ shortContentHashMap
298
+ ) } [chunkId] + "`;
299
+ } ,
300
+ } ,
301
+ name : `" + (${ JSON . stringify (
302
+ chunkMaps . name
303
+ ) } [chunkId]||chunkId) + "`,
304
+ } ,
305
+ contentHashType : NS ,
306
+ }
307
+ ) ;
247
308
return Template . asString ( [
248
309
source ,
249
310
'' ,
@@ -253,120 +314,78 @@ class MiniCssExtractPlugin {
253
314
chunk . ids . map ( ( id ) => `${ JSON . stringify ( id ) } : 0` ) . join ( ',\n' )
254
315
) ,
255
316
'}' ,
317
+ '' ,
318
+ 'function cssLinkHref(chunkId) {' ,
319
+ Template . indent ( [
320
+ `var href = ${ linkHrefPath } ;` ,
321
+ `var fullhref = ${ mainTemplate . requireFn } .p + href;` ,
322
+ 'return {href: href, fullhref: fullhref};' ,
323
+ ] ) ,
324
+ '}' ,
256
325
] ) ;
257
326
}
258
327
return source ;
259
328
} ) ;
260
- mainTemplate . hooks . requireEnsure . tap (
261
- pluginName ,
262
- ( source , chunk , hash ) => {
263
- const chunkMap = this . getCssChunkObject ( chunk ) ;
264
- if ( Object . keys ( chunkMap ) . length > 0 ) {
265
- const chunkMaps = chunk . getChunkMaps ( ) ;
266
- const linkHrefPath = mainTemplate . getAssetPath (
267
- JSON . stringify ( this . options . chunkFilename ) ,
268
- {
269
- hash : `" + ${ mainTemplate . renderCurrentHashCode ( hash ) } + "` ,
270
- hashWithLength : ( length ) =>
271
- `" + ${ mainTemplate . renderCurrentHashCode ( hash , length ) } + "` ,
272
- chunk : {
273
- id : '" + chunkId + "' ,
274
- hash : `" + ${ JSON . stringify ( chunkMaps . hash ) } [chunkId] + "` ,
275
- hashWithLength ( length ) {
276
- const shortChunkHashMap = Object . create ( null ) ;
277
- for ( const chunkId of Object . keys ( chunkMaps . hash ) ) {
278
- if ( typeof chunkMaps . hash [ chunkId ] === 'string' ) {
279
- shortChunkHashMap [ chunkId ] = chunkMaps . hash [
280
- chunkId
281
- ] . substring ( 0 , length ) ;
282
- }
283
- }
284
- return `" + ${ JSON . stringify (
285
- shortChunkHashMap
286
- ) } [chunkId] + "`;
287
- } ,
288
- contentHash : {
289
- [ NS ] : `" + ${ JSON . stringify (
290
- chunkMaps . contentHash [ NS ]
291
- ) } [chunkId] + "`,
292
- } ,
293
- contentHashWithLength : {
294
- [ NS ] : ( length ) => {
295
- const shortContentHashMap = { } ;
296
- const contentHash = chunkMaps . contentHash [ NS ] ;
297
- for ( const chunkId of Object . keys ( contentHash ) ) {
298
- if ( typeof contentHash [ chunkId ] === 'string' ) {
299
- shortContentHashMap [ chunkId ] = contentHash [
300
- chunkId
301
- ] . substring ( 0 , length ) ;
302
- }
303
- }
304
- return `" + ${ JSON . stringify (
305
- shortContentHashMap
306
- ) } [chunkId] + "`;
307
- } ,
308
- } ,
309
- name : `" + (${ JSON . stringify (
310
- chunkMaps . name
311
- ) } [chunkId]||chunkId) + "`,
312
- } ,
313
- contentHashType : NS ,
314
- }
315
- ) ;
316
- return Template . asString ( [
317
- source ,
318
- '' ,
319
- `// ${ pluginName } CSS loading` ,
320
- `var cssChunks = ${ JSON . stringify ( chunkMap ) } ;` ,
321
- 'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);' ,
322
- 'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {' ,
329
+ mainTemplate . hooks . requireEnsure . tap ( pluginName , ( source , chunk ) => {
330
+ const chunkMap = this . getCssChunkObject ( chunk ) ;
331
+ if ( this . options . forceHookRuntime || Object . keys ( chunkMap ) . length > 0 ) {
332
+ const checkCssChunk = this . options . checkCssChunk ;
333
+ return Template . asString ( [
334
+ source ,
335
+ '' ,
336
+ `// ${ pluginName } CSS loading` ,
337
+ checkCssChunk ? `var cssChunks = ${ JSON . stringify ( chunkMap ) } ;` : '' ,
338
+ 'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);' ,
339
+ `else if(installedCssChunks[chunkId] !== 0${
340
+ checkCssChunk ? ' && cssChunks[chunkId]' : ''
341
+ } ) {`,
342
+ Template . indent ( [
343
+ 'promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {' ,
323
344
Template . indent ( [
324
- 'promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {' ,
345
+ 'var hrefData = cssLinkHref(chunkId);' ,
346
+ 'var href = hrefData.href;' ,
347
+ 'var fullhref = hrefData.fullhref;' ,
348
+ 'var existingLinkTags = document.getElementsByTagName("link");' ,
349
+ 'for(var i = 0; i < existingLinkTags.length; i++) {' ,
350
+ Template . indent ( [
351
+ 'var tag = existingLinkTags[i];' ,
352
+ 'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");' ,
353
+ 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();' ,
354
+ ] ) ,
355
+ '}' ,
356
+ 'var existingStyleTags = document.getElementsByTagName("style");' ,
357
+ 'for(var i = 0; i < existingStyleTags.length; i++) {' ,
325
358
Template . indent ( [
326
- `var href = ${ linkHrefPath } ;` ,
327
- `var fullhref = ${ mainTemplate . requireFn } .p + href;` ,
328
- 'var existingLinkTags = document.getElementsByTagName("link");' ,
329
- 'for(var i = 0; i < existingLinkTags.length; i++) {' ,
330
- Template . indent ( [
331
- 'var tag = existingLinkTags[i];' ,
332
- 'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");' ,
333
- 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();' ,
334
- ] ) ,
335
- '}' ,
336
- 'var existingStyleTags = document.getElementsByTagName("style");' ,
337
- 'for(var i = 0; i < existingStyleTags.length; i++) {' ,
338
- Template . indent ( [
339
- 'var tag = existingStyleTags[i];' ,
340
- 'var dataHref = tag.getAttribute("data-href");' ,
341
- 'if(dataHref === href || dataHref === fullhref) return resolve();' ,
342
- ] ) ,
343
- '}' ,
344
- 'var linkTag = document.createElement("link");' ,
345
- 'linkTag.rel = "stylesheet";' ,
346
- 'linkTag.type = "text/css";' ,
347
- 'linkTag.onload = resolve;' ,
348
- 'linkTag.onerror = function(event) {' ,
349
- Template . indent ( [
350
- 'var request = event && event.target && event.target.src || fullhref;' ,
351
- 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");' ,
352
- 'err.request = request;' ,
353
- 'reject(err);' ,
354
- ] ) ,
355
- '};' ,
356
- 'linkTag.href = fullhref;' ,
357
- 'var head = document.getElementsByTagName("head")[0];' ,
358
- 'head.appendChild(linkTag);' ,
359
+ 'var tag = existingStyleTags[i];' ,
360
+ 'var dataHref = tag.getAttribute("data-href");' ,
361
+ 'if(dataHref === href || dataHref === fullhref) return resolve();' ,
359
362
] ) ,
360
- '}).then(function() {' ,
361
- Template . indent ( [ 'installedCssChunks[chunkId] = 0;' ] ) ,
362
- '}));' ,
363
+ '}' ,
364
+ 'var linkTag = document.createElement("link");' ,
365
+ 'linkTag.rel = "stylesheet";' ,
366
+ 'linkTag.type = "text/css";' ,
367
+ 'linkTag.onload = resolve;' ,
368
+ 'linkTag.onerror = function(event) {' ,
369
+ Template . indent ( [
370
+ 'var request = event && event.target && event.target.src || fullhref;' ,
371
+ 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");' ,
372
+ 'err.request = request;' ,
373
+ 'reject(err);' ,
374
+ ] ) ,
375
+ '};' ,
376
+ 'linkTag.href = fullhref;' ,
377
+ 'var head = document.getElementsByTagName("head")[0];' ,
378
+ 'head.appendChild(linkTag);' ,
363
379
] ) ,
364
- '}' ,
365
- ] ) ;
366
- }
367
- return source ;
380
+ '}).then(function() {' ,
381
+ Template . indent ( [ 'installedCssChunks[chunkId] = 0;' ] ) ,
382
+ '}));' ,
383
+ ] ) ,
384
+ '}' ,
385
+ ] ) ;
368
386
}
369
- ) ;
387
+ return source ;
388
+ } ) ;
370
389
} ) ;
371
390
}
372
391
0 commit comments