@@ -34,23 +34,9 @@ export default class Eleventy extends Core {
3434 // super(input, output, options, eleventyConfig);
3535 // }
3636
37- /**
38- * Sets the incremental build mode.
39- *
40- * @param {boolean } isIncremental - Shall Eleventy run in incremental build mode and only write the files that trigger watch updates
41- */
42- setIncrementalBuild ( isIncremental ) {
43- super . setIncrementalBuild ( isIncremental ) ;
44-
45- if ( this . #watchQueue) {
46- this . watchQueue . incremental = ! ! isIncremental ;
47- }
48- }
49-
5037 get watchQueue ( ) {
5138 if ( ! this . #watchQueue) {
5239 this . #watchQueue = new WatchQueue ( ) ;
53- this . #watchQueue. incremental = this . isIncremental ;
5440 }
5541 return this . #watchQueue;
5642 }
@@ -100,33 +86,12 @@ export default class Eleventy extends Core {
10086 * @param {string } changedFilePath - File that triggered a re-run (added or modified)
10187 * @param {boolean } [isResetConfig] - are we doing a config reset
10288 */
103- async #addFileToWatchQueue( changedFilePath , isResetConfig ) {
104- let isAdded = this . watchQueue . addToPendingQueue ( changedFilePath ) ;
105- if ( ! isAdded ) {
106- return ;
107- }
108-
109- // Currently this is only for 11ty.js deps but should be extended with usesGraph
110- let usedByDependants = [ ] ;
111- if ( this . watchTargets ) {
112- usedByDependants = this . watchTargets . getDependantsOf (
113- TemplatePath . addLeadingDotSlash ( changedFilePath ) ,
114- ) ;
115- }
89+ #resetFileInWatchQueue( changedFilePath , isResetConfig ) {
90+ // v3.1.0: `eleventy.templateModified` is no longer used internally
91+ // v4.0.0-alpha.8 `eleventy.templateModified` event removed
11692
117- let relevantLayouts = this . eleventyConfig . usesGraph . getLayoutsUsedBy ( changedFilePath ) ;
118-
119- // `eleventy.templateModified` is no longer used internally, remove in a future major version.
120- eventBus . emit ( "eleventy.templateModified" , changedFilePath , {
121- usedByDependants,
122- relevantLayouts,
123- } ) ;
124-
125- // These listeners are *global*, not cleared even on config reset
126- eventBus . emit ( "eleventy.resourceModified" , changedFilePath , usedByDependants , {
127- viaConfigReset : isResetConfig ,
128- relevantLayouts,
129- } ) ;
93+ // These listeners are *global*, not cleared even on config reset (v4.0.0-alpha.8 removed some arguments here)
94+ eventBus . emit ( "eleventy.resourceModified" , changedFilePath ) ;
13095
13196 this . config . events . emit ( "eleventy#templateModified" , changedFilePath ) ;
13297 }
@@ -176,27 +141,25 @@ export default class Eleventy extends Core {
176141 ) ;
177142 }
178143
179- async #rewatch( opts = { } ) {
180- let { skipIncremental } = opts ;
181-
144+ async #rewatch( ) {
182145 if ( this . watchQueue . isBuildRunning ( ) ) {
183146 // this.logger.forceLog("Waiting for previous build to finish…");
184147 return ;
185148 }
186149
187- if ( skipIncremental ) {
188- // skip incremental when pending queue size > 2 and has non-template files
189- this . unsetIncrementalFile ( ) ;
190- this . writer ?. resetIncrementalFile ( ) ;
191- this . watchQueue . setIncrementalOverride ( true ) ;
192- this . watchQueue . clearPendingQueue ( ) ;
193- }
194-
195150 this . watchQueue . startBuild ( ) ;
196151
197152 let queue = this . watchQueue . getActiveQueue ( ) ;
198153 let isResetConfig = this . #shouldResetConfig( queue ) ;
199- this . logger . forceLog ( "Build starting…" + ( isResetConfig ? " (configuration reset)" : "" ) ) ;
154+
155+ for ( let p of queue ) {
156+ this . #resetFileInWatchQueue( p , isResetConfig ) ;
157+ }
158+
159+ this . logger . forceLog (
160+ `Build starting${ queue . length > 1 ? ` (${ queue . length } queued changes)` : "" } …` +
161+ ( isResetConfig ? " (configuration reset)" : "" ) ,
162+ ) ;
200163
201164 await this . config . events . emit ( "beforeWatch" , queue ) ;
202165 await this . config . events . emit ( "eleventy.beforeWatch" , queue ) ;
@@ -241,15 +204,13 @@ export default class Eleventy extends Core {
241204 ) ;
242205 } ) ;
243206
244- let files = this . watchQueue . getActiveQueue ( ) ;
245-
246207 // Maps passthrough copy files to output URLs for CSS live reload
247208 let stylesheetUrls = new Set ( ) ;
248209 for ( let entry of passthroughCopyResults ) {
249210 for ( let filepath in entry . map ) {
250211 if (
251212 filepath . endsWith ( ".css" ) &&
252- files . includes ( TemplatePath . addLeadingDotSlash ( filepath ) )
213+ queue . includes ( TemplatePath . addLeadingDotSlash ( filepath ) )
253214 ) {
254215 stylesheetUrls . add (
255216 "/" + TemplatePath . stripLeadingSubPath ( entry . map [ filepath ] , this . outputDir ) ,
@@ -270,7 +231,7 @@ export default class Eleventy extends Core {
270231 } ) ;
271232
272233 await this . eleventyServe . reload ( {
273- files,
234+ files : queue ,
274235 subtype : onlyCssChanges ? "css" : undefined ,
275236 build : {
276237 stylesheets : Array . from ( stylesheetUrls ) ,
@@ -288,24 +249,7 @@ export default class Eleventy extends Core {
288249 // Re-fetch
289250 let pendingQueue = this . watchQueue . getPendingQueue ( ) ;
290251 if ( pendingQueue . length > 0 ) {
291- let hasNonTemplateFiles = Boolean (
292- pendingQueue . find ( ( path ) => ! this . directories . isTemplateFile ( path ) ) ,
293- ) ;
294- let skipIncremental = pendingQueue . length > 1 && hasNonTemplateFiles ;
295-
296- if ( ! skipIncremental && this . isIncremental ) {
297- this . logger . forceLog (
298- `Build queued for: ${ TemplatePath . stripLeadingDotSlash ( pendingQueue . slice ( 0 , 1 ) . pop ( ) ) } ${ pendingQueue . length > 1 ? ` (1/${ pendingQueue . length } changes)` : "" } ` ,
299- ) ;
300- } else {
301- this . logger . forceLog (
302- `Build queued… (${ pendingQueue . length } change${ pendingQueue . length !== 1 ? "s" : "" } )` ,
303- ) ;
304- }
305-
306- await this . #rewatch( {
307- skipIncremental,
308- } ) ;
252+ await this . #rewatch( ) ;
309253 } else if ( ! this . #interrupted) {
310254 // also logs in startWatch for initial build
311255 this . logger . forceLog ( `Waiting…` ) ;
@@ -329,36 +273,33 @@ export default class Eleventy extends Core {
329273 return this . bench . get ( "Watcher" ) ;
330274 }
331275
332- static async wait ( timeMs ) {
333- let { promise, resolve, reject } = withResolvers ( ) ;
276+ async waitThrottle ( ) {
277+ if ( this . #watchDelay) {
278+ clearTimeout ( this . #watchDelay) ;
279+ }
334280
335- let id = setTimeout ( resolve , timeMs ) ;
281+ if ( this . config . watchThrottleWaitTime > 0 ) {
282+ let { promise, resolve } = withResolvers ( ) ;
336283
337- await promise ;
284+ this . #watchDelay = setTimeout ( resolve , this . config . watchThrottleWaitTime ) ;
338285
339- return id ;
286+ return promise ;
287+ }
340288 }
341289
290+ // Triggers when files are modified on file system
342291 async triggerWatchRunForPath ( path ) {
343- path = TemplatePath . normalize ( path ) ;
292+ this . watchQueue . addToPendingQueue ( path ) ;
344293
345- try {
346- let isResetConfig = this . #shouldResetConfig( [ path ] ) ;
347- this . #addFileToWatchQueue( path , isResetConfig ) ;
348-
349- if ( this . #watchDelay) {
350- clearTimeout ( this . #watchDelay) ;
351- }
352-
353- if ( this . config . watchThrottleWaitTime ) {
354- this . #watchDelay = Eleventy . wait ( this . config . watchThrottleWaitTime ) ;
355- }
294+ await this . waitThrottle ( ) ;
356295
296+ try {
357297 await this . #rewatch( ) ;
358298 } catch ( e ) {
299+ this . watchQueue . finishBuild ( ) ;
300+
359301 if ( e instanceof EleventyBaseError ) {
360302 this . errorHandler . error ( e , "Eleventy watch error" ) ;
361- this . watchQueue . finishBuild ( ) ;
362303 } else {
363304 this . errorHandler . fatal ( e , "Eleventy fatal watch error" ) ;
364305 await this . close ( ) ;
@@ -420,34 +361,38 @@ export default class Eleventy extends Core {
420361 // Emulated passthrough copy logs from the server
421362 if ( ! this . eleventyServe . isEmulatedPassthroughCopyMatch ( path ) ) {
422363 this . logger . forceLog (
423- `File changed: ${ TemplatePath . stripLeadingDotSlash ( TemplatePath . standardizeFilePath ( path ) ) } ` ,
364+ `File changed: ${ TemplatePath . stripLeadingDotSlash ( TemplatePath . standardizeFilePath ( path ) ) } ${ this . watchQueue . isBuildRunning ( ) ? " (queued for next build)" : "" } ` ,
424365 ) ;
425366 }
426367
427- await this . triggerWatchRunForPath ( path ) ;
368+ // don’t await
369+ this . triggerWatchRunForPath ( path ) ;
428370 } ) ;
429371
430372 this . watcher . on ( "add" , async ( path ) => {
431373 // Emulated passthrough copy logs from the server
432374 if ( ! this . eleventyServe . isEmulatedPassthroughCopyMatch ( path ) ) {
433375 this . logger . forceLog (
434- `File added: ${ TemplatePath . stripLeadingDotSlash ( TemplatePath . standardizeFilePath ( path ) ) } ` ,
376+ `File added: ${ TemplatePath . stripLeadingDotSlash ( TemplatePath . standardizeFilePath ( path ) ) } ${ this . watchQueue . isBuildRunning ( ) ? " (queued for next build)" : "" } ` ,
435377 ) ;
436378 }
437379
438380 this . fileSystemSearch . add ( path ) ;
439- await this . triggerWatchRunForPath ( path ) ;
381+ // don’t await
382+ this . triggerWatchRunForPath ( path ) ;
440383 } ) ;
441384
442385 this . watcher . on ( "unlink" , async ( path ) => {
443386 // Emulated passthrough copy logs from the server
444387 if ( ! this . eleventyServe . isEmulatedPassthroughCopyMatch ( path ) ) {
445388 this . logger . forceLog (
446- `File deleted: ${ TemplatePath . stripLeadingDotSlash ( TemplatePath . standardizeFilePath ( path ) ) } ` ,
389+ `File deleted: ${ TemplatePath . stripLeadingDotSlash ( TemplatePath . standardizeFilePath ( path ) ) } ${ this . watchQueue . isBuildRunning ( ) ? " (queued for next build)" : "" } ` ,
447390 ) ;
448391 }
392+
449393 this . fileSystemSearch . delete ( path ) ;
450- await this . triggerWatchRunForPath ( path ) ;
394+ // don’t await
395+ this . triggerWatchRunForPath ( path ) ;
451396 } ) ;
452397 }
453398
@@ -588,8 +533,9 @@ Arguments:
588533 --incremental
589534 Only build the files that have changed. Best with watch/serve.
590535
591- --incremental=filename.md
592- Does not require watch/serve. Run an incremental build targeting a single file.
536+ --incremental=first.md,second.md
537+ --incremental=first.md --incremental=second.md
538+ Does not require watch/serve. Run an incremental build targeting one or more files.
593539
594540 --ignore-initial
595541 Start without a build; build when files change. Works best with watch/serve/incremental.
0 commit comments