1
1
/* eslint-disable class-methods-use-this */
2
2
3
3
import { validate } from 'schema-utils' ;
4
+ import { SyncWaterfallHook } from 'tapable' ;
4
5
5
6
import schema from './plugin-options.json' ;
6
7
import { MODULE_TYPE , compareModulesByIdentifier } from './utils' ;
@@ -28,6 +29,8 @@ const cssModuleCache = new WeakMap();
28
29
*/
29
30
const cssDependencyCache = new WeakMap ( ) ;
30
31
32
+ const compilerHookMap = new WeakMap ( ) ;
33
+
31
34
class MiniCssExtractPlugin {
32
35
static getCssModule ( webpack ) {
33
36
/**
@@ -300,6 +303,20 @@ class MiniCssExtractPlugin {
300
303
return CssDependency ;
301
304
}
302
305
306
+ static getCompilerHooks ( compiler ) {
307
+ /**
308
+ * Prevent creation of multiple compiler hook maps to allow other integrations to get the current mapping.
309
+ */
310
+ let hooks = compilerHookMap . get ( compiler ) ;
311
+ if ( ! hooks ) {
312
+ hooks = {
313
+ customize : new SyncWaterfallHook ( [ 'attributes' ] ) ,
314
+ } ;
315
+ compilerHookMap . set ( compiler , hooks ) ;
316
+ }
317
+ return hooks ;
318
+ }
319
+
303
320
constructor ( options = { } ) {
304
321
validate ( schema , options , {
305
322
name : 'Mini CSS Extract Plugin' ,
@@ -847,30 +864,46 @@ class MiniCssExtractPlugin {
847
864
return null ;
848
865
}
849
866
867
+ const attributes = {
868
+ href : `${ RuntimeGlobals . publicPath } + ${ RuntimeGlobals . require } .miniCssF(chunkId)` ,
869
+ rel : JSON . stringify ( 'stylesheet' ) ,
870
+ onload : 'onLinkComplete' ,
871
+ onerror : 'onLinkComplete' ,
872
+ } ;
873
+
874
+ // Some attributes cannot be assigned through setAttribute, so we maintain
875
+ // a list of attributes that can safely be assigned through dot notation
876
+ const safeAttrs = [ 'href' , 'rel' , 'type' , 'onload' , 'onerror' ] ;
877
+
878
+ if ( this . runtimeOptions . linkType ) {
879
+ attributes . type = JSON . stringify ( this . runtimeOptions . linkType ) ;
880
+ }
881
+
882
+ if ( crossOriginLoading ) {
883
+ attributes . crossOrigin = `(linkTag.href.indexOf(window.location.origin + '/') !== 0)
884
+ ? ${ JSON . stringify ( crossOriginLoading ) }
885
+ : undefined` ;
886
+ }
887
+
888
+ // Append static attributes
889
+ if ( this . runtimeOptions . attributes ) {
890
+ Object . entries ( this . runtimeOptions . attributes ) . forEach (
891
+ ( [ key , value ] ) => {
892
+ attributes [ key ] = JSON . stringify ( value ) ;
893
+ }
894
+ ) ;
895
+ }
896
+
897
+ // Append dynamic attributes
898
+ MiniCssExtractPlugin . getCompilerHooks ( compiler ) . customize . call (
899
+ attributes
900
+ ) ;
901
+
850
902
return Template . asString ( [
851
903
`var createStylesheet = ${ runtimeTemplate . basicFunction (
852
904
'chunkId, fullhref, resolve, reject' ,
853
905
[
854
906
'var linkTag = document.createElement("link");' ,
855
- this . runtimeOptions . attributes
856
- ? Template . asString (
857
- Object . entries ( this . runtimeOptions . attributes ) . map (
858
- ( entry ) => {
859
- const [ key , value ] = entry ;
860
-
861
- return `linkTag.setAttribute(${ JSON . stringify (
862
- key
863
- ) } , ${ JSON . stringify ( value ) } );`;
864
- }
865
- )
866
- )
867
- : '' ,
868
- 'linkTag.rel = "stylesheet";' ,
869
- this . runtimeOptions . linkType
870
- ? `linkTag.type = ${ JSON . stringify (
871
- this . runtimeOptions . linkType
872
- ) } ;`
873
- : '' ,
874
907
`var onLinkComplete = ${ runtimeTemplate . basicFunction (
875
908
'event' ,
876
909
[
@@ -892,19 +925,17 @@ class MiniCssExtractPlugin {
892
925
'}' ,
893
926
]
894
927
) } `,
895
- 'linkTag.onerror = linkTag.onload = onLinkComplete;' ,
896
- 'linkTag.href = fullhref;' ,
897
- crossOriginLoading
898
- ? Template . asString ( [
899
- `if (linkTag.href.indexOf(window.location.origin + '/') !== 0) {` ,
900
- Template . indent (
901
- `linkTag.crossOrigin = ${ JSON . stringify (
902
- crossOriginLoading
903
- ) } ;`
904
- ) ,
905
- '}' ,
906
- ] )
907
- : '' ,
928
+ Template . asString (
929
+ Object . entries ( attributes ) . map ( ( [ key , value ] ) => {
930
+ if ( safeAttrs . includes ( key ) ) {
931
+ return `linkTag.${ key } = ${ value } ;` ;
932
+ }
933
+
934
+ return `linkTag.setAttribute(${ JSON . stringify (
935
+ key
936
+ ) } , ${ value } );`;
937
+ } )
938
+ ) ,
908
939
typeof this . runtimeOptions . insert !== 'undefined'
909
940
? typeof this . runtimeOptions . insert === 'function'
910
941
? `(${ this . runtimeOptions . insert . toString ( ) } )(linkTag)`
@@ -945,7 +976,7 @@ class MiniCssExtractPlugin {
945
976
'resolve, reject' ,
946
977
[
947
978
`var href = ${ RuntimeGlobals . require } .miniCssF(chunkId);` ,
948
- `var fullhref = ${ RuntimeGlobals . publicPath } + href;` ,
979
+ `var fullhref = ${ attributes . href } ;` ,
949
980
'if(findStylesheet(href, fullhref)) return resolve();' ,
950
981
'createStylesheet(chunkId, fullhref, resolve, reject);' ,
951
982
]
@@ -1016,7 +1047,7 @@ class MiniCssExtractPlugin {
1016
1047
'chunkId' ,
1017
1048
[
1018
1049
`var href = ${ RuntimeGlobals . require } .miniCssF(chunkId);` ,
1019
- `var fullhref = ${ RuntimeGlobals . publicPath } + href;` ,
1050
+ `var fullhref = ${ attributes . href } ;` ,
1020
1051
'var oldTag = findStylesheet(href, fullhref);' ,
1021
1052
'if(!oldTag) return;' ,
1022
1053
`promises.push(new Promise(${ runtimeTemplate . basicFunction (
0 commit comments