mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
* add `jiti` and `detective-typescript` dependencies
* use `jiti` and `detective-typescript`
Instead of `detective`, this way we will be able to support
`tailwind.config.ts` files and `ESM` files.
* use `@swc/core` instead of the built-in `babel` form `jiti`
* update changelog
* add `jiti` and `detective-typescript` dependencies to `stable`
* use `sucrase` to transform the configs
* add `sucrase` dependency to `stable` engine
* make loading the config easier
* use abstracted loading config utils
* WIP: make `load` related files public API
* use new config loader in PostCSS plugin
* add list of default config files to look for
* cleanup unused arguments
* find default config path when using CLI
* improve `init` command
* make eslint happy
* keep all files in `stubs` folder
* add `tailwind.config.js` stub file
* Initialize PostCSS config using the same format as Tailwind config
* Rename config content stubs to config.*.js
* Improve option descriptions for init options
* Remove unused code, remove `constants` file
* Fix TS warning
* apply CLI changes to the Oxide version
* update `--help` output in CLI tests
* WIP: make tests work on CI
TODO: Test all combinations of `--full`, `--ts`, `--postcss`, and `--esm`.
* wip
* remove unused `fs`
* Fix init tests
Did you know you could pass an empty args to a command? No? Me neither. ¯\_(ツ)_/¯
* bump `napi-derive`
* list extensions we are interested in
* no-op the `removeFile` if file doesn't exist
* ensure all `init` flags work
* ensure we cleanup the new files
* test ESM/CJS generation based on package.json
* remove unnecessary test
We are not displaying output in the `--help` anymore based on whether
`type: module` is present or not.
Therefore this test is unneeded.
* only look for `TypeScript` files when the entryFile is `TypeScript` as well
* refactor `load` to be `loadConfig`
This will allow you to use:
```js
import loadConfig from 'tailwindcss/loadConfig'
let config = loadConfig("/Users/xyz/projects/my-app/tailwind.config.ts")
```
The `loadConfig` function will return the configuration object based on
the given absolute path of a tailwind configuration file.
The given path can be a CJS, an ESM or a TS file.
* use the `config.full.js` stub instead of the `defaultConfig.stub.js` file
The root `defaultConfig` is still there for backwards compatibilty
reasons. But the `module.exports = requrie('./config.full.js')` was
causing some problems when actually using tailwindcss.
So dropped it instead.
* apply `load` -> `loadConfig` changes to `Oxide` engine CLI
* ensure we write the config file in the Oxide engine
* improve type in Oxide engine CLI
* catch errors instead of checking if the file exists
A little smaller but just for tests so doesn't matter too much here 👍
* ensure we publish the correct stub files
---------
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: Enzo Innocenzi <enzo@innocenzi.dev>
145 lines
3.4 KiB
JavaScript
145 lines
3.4 KiB
JavaScript
let fs = require('fs')
|
|
let path = require('path')
|
|
let { spawn } = require('child_process')
|
|
let resolveToolRoot = require('./resolve-tool-root')
|
|
|
|
let runningProcessess = []
|
|
|
|
afterEach(() => {
|
|
runningProcessess.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) => {
|
|
stdoutMessages.push(data.toString())
|
|
notifyNextStdoutActor()
|
|
stdout += data
|
|
combined += data
|
|
})
|
|
|
|
child.stderr.on('data', (data) => {
|
|
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,
|
|
})
|
|
})
|
|
})
|
|
|
|
runningProcessess.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()
|
|
})
|
|
},
|
|
})
|
|
}
|