Skip to content

Commit

Permalink
Improve the performance when checking broad glob patterns.
Browse files Browse the repository at this point in the history
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.

Fixes tailwindlabs#14353
  • Loading branch information
ivanwonder committed Sep 20, 2024
1 parent e8614a2 commit 456b837
Showing 1 changed file with 7 additions and 3 deletions.
10 changes: 7 additions & 3 deletions src/lib/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,12 @@ export function createBroadPatternCheck(paths) {
return () => {}
}

const pathsMatcher = paths.map((path) => micromatch.matcher(path))
// All globs that explicitly contain any of the known large directories (e.g.:
// node_modules).
let explicitGlobs = paths.filter((path) => LARGE_DIRECTORIES_REGEX.test(path))
let explicitGlobsMatcher = paths
.filter((path) => LARGE_DIRECTORIES_REGEX.test(path))
.map((path) => micromatch.matcher(path))

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

// When a broad pattern is used, we have to double check that the file was
// not explicitly included in the globs.
let matchingGlob = paths.find((path) => micromatch.isMatch(file, path))
let matchingGlobIndex = pathsMatcher.findIndex((matcher) => matcher(file))
let matchingGlob = paths[matchingGlobIndex]
if (!matchingGlob) return // This should never happen

// Create relative paths to make the output a bit more readable.
Expand Down

0 comments on commit 456b837

Please sign in to comment.