tailwindcss 3.4.7 → 3.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,7 @@ import { loadAutoprefixer, loadCssNano, loadPostcss, loadPostcssImport } from '.
12
12
  import { formatNodes, drainStdin, outputFile } from './utils'
13
13
  import { env } from '../../lib/sharedState'
14
14
  import resolveConfig from '../../../resolveConfig.js'
15
- import { parseCandidateFiles } from '../../lib/content.js'
15
+ import { createBroadPatternCheck, parseCandidateFiles } from '../../lib/content.js'
16
16
  import { createWatcher } from './watching.js'
17
17
  import fastGlob from 'fast-glob'
18
18
  import { findAtConfigPath } from '../../lib/findAtConfigPath.js'
@@ -184,7 +184,11 @@ let state = {
184
184
  // TODO: When we make the postcss plugin async-capable this can become async
185
185
  let files = fastGlob.sync(this.contentPatterns.all)
186
186
 
187
+ let checkBroadPattern = createBroadPatternCheck(this.contentPatterns.all)
188
+
187
189
  for (let file of files) {
190
+ checkBroadPattern(file)
191
+
188
192
  content.push({
189
193
  content: fs.readFileSync(path.resolve(file), 'utf8'),
190
194
  extension: path.extname(file).slice(1),
@@ -318,7 +322,7 @@ export async function createProcessor(args, cliConfigPath) {
318
322
  return fs.promises.readFile(path.resolve(input), 'utf8')
319
323
  }
320
324
 
321
- // No input file provided, fallback to default atrules
325
+ // No input file provided, fallback to default at-rules
322
326
  return '@tailwind base; @tailwind components; @tailwind utilities'
323
327
  }
324
328
 
@@ -7,6 +7,8 @@ import fastGlob from 'fast-glob'
7
7
  import normalizePath from 'normalize-path'
8
8
  import { parseGlob } from '../util/parseGlob'
9
9
  import { env } from './sharedState'
10
+ import log from '../util/log'
11
+ import micromatch from 'micromatch'
10
12
 
11
13
  /** @typedef {import('../../types/config.js').RawFile} RawFile */
12
14
  /** @typedef {import('../../types/config.js').FilePath} FilePath */
@@ -181,6 +183,73 @@ export function resolvedChangedContent(context, candidateFiles, fileModifiedMap)
181
183
  return [changedContent, mTimesToCommit]
182
184
  }
183
185
 
186
+ const LARGE_DIRECTORIES = [
187
+ 'node_modules', // Node
188
+ ]
189
+
190
+ // Ensures that `node_modules` has to match as-is, otherwise `mynode_modules`
191
+ // would match as well, but that is not a known large directory.
192
+ const LARGE_DIRECTORIES_REGEX = new RegExp(
193
+ `(${LARGE_DIRECTORIES.map((dir) => String.raw`\b${dir}\b`).join('|')})`
194
+ )
195
+
196
+ /**
197
+ * @param {string[]} paths
198
+ */
199
+ export function createBroadPatternCheck(paths) {
200
+ // Detect whether a glob pattern might be too broad. This means that it:
201
+ // - Includes `**`
202
+ // - Does not include any of the known large directories (e.g.: node_modules)
203
+ let maybeBroadPattern = paths.some(
204
+ (path) => path.includes('**') && !LARGE_DIRECTORIES_REGEX.test(path)
205
+ )
206
+
207
+ // Didn't detect any potentially broad patterns, so we can skip further
208
+ // checks.
209
+ if (!maybeBroadPattern) {
210
+ return () => {}
211
+ }
212
+
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))
216
+
217
+ // Keep track of whether we already warned about the broad pattern issue or
218
+ // not. The `log.warn` function already does something similar where we only
219
+ // output the log once. However, with this we can also skip the other checks
220
+ // when we already warned about the broad pattern.
221
+ let warned = false
222
+
223
+ /**
224
+ * @param {string} file
225
+ */
226
+ return (file) => {
227
+ if (warned) return // Already warned about the broad pattern
228
+ if (micromatch.isMatch(file, explicitGlobs)) return // Explicitly included, so we can skip further checks
229
+
230
+ // When a broad pattern is used, we have to double check that the file was
231
+ // not explicitly included in the globs.
232
+ let matchingGlob = paths.find((path) => micromatch.isMatch(file, path))
233
+ if (!matchingGlob) return // This should never happen
234
+
235
+ // Create relative paths to make the output a bit more readable.
236
+ let relativeMatchingGlob = path.relative(process.cwd(), matchingGlob)
237
+ if (relativeMatchingGlob[0] !== '.') relativeMatchingGlob = `./${relativeMatchingGlob}`
238
+
239
+ let largeDirectory = LARGE_DIRECTORIES.find((directory) => file.includes(directory))
240
+ if (largeDirectory) {
241
+ warned = true
242
+
243
+ log.warn('broad-content-glob-pattern', [
244
+ `Your \`content\` configuration includes a pattern which looks like it's accidentally matching all of \`${largeDirectory}\` and can cause serious performance issues.`,
245
+ `Pattern: \`${relativeMatchingGlob}\``,
246
+ `See our documentation for recommendations:`,
247
+ 'https://tailwindcss.com/docs/content-configuration#pattern-recommendations',
248
+ ])
249
+ }
250
+ }
251
+ }
252
+
184
253
  /**
185
254
  *
186
255
  * @param {ContentPath[]} candidateFiles
@@ -191,10 +260,14 @@ function resolveChangedFiles(candidateFiles, fileModifiedMap) {
191
260
  let paths = candidateFiles.map((contentPath) => contentPath.pattern)
192
261
  let mTimesToCommit = new Map()
193
262
 
263
+ let checkBroadPattern = createBroadPatternCheck(paths)
264
+
194
265
  let changedFiles = new Set()
195
266
  env.DEBUG && console.time('Finding changed files')
196
267
  let files = fastGlob.sync(paths, { absolute: true })
197
268
  for (let file of files) {
269
+ checkBroadPattern(file)
270
+
198
271
  let prevModified = fileModifiedMap.get(file) || -Infinity
199
272
  let modified = fs.statSync(file).mtimeMs
200
273