diff --git a/README.md b/README.md index 4b334be..ecf4e98 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,26 @@ The default options passed to Critical are: Where `content` and `outputPath` are the arguments passed to [Eleventy transforms](https://www.11ty.dev/docs/config/#transforms) and `outputDir` is the output directory specified in your [Eleventy configuration](https://www.11ty.dev/docs/config/#output-directory). +### Maximum Concurrency + +Node.js will print a warning if more than 10 listeners are added for a particular event. This is a useful default that helps finding memory leaks. + +So that you don't see warnings when using eleventy-critical-css, the plugin respects the maximum number of listeners. You can use `process.setMaxListeners()` to increase the concurrency of eleventy-critical-css above the default, but be aware that it may be harder to detect memory leaks in your application as a result. + +```js +const criticalCss = require("eleventy-critical-css"); + +// Increase concurrency to 100 +process.setMaxListeners(100); + +// Unlimited concurrency +process.setMaxListeners(0); + +module.exports = function (eleventyConfig) { + eleventyConfig.addPlugin(criticalCss); +}; +``` + [npm-version-src]: https://img.shields.io/npm/v/eleventy-critical-css/latest.svg diff --git a/index.js b/index.js index 34c38d1..972428a 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,42 @@ const path = require("path"); +let maxListeners; +let currentListeners = 1; + +const functionsToProcess = []; + +const startProcessing = async () => { + if (maxListeners === undefined) { + maxListeners = process.getMaxListeners(); + } + + if (currentListeners < maxListeners) { + const entry = functionsToProcess.pop(); + + if (entry) { + currentListeners++; + const [resolve, reject, functionToProcess] = entry; + + functionToProcess() + .then(resolve) + .catch(reject) + .finally(() => { + currentListeners--; + startProcessing(); + }); + } + } +}; + +const processFunction = async (functionToProcess) => { + const promise = new Promise((resolve, reject) => { + functionsToProcess.push([resolve, reject, functionToProcess]); + }); + + startProcessing(); + return await promise; +}; + module.exports = function (config, options) { let critical; @@ -9,16 +46,20 @@ module.exports = function (config, options) { config.addTransform("critical-css", async function (content, outputPath) { if (outputPath && outputPath.endsWith(".html")) { - const { html } = await critical.generate({ - assetPaths: [path.dirname(outputPath)], - base: config.dir.output ?? "_site", - html: content, - inline: true, - rebase: ({ originalUrl }) => originalUrl, - ...options, - }); - - return html; + const functionToProcess = async () => { + const { html } = await critical.generate({ + assetPaths: [path.dirname(outputPath)], + base: config.dir?.output ?? "_site", + html: content, + inline: true, + rebase: ({ originalUrl }) => originalUrl, + ...options, + }); + + return html; + }; + + return await processFunction(functionToProcess); } return content;