@@ -64,6 +64,59 @@ interface CompilationResult {
64
64
analyses : Array < TemplateAnalysis < keyof TemplateTypes > > ;
65
65
}
66
66
67
+ export class CssBlocksRewriterPlugin
68
+ extends Tapable
69
+ implements WebpackPlugin
70
+ {
71
+ parent : CssBlocksPlugin ;
72
+ compilationOptions : CssBlocksOptions ;
73
+ outputCssFile : string ;
74
+ name : any ;
75
+ debug : debugGenerator . IDebugger ;
76
+ pendingResult : Promise < StyleMapping | void > | undefined ;
77
+ constructor ( parent : CssBlocksPlugin ) {
78
+ super ( ) ;
79
+ this . debug = parent . debug ;
80
+ this . outputCssFile = parent . outputCssFile ;
81
+ this . name = parent . name ;
82
+ this . compilationOptions = parent . compilationOptions ;
83
+ this . parent = parent ;
84
+ parent . onCompilationExpiration ( ( ) => {
85
+ this . trace ( `resetting pending compilation.` ) ;
86
+ this . pendingResult = undefined ;
87
+ } ) ;
88
+ parent . onPendingCompilation ( ( pendingResult ) => {
89
+ this . trace ( `received pending compilation.` ) ;
90
+ this . pendingResult = pendingResult ;
91
+ } ) ;
92
+ }
93
+
94
+ apply ( compiler : WebpackCompiler ) {
95
+ compiler . plugin ( "compilation" , ( compilation : any ) => {
96
+ compilation . plugin ( "normal-module-loader" , ( context : any , mod : any ) => {
97
+ this . trace ( `preparing normal-module-loader for ${ mod . resource } ` ) ;
98
+ context . cssBlocks = context . cssBlocks || { mappings : { } , compilationOptions : this . compilationOptions } ;
99
+
100
+ // If we're already waiting for a css file of this name to finish compiling, throw.
101
+ if ( context . cssBlocks . mappings [ this . outputCssFile ] ) {
102
+ throw new Error ( `css conflict detected. Multiple compiles writing to ${ this . parent . outputCssFile } ?` ) ;
103
+ }
104
+
105
+ if ( this . pendingResult === undefined ) {
106
+ throw new Error ( `No pending result is available yet.` ) ;
107
+ }
108
+ context . cssBlocks . mappings [ this . outputCssFile ] = this . pendingResult ;
109
+ } ) ;
110
+ } ) ;
111
+ }
112
+
113
+ trace ( message : string ) {
114
+ message = message . replace ( this . parent . projectDir + "/" , "" ) ;
115
+ this . debug ( `[${ this . name } ] ${ message } ` ) ;
116
+ }
117
+
118
+ }
119
+
67
120
export class CssBlocksPlugin
68
121
extends Tapable
69
122
implements WebpackPlugin
@@ -74,7 +127,7 @@ export class CssBlocksPlugin
74
127
projectDir : string ;
75
128
outputCssFile : string ;
76
129
compilationOptions : CssBlocksOptions ;
77
- debug : ( message : string ) => void ;
130
+ debug : debugGenerator . IDebugger ;
78
131
79
132
constructor ( options : CssBlocksWebpackOptions ) {
80
133
super ( ) ;
@@ -89,13 +142,11 @@ export class CssBlocksPlugin
89
142
Object . assign ( { } , DEFAULT_OPTIONS , options . optimization ) ;
90
143
}
91
144
92
- apply ( compiler : WebpackCompiler ) {
93
- this . projectDir = compiler . options . context || this . projectDir ;
94
- let outputPath = compiler . options . output && compiler . options . output . path || this . projectDir ; // TODO What is the webpack default output directory?
95
- let assets : Assets = { } ;
96
-
97
- compiler . plugin ( "make" , ( compilation : any , cb : ( error ?: Error ) => void ) => {
145
+ getRewriterPlugin ( ) : CssBlocksRewriterPlugin {
146
+ return new CssBlocksRewriterPlugin ( this ) ;
147
+ }
98
148
149
+ private handleMake ( outputPath : string , assets : Assets , compilation : any , cb : ( error ?: Error ) => void ) {
99
150
// Start analysis with a clean analysis object
100
151
this . trace ( `starting analysis.` ) ;
101
152
this . analyzer . reset ( ) ;
@@ -169,30 +220,30 @@ export class CssBlocksPlugin
169
220
this . trace ( `notified of compilation failure` ) ;
170
221
} ) ;
171
222
172
- compilation . plugin ( "normal-module-loader" , ( context : any , mod : any ) => {
173
- this . trace ( `preparing normal-module-loader for ${ mod . resource } ` ) ;
174
- context . cssBlocks = context . cssBlocks || { mappings : { } , compilationOptions : this . compilationOptions } ;
175
-
176
- // If we're already waiting for a css file of this name to finish compiling, throw.
177
- if ( context . cssBlocks . mappings [ this . outputCssFile ] ) {
178
- throw new Error ( `css conflict detected. Multiple compiles writing to ${ this . outputCssFile } ` ) ;
179
- }
223
+ this . trace ( `notifying of pending compilation` ) ;
224
+ this . notifyPendingCompilation ( pendingResult ) ;
225
+ this . trace ( `notified of pending compilation` ) ;
226
+ }
180
227
181
- context . cssBlocks . mappings [ this . outputCssFile ] = pendingResult ;
228
+ apply ( compiler : WebpackCompiler ) {
229
+ this . projectDir = compiler . options . context || this . projectDir ;
230
+ let outputPath = compiler . options . output && compiler . options . output . path || this . projectDir ; // TODO What is the webpack default output directory?
231
+ let assets : Assets = { } ;
182
232
183
- } ) ;
233
+ compiler . plugin ( "this-compilation" , ( compilation ) => {
234
+ this . notifyCompilationExpiration ( ) ;
184
235
185
236
compilation . plugin ( 'additional-assets' , ( cb : ( ) => void ) => {
186
237
Object . assign ( compilation . assets , assets ) ;
187
238
cb ( ) ;
188
239
} ) ;
240
+ } ) ;
189
241
190
- this . trace ( `notifying of pending compilation` ) ;
191
- this . notifyPendingCompilation ( pendingResult ) ;
192
- this . trace ( `notified of pending compilation` ) ;
242
+ compiler . plugin ( "make" , this . handleMake . bind ( this , outputPath , assets ) ) ;
193
243
194
- } ) ;
244
+ this . getRewriterPlugin ( ) . apply ( compiler ) ;
195
245
}
246
+
196
247
private compileBlocks ( analysis : MetaTemplateAnalysis , cssOutputName : string ) : Promise < CompilationResult > {
197
248
let options : CssBlocksOptions = this . compilationOptions ;
198
249
let reader = new CssBlocksOptionsReader ( options ) ;
@@ -236,16 +287,32 @@ export class CssBlocksPlugin
236
287
message = message . replace ( this . projectDir + "/" , "" ) ;
237
288
this . debug ( `[${ this . name } ] ${ message } ` ) ;
238
289
}
290
+ /**
291
+ * Fires when the compilation promise is available.
292
+ */
239
293
onPendingCompilation ( handler : ( pendingResult : Promise < StyleMapping | void > ) => void ) {
240
294
this . plugin ( "block-compilation-pending" , handler ) ;
241
295
}
242
- notifyPendingCompilation ( pendingResult : Promise < StyleMapping | void > ) {
296
+ private notifyPendingCompilation ( pendingResult : Promise < StyleMapping | void > ) {
243
297
this . applyPlugins ( "block-compilation-pending" , pendingResult ) ;
244
298
}
299
+ /**
300
+ * Fires when the compilation is first started to let any listeners know that
301
+ * their current promise is no longer valid.
302
+ */
303
+ onCompilationExpiration ( handler : ( ) => void ) {
304
+ this . plugin ( "block-compilation-expired" , handler ) ;
305
+ }
306
+ private notifyCompilationExpiration ( ) {
307
+ this . applyPlugins ( "block-compilation-expired" ) ;
308
+ }
309
+ /**
310
+ * Fires when the compilation is done.
311
+ */
245
312
onComplete ( handler : ( result : BlockCompilationComplete | BlockCompilationError , cb : ( err : Error ) => void ) => void ) {
246
313
this . plugin ( "block-compilation-complete" , handler ) ;
247
314
}
248
- notifyComplete ( result : BlockCompilationComplete | BlockCompilationError , cb : ( err : Error ) => void ) {
315
+ private notifyComplete ( result : BlockCompilationComplete | BlockCompilationError , cb : ( err : Error ) => void ) {
249
316
this . applyPluginsAsync ( "block-compilation-complete" , result , cb ) ;
250
317
}
251
318
}
0 commit comments