diff --git a/CHANGELOG.md b/CHANGELOG.md index 245179b79..092cc699f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix incorrectly generated CSS when using square brackets inside arbitrary properties ([#11709](https://github.com/tailwindlabs/tailwindcss/pull/11709)) - Make `content` optional for presets in TypeScript types ([#11730](https://github.com/tailwindlabs/tailwindcss/pull/11730)) - Handle variable colors that have variable fallback values ([#12049](https://github.com/tailwindlabs/tailwindcss/pull/12049)) +- Batch reading content files to prevent `too many open files` error ([#12079](https://github.com/tailwindlabs/tailwindcss/pull/12079)) ## [3.3.3] - 2023-07-13 diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js index 835c1622f..2933d6f3e 100644 --- a/src/lib/expandTailwindAtRules.js +++ b/src/lib/expandTailwindAtRules.js @@ -145,14 +145,26 @@ export default function expandTailwindAtRules(context) { // getClassCandidatesOxide(file, transformer(content), extractor, candidates, seen) // } } else { - await Promise.all( - context.changedContent.map(async ({ file, content, extension }) => { - let transformer = getTransformer(context.tailwindConfig, extension) - let extractor = getExtractor(context, extension) - content = file ? await fs.promises.readFile(file, 'utf8') : content - getClassCandidates(transformer(content), extractor, candidates, seen) - }) - ) + /** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */ + let regexParserContent = [] + + for (let item of context.changedContent) { + let transformer = getTransformer(context.tailwindConfig, item.extension) + let extractor = getExtractor(context, item.extension) + regexParserContent.push([item, { transformer, extractor }]) + } + + const BATCH_SIZE = 500 + + for (let i = 0; i < regexParserContent.length; i += BATCH_SIZE) { + let batch = regexParserContent.slice(i, i + BATCH_SIZE) + await Promise.all( + batch.map(async ([{ file, content }, { transformer, extractor }]) => { + content = file ? await fs.promises.readFile(file, 'utf8') : content + getClassCandidates(transformer(content), extractor, candidates, seen) + }) + ) + } } env.DEBUG && console.timeEnd('Reading changed files')