@@ -70,19 +70,24 @@ export default class CSSSplitWebpackPlugin {
70
70
* @param {Boolean|String } imports Truish to generate an additional import
71
71
* asset. When a boolean use the default name for the asset.
72
72
* @param {String } filename Control the generated split file name.
73
+ * @param {Boolean } defer Defer splitting until the `emit` phase. Normally
74
+ * only needed if something else in your pipeline is mangling things at
75
+ * the emit phase too.
73
76
* @param {Boolean } preserve True to keep the original unsplit file.
74
77
*/
75
78
constructor ( {
76
79
size = 4000 ,
77
80
imports = false ,
78
81
filename = '[name]-[part].[ext]' ,
79
82
preserve,
83
+ defer = false ,
80
84
} ) {
81
85
this . options = {
82
86
size,
83
87
imports : normalizeImports ( imports , preserve ) ,
84
88
filename : nameInterpolator ( filename ) ,
85
89
preserve,
90
+ defer,
86
91
} ;
87
92
}
88
93
@@ -121,6 +126,48 @@ export default class CSSSplitWebpackPlugin {
121
126
} ) ;
122
127
}
123
128
129
+ chunksMapping ( compilation , chunks , done ) {
130
+ const assets = compilation . assets ;
131
+ const publicPath = strip ( compilation . options . output . publicPath || './' ) ;
132
+ const promises = chunks . map ( ( chunk ) => {
133
+ const input = chunk . files . filter ( isCSS ) ;
134
+ const items = input . map ( ( name ) => this . file ( name , assets [ name ] ) ) ;
135
+ return Promise . all ( items ) . then ( ( entries ) => {
136
+ entries . forEach ( ( entry ) => {
137
+ // Skip the splitting operation for files that result in no
138
+ // split occuring.
139
+ if ( entry . chunks . length === 1 ) {
140
+ return ;
141
+ }
142
+ // Inject the new files into the chunk.
143
+ entry . chunks . forEach ( ( file ) => {
144
+ assets [ file . _name ] = file ;
145
+ chunk . files . push ( file . _name ) ;
146
+ } ) ;
147
+ const content = entry . chunks . map ( ( file ) => {
148
+ return `@import "${ publicPath } /${ file . _name } ";` ;
149
+ } ) . join ( '\n' ) ;
150
+ const imports = this . options . imports ( {
151
+ ...entry ,
152
+ content,
153
+ } ) ;
154
+ if ( ! this . options . preserve ) {
155
+ chunk . files . splice ( chunk . files . indexOf ( entry . file ) , 1 ) ;
156
+ delete assets [ entry . file ] ;
157
+ }
158
+ if ( imports ) {
159
+ assets [ imports ] = new RawSource ( content ) ;
160
+ chunk . files . push ( imports ) ;
161
+ }
162
+ } ) ;
163
+ return Promise . resolve ( ) ;
164
+ } ) ;
165
+ } ) ;
166
+ Promise . all ( promises ) . then ( ( ) => {
167
+ done ( ) ;
168
+ } , done ) ;
169
+ }
170
+
124
171
/**
125
172
* Run the plugin against a webpack compiler instance. Roughly it walks all
126
173
* the chunks searching for CSS files and when it finds one that needs to be
@@ -132,50 +179,21 @@ export default class CSSSplitWebpackPlugin {
132
179
* @returns {void }
133
180
*/
134
181
apply ( compiler : Object ) {
135
- // Only run on `this-compilation` to avoid injecting the plugin into
136
- // sub-compilers as happens when using the `extract-text-webpack-plugin`.
137
- compiler . plugin ( 'this-compilation' , ( compilation ) => {
138
- const assets = compilation . assets ;
139
- const publicPath = strip ( compilation . options . output . publicPath || './' ) ;
140
- compilation . plugin ( 'optimize-chunk-assets' , ( chunks , done ) => {
141
- const promises = chunks . map ( ( chunk ) => {
142
- const input = chunk . files . filter ( isCSS ) ;
143
- const items = input . map ( ( name ) => this . file ( name , assets [ name ] ) ) ;
144
- return Promise . all ( items ) . then ( ( entries ) => {
145
- entries . forEach ( ( entry ) => {
146
- // Skip the splitting operation for files that result in no
147
- // split occuring.
148
- if ( entry . chunks . length === 1 ) {
149
- return ;
150
- }
151
- // Inject the new files into the chunk.
152
- entry . chunks . forEach ( ( file ) => {
153
- assets [ file . _name ] = file ;
154
- chunk . files . push ( file . _name ) ;
155
- } ) ;
156
- const content = entry . chunks . map ( ( file ) => {
157
- return `@import "${ publicPath } /${ file . _name } ";` ;
158
- } ) . join ( '\n' ) ;
159
- const imports = this . options . imports ( {
160
- ...entry ,
161
- content,
162
- } ) ;
163
- if ( ! this . options . preserve ) {
164
- chunk . files . splice ( chunk . files . indexOf ( entry . file ) , 1 ) ;
165
- delete assets [ entry . file ] ;
166
- }
167
- if ( imports ) {
168
- assets [ imports ] = new RawSource ( content ) ;
169
- chunk . files . push ( imports ) ;
170
- }
171
- } ) ;
172
- return Promise . resolve ( ) ;
173
- } ) ;
182
+ if ( this . options . defer ) {
183
+ // Run on `emit` when user specifies the compiler phase
184
+ // Due to the incorrect css split + optimization behavior
185
+ // Expected: css split should happen after optimization
186
+ compiler . plugin ( 'emit' , ( compilation , done ) => {
187
+ return this . chunksMapping ( compilation , compilation . chunks , done ) ;
188
+ } ) ;
189
+ } else {
190
+ // Only run on `this-compilation` to avoid injecting the plugin into
191
+ // sub-compilers as happens when using the `extract-text-webpack-plugin`.
192
+ compiler . plugin ( 'this-compilation' , ( compilation ) => {
193
+ compilation . plugin ( 'optimize-chunk-assets' , ( chunks , done ) => {
194
+ return this . chunksMapping ( compilation , chunks , done ) ;
174
195
} ) ;
175
- Promise . all ( promises ) . then ( ( ) => {
176
- done ( ) ;
177
- } , done ) ;
178
196
} ) ;
179
- } ) ;
197
+ }
180
198
}
181
199
}
0 commit comments