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' ;
23import { BuildError } from './util/errors' ;
4+ import { readFileAsync } from './util/helpers' ;
35import { bundle , bundleUpdate } from './bundle' ;
46import { clean } from './clean' ;
57import { copy } from './copy' ;
@@ -121,7 +123,7 @@ function buildDev(context: BuildContext) {
121123}
122124
123125
124- export function buildUpdate ( event : string , filePath : string , context : BuildContext ) {
126+ export function buildUpdate ( changedFiles : ChangedFile [ ] , context : BuildContext ) {
125127 return new Promise ( resolve => {
126128 const logger = new Logger ( 'build' ) ;
127129
@@ -151,13 +153,20 @@ export function buildUpdate(event: string, filePath: string, context: BuildConte
151153 // this one is useful when only a sass changed happened
152154 // and the webpack only needs to livereload the css
153155 // but does not need to do a full page refresh
154- emit ( EventType . FileChange , resolveValue . changedFile ) ;
156+ emit ( EventType . FileChange , resolveValue . changedFiles ) ;
155157 }
156158
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 ) {
158167 // a ts file changed, so let's lint it too, however
159168 // this task should run as an after thought
160- lintUpdate ( event , filePath , context ) ;
169+ lintUpdate ( changedFiles , context ) ;
161170 }
162171
163172 logger . finish ( 'green' , true ) ;
@@ -170,16 +179,16 @@ export function buildUpdate(event: string, filePath: string, context: BuildConte
170179
171180 // kick off all the build tasks
172181 // 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 ) ;
175184
176185 // whether it was resolved or rejected, we need to do the same thing
177186 buildTasksPromise
178187 . then ( buildTasksDone )
179188 . catch ( ( ) => {
180189 buildTasksDone ( {
181190 requiresAppReload : false ,
182- changedFile : filePath
191+ changedFiles : changedFiles
183192 } ) ;
184193 } ) ;
185194 } ) ;
@@ -189,18 +198,21 @@ export function buildUpdate(event: string, filePath: string, context: BuildConte
189198 * Collection of all the build tasks than need to run
190199 * Each task will only run if it's set with eacn BuildState.
191200 */
192- function buildUpdateTasks ( event : string , filePath : string , context : BuildContext ) {
201+ function buildUpdateTasks ( changedFiles : ChangedFile [ ] , context : BuildContext ) {
193202 const resolveValue : BuildTaskResolveValue = {
194203 requiresAppReload : false ,
195- changedFile : filePath
204+ changedFiles : [ ]
196205 } ;
197206
198207 return Promise . resolve ( )
208+ . then ( ( ) => {
209+ return loadFiles ( changedFiles , context ) ;
210+ } )
199211 . then ( ( ) => {
200212 // TEMPLATE
201213 if ( context . templateState === BuildState . RequiresUpdate ) {
202214 resolveValue . requiresAppReload = true ;
203- return templateUpdate ( event , filePath , context ) ;
215+ return templateUpdate ( changedFiles , context ) ;
204216 }
205217 // no template updates required
206218 return Promise . resolve ( ) ;
@@ -213,7 +225,7 @@ function buildUpdateTasks(event: string, filePath: string, context: BuildContext
213225 // we've already had a successful transpile once, only do an update
214226 // not that we've also already started a transpile diagnostics only
215227 // build that only needs to be completed by the end of buildUpdate
216- return transpileUpdate ( event , filePath , context ) ;
228+ return transpileUpdate ( changedFiles , context ) ;
217229
218230 } else if ( context . transpileState === BuildState . RequiresBuild ) {
219231 // run the whole transpile
@@ -229,7 +241,7 @@ function buildUpdateTasks(event: string, filePath: string, context: BuildContext
229241 if ( context . bundleState === BuildState . RequiresUpdate ) {
230242 // we need to do a bundle update
231243 resolveValue . requiresAppReload = true ;
232- return bundleUpdate ( event , filePath , context ) ;
244+ return bundleUpdate ( changedFiles , context ) ;
233245
234246 } else if ( context . bundleState === BuildState . RequiresBuild ) {
235247 // we need to do a full bundle build
@@ -244,14 +256,30 @@ function buildUpdateTasks(event: string, filePath: string, context: BuildContext
244256 // SASS
245257 if ( context . sassState === BuildState . RequiresUpdate ) {
246258 // 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 ) ;
249269 } ) ;
250270
251271 } else if ( context . sassState === BuildState . RequiresBuild ) {
252272 // we need to do a full sass build
253273 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 ) ;
255283 } ) ;
256284 }
257285 // no sass build required
@@ -262,17 +290,37 @@ function buildUpdateTasks(event: string, filePath: string, context: BuildContext
262290 } ) ;
263291}
264292
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+
265313interface BuildTaskResolveValue {
266314 requiresAppReload : boolean ;
267- changedFile : string ;
315+ changedFiles : ChangedFile [ ] ;
268316}
269317
270318/**
271319 * parallelTasks are for any tasks that can run parallel to the entire
272320 * build, but we still need to make sure they've completed before we're
273321 * all done, it's also possible there are no parallelTasks at all
274322 */
275- function buildUpdateParallelTasks ( event : string , filePath : string , context : BuildContext ) {
323+ function buildUpdateParallelTasks ( changedFiles : ChangedFile [ ] , context : BuildContext ) {
276324 const parallelTasks : Promise < any > [ ] = [ ] ;
277325
278326 if ( context . transpileState === BuildState . RequiresUpdate ) {
0 commit comments