mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
When you use a glob pattern in your `content` configuration that is too broad, it could be that you are accidentally including files that you didn't intend to include. E.g.: all of `node_modules` This has been documented in the [Tailwind CSS documentation](https://tailwindcss.com/docs/content-configuration#pattern-recommendations), but it's still something that a lot of people run into. This PR will try to detect those patterns and show a big warning to let you know if you may have done something wrong. We will show a warning if all of these conditions are true: 1. We detect `**` in the glob pattern 2. _and_ you didn't explicitly use `node_modules` in the glob pattern 3. _and_ we found files that include `node_modules` in the file path 4. _and_ no other globs exist that explicitly match the found file With these rules in place, the DX has nice trade-offs: 1. Very simple projects (that don't even have a `node_modules` folder), can simply use `./**/*` because while resolving actual files we won't see files from `node_modules` and thus won't warn. 2. If you use `./src/**` and you do have a `node_modules`, then we also won't complain (unless you have a `node_modules` folder in the `./src` folder). 3. If you work with a 3rd party library that you want to make changes to. Using an explicit match like `./node_modules/my-package/**/*` is allowed because `node_modules` is explicitly mentioned. Note: this only shows a warning, it does not stop the process entirely. The warning will be show when the very first file in the `node_modules` is detected. <!-- 👋 Hey, thanks for your interest in contributing to Tailwind! **Please ask first before starting work on any significant new features.** It's never a fun experience to have your pull request declined after investing a lot of time and effort into a new feature. To avoid this from happening, we request that contributors create an issue to first discuss any significant new features. This includes things like adding new utilities, creating new at-rules, or adding new component examples to the documentation. https://github.com/tailwindcss/tailwindcss/blob/master/.github/CONTRIBUTING.md --> --------- Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
153 lines
3.5 KiB
JavaScript
153 lines
3.5 KiB
JavaScript
let fs = require('fs')
|
|
let path = require('path')
|
|
let { spawn } = require('child_process')
|
|
let resolveToolRoot = require('./resolve-tool-root')
|
|
|
|
let SHOW_OUTPUT = false
|
|
|
|
let runningProcesses = []
|
|
|
|
afterEach(() => {
|
|
runningProcesses.splice(0).forEach((runningProcess) => runningProcess.stop())
|
|
})
|
|
|
|
function debounce(fn, ms) {
|
|
let state = { timer: undefined }
|
|
|
|
return (...args) => {
|
|
if (state.timer) clearTimeout(state.timer)
|
|
state.timer = setTimeout(() => fn(...args), ms)
|
|
}
|
|
}
|
|
|
|
module.exports = function $(command, options = {}) {
|
|
let abortController = new AbortController()
|
|
let root = resolveToolRoot()
|
|
let cwd = options.cwd ?? root
|
|
|
|
let args = options.shell
|
|
? [command]
|
|
: (() => {
|
|
let args = command.trim().split(/\s+/)
|
|
command = args.shift()
|
|
command =
|
|
command === 'node'
|
|
? command
|
|
: (function () {
|
|
let local = path.resolve(root, 'node_modules', '.bin', command)
|
|
if (fs.existsSync(local)) {
|
|
return local
|
|
}
|
|
|
|
let hoisted = path.resolve(root, '..', '..', 'node_modules', '.bin', command)
|
|
if (fs.existsSync(hoisted)) {
|
|
return hoisted
|
|
}
|
|
|
|
return `npx ${command}`
|
|
})()
|
|
return [command, args]
|
|
})()
|
|
|
|
let stdoutMessages = []
|
|
let stderrMessages = []
|
|
|
|
let stdoutActors = []
|
|
let stderrActors = []
|
|
|
|
function notifyNext(actors, messages) {
|
|
if (actors.length <= 0) return
|
|
let [next] = actors
|
|
|
|
for (let [idx, message] of messages.entries()) {
|
|
if (next.predicate(message)) {
|
|
messages.splice(0, idx + 1)
|
|
let actorIdx = actors.indexOf(next)
|
|
actors.splice(actorIdx, 1)
|
|
next.resolve()
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
let notifyNextStdoutActor = debounce(() => {
|
|
return notifyNext(stdoutActors, stdoutMessages)
|
|
}, 200)
|
|
|
|
let notifyNextStderrActor = debounce(() => {
|
|
return notifyNext(stderrActors, stderrMessages)
|
|
}, 200)
|
|
|
|
let runningProcess = new Promise((resolve, reject) => {
|
|
let child = spawn(...args, {
|
|
...options,
|
|
env: {
|
|
...process.env,
|
|
...options.env,
|
|
},
|
|
signal: abortController.signal,
|
|
cwd,
|
|
})
|
|
|
|
let stdout = ''
|
|
let stderr = ''
|
|
let combined = ''
|
|
|
|
child.stdout.on('data', (data) => {
|
|
if (SHOW_OUTPUT) {
|
|
console.log(data.toString())
|
|
}
|
|
stdoutMessages.push(data.toString())
|
|
notifyNextStdoutActor()
|
|
stdout += data
|
|
combined += data
|
|
})
|
|
|
|
child.stderr.on('data', (data) => {
|
|
if (SHOW_OUTPUT) {
|
|
console.error(data.toString())
|
|
}
|
|
stderrMessages.push(data.toString())
|
|
notifyNextStderrActor()
|
|
stderr += data
|
|
combined += data
|
|
})
|
|
|
|
child.on('error', (err) => {
|
|
if (err.name !== 'AbortError') {
|
|
throw err
|
|
}
|
|
})
|
|
|
|
child.on('close', (code, signal) => {
|
|
;(signal === 'SIGTERM' ? resolve : code === 0 ? resolve : reject)({
|
|
code,
|
|
stdout,
|
|
stderr,
|
|
combined,
|
|
})
|
|
})
|
|
})
|
|
|
|
runningProcesses.push(runningProcess)
|
|
|
|
return Object.assign(runningProcess, {
|
|
stop() {
|
|
abortController.abort()
|
|
return runningProcess
|
|
},
|
|
onStdout(predicate) {
|
|
return new Promise((resolve) => {
|
|
stdoutActors.push({ predicate, resolve })
|
|
notifyNextStdoutActor()
|
|
})
|
|
},
|
|
onStderr(predicate) {
|
|
return new Promise((resolve) => {
|
|
stderrActors.push({ predicate, resolve })
|
|
notifyNextStderrActor()
|
|
})
|
|
},
|
|
})
|
|
}
|