diff --git a/src/UserConfig.js b/src/UserConfig.js index b5d3070ee..e4e33046d 100644 --- a/src/UserConfig.js +++ b/src/UserConfig.js @@ -251,6 +251,10 @@ class UserConfig { return this.events.emit(eventName, ...args); } + setEventEmitterMode(mode) { + this.events.setHandlerMode(mode); + } + /* * Universal getters */ diff --git a/src/Util/AsyncEventEmitter.js b/src/Util/AsyncEventEmitter.js index d14c35da9..cb3dd3dda 100644 --- a/src/Util/AsyncEventEmitter.js +++ b/src/Util/AsyncEventEmitter.js @@ -5,6 +5,8 @@ import { EventEmitter } from "node:events"; * It can be used for time measurements during a build. */ class AsyncEventEmitter extends EventEmitter { + #handlerMode = "parallel"; + // TypeScript slop constructor(...args) { super(...args); @@ -22,7 +24,20 @@ class AsyncEventEmitter extends EventEmitter { return []; } - return Promise.all(listeners.map((listener) => listener.apply(this, args))); + if (this.#handlerMode == "sequential") { + const result = []; + for (const listener of listeners) { + const returnValue = await listener.apply(this, args); + result.push(returnValue); + } + return result; + } else { + return Promise.all( + listeners.map((listener) => { + return listener.apply(this, args); + }), + ); + } } /** @@ -51,6 +66,10 @@ class AsyncEventEmitter extends EventEmitter { return this.emit.call(this, type, ...argsMap); } + + setHandlerMode(mode) { + this.#handlerMode = mode; + } } export default AsyncEventEmitter; diff --git a/test/EleventyTest.js b/test/EleventyTest.js index 6fec34aac..9badd6402 100644 --- a/test/EleventyTest.js +++ b/test/EleventyTest.js @@ -816,6 +816,33 @@ test("eleventy.before and eleventy.after Event Arguments, directories", async (t let results = await elev.toJSON(); }); +test("eleventy.after fires sequentially setting eventEmitterMode 'sequential'", async (t) => { + let reachFirst; + const firstReached = new Promise(resolve => reachFirst = resolve) + let next; + const firstResult = new Promise(resolve => next = resolve) + let secondCalled = false; + let elev = new Eleventy("./test/noop/", "./test/noop/_site", { + config: function (eleventyConfig) { + eleventyConfig.setEventEmitterMode('sequential') + eleventyConfig.on("eleventy.after", arg => { + reachFirst() + return firstResult; + }) + eleventyConfig.on("eleventy.after", arg => { + secondCalled = true; + }) + }, + }); + const resultPromise = elev.toJSON(); + await firstReached; + t.is(secondCalled, false) + next() + await 'microtask' + t.is(secondCalled, true) + await resultPromise; +}) + test("setInputDirectory config method #1503", async (t) => { t.plan(5); let elev = new Eleventy("./test/noop/", "./test/noop/_site", {