1
- import { BuildContext , BuildState , BuildUpdateMessage } from './util/interfaces' ;
1
+ import { FILE_CHANGE_EVENT , FILE_DELETE_EVENT } from './util/constants' ;
2
+ import { BuildContext , BuildState , BuildUpdateMessage , ChangedFile } from './util/interfaces' ;
2
3
import { BuildError } from './util/errors' ;
4
+ import { readFileAsync } from './util/helpers' ;
3
5
import { bundle , bundleUpdate } from './bundle' ;
4
6
import { clean } from './clean' ;
5
7
import { copy } from './copy' ;
@@ -121,7 +123,7 @@ function buildDev(context: BuildContext) {
121
123
}
122
124
123
125
124
- export function buildUpdate ( event : string , filePath : string , context : BuildContext ) {
126
+ export function buildUpdate ( changedFiles : ChangedFile [ ] , context : BuildContext ) {
125
127
return new Promise ( resolve => {
126
128
const logger = new Logger ( 'build' ) ;
127
129
@@ -151,13 +153,20 @@ export function buildUpdate(event: string, filePath: string, context: BuildConte
151
153
// this one is useful when only a sass changed happened
152
154
// and the webpack only needs to livereload the css
153
155
// but does not need to do a full page refresh
154
- emit ( EventType . FileChange , resolveValue . changedFile ) ;
156
+ emit ( EventType . FileChange , resolveValue . changedFiles ) ;
155
157
}
156
158
157
- if ( filePath . endsWith ( '.ts' ) ) {
159
+ let requiresLintUpdate = false ;
160
+ for ( const changedFile of changedFiles ) {
161
+ if ( changedFile . ext === '.ts' && changedFile . event === 'ch' ) {
162
+ requiresLintUpdate = true ;
163
+ break ;
164
+ }
165
+ }
166
+ if ( requiresLintUpdate ) {
158
167
// a ts file changed, so let's lint it too, however
159
168
// this task should run as an after thought
160
- lintUpdate ( event , filePath , context ) ;
169
+ lintUpdate ( changedFiles , context ) ;
161
170
}
162
171
163
172
logger . finish ( 'green' , true ) ;
@@ -170,16 +179,16 @@ export function buildUpdate(event: string, filePath: string, context: BuildConte
170
179
171
180
// kick off all the build tasks
172
181
// and the tasks that can run parallel to all the build tasks
173
- const buildTasksPromise = buildUpdateTasks ( event , filePath , context ) ;
174
- const parallelTasksPromise = buildUpdateParallelTasks ( event , filePath , context ) ;
182
+ const buildTasksPromise = buildUpdateTasks ( changedFiles , context ) ;
183
+ const parallelTasksPromise = buildUpdateParallelTasks ( changedFiles , context ) ;
175
184
176
185
// whether it was resolved or rejected, we need to do the same thing
177
186
buildTasksPromise
178
187
. then ( buildTasksDone )
179
188
. catch ( ( ) => {
180
189
buildTasksDone ( {
181
190
requiresAppReload : false ,
182
- changedFile : filePath
191
+ changedFiles : changedFiles
183
192
} ) ;
184
193
} ) ;
185
194
} ) ;
@@ -189,18 +198,21 @@ export function buildUpdate(event: string, filePath: string, context: BuildConte
189
198
* Collection of all the build tasks than need to run
190
199
* Each task will only run if it's set with eacn BuildState.
191
200
*/
192
- function buildUpdateTasks ( event : string , filePath : string , context : BuildContext ) {
201
+ function buildUpdateTasks ( changedFiles : ChangedFile [ ] , context : BuildContext ) {
193
202
const resolveValue : BuildTaskResolveValue = {
194
203
requiresAppReload : false ,
195
- changedFile : filePath
204
+ changedFiles : [ ]
196
205
} ;
197
206
198
207
return Promise . resolve ( )
208
+ . then ( ( ) => {
209
+ return loadFiles ( changedFiles , context ) ;
210
+ } )
199
211
. then ( ( ) => {
200
212
// TEMPLATE
201
213
if ( context . templateState === BuildState . RequiresUpdate ) {
202
214
resolveValue . requiresAppReload = true ;
203
- return templateUpdate ( event , filePath , context ) ;
215
+ return templateUpdate ( changedFiles , context ) ;
204
216
}
205
217
// no template updates required
206
218
return Promise . resolve ( ) ;
@@ -213,7 +225,7 @@ function buildUpdateTasks(event: string, filePath: string, context: BuildContext
213
225
// we've already had a successful transpile once, only do an update
214
226
// not that we've also already started a transpile diagnostics only
215
227
// build that only needs to be completed by the end of buildUpdate
216
- return transpileUpdate ( event , filePath , context ) ;
228
+ return transpileUpdate ( changedFiles , context ) ;
217
229
218
230
} else if ( context . transpileState === BuildState . RequiresBuild ) {
219
231
// run the whole transpile
@@ -229,7 +241,7 @@ function buildUpdateTasks(event: string, filePath: string, context: BuildContext
229
241
if ( context . bundleState === BuildState . RequiresUpdate ) {
230
242
// we need to do a bundle update
231
243
resolveValue . requiresAppReload = true ;
232
- return bundleUpdate ( event , filePath , context ) ;
244
+ return bundleUpdate ( changedFiles , context ) ;
233
245
234
246
} else if ( context . bundleState === BuildState . RequiresBuild ) {
235
247
// we need to do a full bundle build
@@ -244,14 +256,30 @@ function buildUpdateTasks(event: string, filePath: string, context: BuildContext
244
256
// SASS
245
257
if ( context . sassState === BuildState . RequiresUpdate ) {
246
258
// we need to do a sass update
247
- return sassUpdate ( event , filePath , context ) . then ( outputCssFile => {
248
- resolveValue . changedFile = outputCssFile ;
259
+ return sassUpdate ( changedFiles , context ) . then ( outputCssFile => {
260
+ const changedFile : ChangedFile = {
261
+ event : FILE_CHANGE_EVENT ,
262
+ ext : '.css' ,
263
+ filePath : outputCssFile
264
+ } ;
265
+
266
+ context . fileCache . set ( outputCssFile , { path : outputCssFile , content : outputCssFile } ) ;
267
+
268
+ resolveValue . changedFiles . push ( changedFile ) ;
249
269
} ) ;
250
270
251
271
} else if ( context . sassState === BuildState . RequiresBuild ) {
252
272
// we need to do a full sass build
253
273
return sass ( context ) . then ( outputCssFile => {
254
- resolveValue . changedFile = outputCssFile ;
274
+ const changedFile : ChangedFile = {
275
+ event : FILE_CHANGE_EVENT ,
276
+ ext : '.css' ,
277
+ filePath : outputCssFile
278
+ } ;
279
+
280
+ context . fileCache . set ( outputCssFile , { path : outputCssFile , content : outputCssFile } ) ;
281
+
282
+ resolveValue . changedFiles . push ( changedFile ) ;
255
283
} ) ;
256
284
}
257
285
// no sass build required
@@ -262,17 +290,37 @@ function buildUpdateTasks(event: string, filePath: string, context: BuildContext
262
290
} ) ;
263
291
}
264
292
293
+ function loadFiles ( changedFiles : ChangedFile [ ] , context : BuildContext ) {
294
+ // UPDATE IN-MEMORY FILE CACHE
295
+ let promises : Promise < any > [ ] = [ ] ;
296
+ for ( const changedFile of changedFiles ) {
297
+ if ( changedFile . event === FILE_DELETE_EVENT ) {
298
+ // remove from the cache on delete
299
+ context . fileCache . remove ( changedFile . filePath ) ;
300
+ } else {
301
+ // load the latest since the file changed
302
+ const promise = readFileAsync ( changedFile . filePath ) ;
303
+ promises . push ( promise ) ;
304
+ promise . then ( ( content : string ) => {
305
+ context . fileCache . set ( changedFile . filePath , { path : changedFile . filePath , content : content } ) ;
306
+ } ) ;
307
+ }
308
+ }
309
+
310
+ return Promise . all ( promises ) ;
311
+ }
312
+
265
313
interface BuildTaskResolveValue {
266
314
requiresAppReload : boolean ;
267
- changedFile : string ;
315
+ changedFiles : ChangedFile [ ] ;
268
316
}
269
317
270
318
/**
271
319
* parallelTasks are for any tasks that can run parallel to the entire
272
320
* build, but we still need to make sure they've completed before we're
273
321
* all done, it's also possible there are no parallelTasks at all
274
322
*/
275
- function buildUpdateParallelTasks ( event : string , filePath : string , context : BuildContext ) {
323
+ function buildUpdateParallelTasks ( changedFiles : ChangedFile [ ] , context : BuildContext ) {
276
324
const parallelTasks : Promise < any > [ ] = [ ] ;
277
325
278
326
if ( context . transpileState === BuildState . RequiresUpdate ) {
0 commit comments