Skip to content

Commit 066ccf8

Browse files
Improve the performance when checking broad glob patterns. (tailwindlabs#14481)
In a large project, it's costly to repeatedly call the function `micromatch.isMatch` that parses a glob pattern, creates a regular expression, and tests the path name against the regular expression. To optimize performance, it's important to cache the parsing and creating process before entering the loop. For example, the content configuration in a project looks like this `['./pages/**/*.{ts,js}', './node_modules/pages/**/*.{ts,js}']`. If the project has 10000 matched files and 10 glob patterns, the function `micromatch.isMatch` will be called 100000 times. --- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
1 parent e8614a2 commit 066ccf8

File tree

2 files changed

+23
-7
lines changed

2 files changed

+23
-7
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- Nothing yet!
10+
### Fixed
11+
12+
- Improve source glob verification performance ([#14481](https://github.com/tailwindlabs/tailwindcss/pull/14481))
1113

1214
## [3.4.12] - 2024-09-17
1315

src/lib/content.js

+20-6
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,22 @@ export function createBroadPatternCheck(paths) {
210210
return () => {}
211211
}
212212

213-
// All globs that explicitly contain any of the known large directories (e.g.:
214-
// node_modules).
215-
let explicitGlobs = paths.filter((path) => LARGE_DIRECTORIES_REGEX.test(path))
213+
// All glob matchers
214+
let matchers = []
215+
216+
// All glob matchers that explicitly contain any of the known large
217+
// directories (e.g.: node_modules).
218+
let explicitMatchers = []
219+
220+
// Create matchers for all paths
221+
for (let path of paths) {
222+
let matcher = micromatch.matcher(path)
223+
if (LARGE_DIRECTORIES_REGEX.test(path)) {
224+
explicitMatchers.push(matcher)
225+
}
226+
227+
matchers.push(matcher)
228+
}
216229

217230
// Keep track of whether we already warned about the broad pattern issue or
218231
// not. The `log.warn` function already does something similar where we only
@@ -225,12 +238,13 @@ export function createBroadPatternCheck(paths) {
225238
*/
226239
return (file) => {
227240
if (warned) return // Already warned about the broad pattern
228-
if (micromatch.isMatch(file, explicitGlobs)) return // Explicitly included, so we can skip further checks
241+
if (explicitMatchers.some((matcher) => matcher(file))) return // Explicitly included, so we can skip further checks
229242

230243
// When a broad pattern is used, we have to double check that the file was
231244
// not explicitly included in the globs.
232-
let matchingGlob = paths.find((path) => micromatch.isMatch(file, path))
233-
if (!matchingGlob) return // This should never happen
245+
let matchingGlobIndex = matchers.findIndex((matcher) => matcher(file))
246+
if (matchingGlobIndex === -1) return // This should never happen
247+
let matchingGlob = paths[matchingGlobIndex]
234248

235249
// Create relative paths to make the output a bit more readable.
236250
let relativeMatchingGlob = path.relative(process.cwd(), matchingGlob)

0 commit comments

Comments
 (0)