tailwindcss 3.4.7 → 3.4.8

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,74 @@ export function resolvedChangedContent(context, candidateFiles, fileModifiedMap)
181
183
  return [changedContent, mTimesToCommit]
182
184
  }
183
185
 
186
+ const LARGE_DIRECTORIES = [
187
+ 'node_modules', // Node
188
+ 'vendor', // PHP
189
+ ]
190
+
191
+ // Ensures that `node_modules` has to match as-is, otherwise `mynode_modules`
192
+ // would match as well, but that is not a known large directory.
193
+ const LARGE_DIRECTORIES_REGEX = new RegExp(
194
+ `(${LARGE_DIRECTORIES.map((dir) => String.raw`\b${dir}\b`).join('|')})`
195
+ )
196
+
197
+ /**
198
+ * @param {string[]} paths
199
+ */
200
+ export function createBroadPatternCheck(paths) {
201
+ // Detect whether a glob pattern might be too broad. This means that it:
202
+ // - Includes `**`
203
+ // - Does not include any of the known large directories (e.g.: node_modules)
204
+ let maybeBroadPattern = paths.some(
205
+ (path) => path.includes('**') && !LARGE_DIRECTORIES_REGEX.test(path)
206
+ )
207
+
208
+ // Didn't detect any potentially broad patterns, so we can skip further
209
+ // checks.
210
+ if (!maybeBroadPattern) {
211
+ return () => {}
212
+ }
213
+
214
+ // All globs that explicitly contain any of the known large directories (e.g.:
215
+ // node_modules).
216
+ let explicitGlobs = paths.filter((path) => LARGE_DIRECTORIES_REGEX.test(path))
217
+
218
+ // Keep track of whether we already warned about the broad pattern issue or
219
+ // not. The `log.warn` function already does something similar where we only
220
+ // output the log once. However, with this we can also skip the other checks
221
+ // when we already warned about the broad pattern.
222
+ let warned = false
223
+
224
+ /**
225
+ * @param {string} file
226
+ */
227
+ return (file) => {
228
+ if (warned) return // Already warned about the broad pattern
229
+ if (micromatch.isMatch(file, explicitGlobs)) return // Explicitly included, so we can skip further checks
230
+
231
+ // When a broad pattern is used, we have to double check that the file was
232
+ // not explicitly included in the globs.
233
+ let matchingGlob = paths.find((path) => micromatch.isMatch(file, path))
234
+ if (!matchingGlob) return // This should never happen
235
+
236
+ // Create relative paths to make the output a bit more readable.
237
+ let relativeMatchingGlob = path.relative(process.cwd(), matchingGlob)
238
+ if (relativeMatchingGlob[0] !== '.') relativeMatchingGlob = `./${relativeMatchingGlob}`
239
+
240
+ let largeDirectory = LARGE_DIRECTORIES.find((directory) => file.includes(directory))
241
+ if (largeDirectory) {
242
+ warned = true
243
+
244
+ log.warn('broad-content-glob-pattern', [
245
+ `Your \`content\` configuration includes a pattern which looks like it's accidentally matching all of \`${largeDirectory}\` and can cause serious performance issues.`,
246
+ `Pattern: \`${relativeMatchingGlob}\``,
247
+ `See our documentation for recommendations:`,
248
+ 'https://tailwindcss.com/docs/content-configuration#pattern-recommendations',
249
+ ])
250
+ }
251
+ }
252
+ }
253
+
184
254
  /**
185
255
  *
186
256
  * @param {ContentPath[]} candidateFiles
@@ -191,10 +261,14 @@ function resolveChangedFiles(candidateFiles, fileModifiedMap) {
191
261
  let paths = candidateFiles.map((contentPath) => contentPath.pattern)
192
262
  let mTimesToCommit = new Map()
193
263
 
264
+ let checkBroadPattern = createBroadPatternCheck(paths)
265
+
194
266
  let changedFiles = new Set()
195
267
  env.DEBUG && console.time('Finding changed files')
196
268
  let files = fastGlob.sync(paths, { absolute: true })
197
269
  for (let file of files) {
270
+ checkBroadPattern(file)
271
+
198
272
  let prevModified = fileModifiedMap.get(file) || -Infinity
199
273
  let modified = fs.statSync(file).mtimeMs
200
274