Write to stdout when --output is omitted (#15656)
This commit is contained in:
parent
2f8c51774e
commit
f93c42fcfc
6 changed files with 170 additions and 5 deletions
|
|
@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Resolve values in functional utilities based on `@theme` options ([#15623](https://github.com/tailwindlabs/tailwindcss/pull/15623))
|
||||
- Discard invalid variants such as `data-checked-[selected=1]:*` ([#15629](https://github.com/tailwindlabs/tailwindcss/pull/15629))
|
||||
- Ensure `-outline-offset-*` utilities are suggested in IntelliSense ([#15646](https://github.com/tailwindlabs/tailwindcss/pull/15646))
|
||||
- Write to `stdout` when `--output` is set to `-` or omitted for `@tailwindcss/cli` ([#15656](https://github.com/tailwindlabs/tailwindcss/pull/15656))
|
||||
- Write to `stdout` when `--output -` flag is used for `@tailwindcss/cli` ([#15656](https://github.com/tailwindlabs/tailwindcss/pull/15656))
|
||||
- _Upgrade (experimental)_: Pretty print `--spacing(…)` to prevent ambiguity ([#15596](https://github.com/tailwindlabs/tailwindcss/pull/15596))
|
||||
|
||||
## [4.0.0-beta.9] - 2025-01-09
|
||||
|
|
|
|||
|
|
@ -95,6 +95,149 @@ describe.each([
|
|||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'production build — read input from stdin',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`{}`,
|
||||
'pnpm-workspace.yaml': yaml`
|
||||
#
|
||||
packages:
|
||||
- project-a
|
||||
`,
|
||||
'project-a/package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "workspace:^",
|
||||
"@tailwindcss/cli": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'project-a/index.html': html`
|
||||
<div
|
||||
class="underline 2xl:font-bold hocus:underline inverted:flex *:flex **:flex"
|
||||
></div>
|
||||
`,
|
||||
'project-a/plugin.js': js`
|
||||
module.exports = function ({ addVariant }) {
|
||||
addVariant('inverted', '@media (inverted-colors: inverted)')
|
||||
addVariant('hocus', ['&:focus', '&:hover'])
|
||||
}
|
||||
`,
|
||||
'project-a/tailwind.config.js': js`
|
||||
module.exports = {
|
||||
content: ['../project-b/src/**/*.js'],
|
||||
}
|
||||
`,
|
||||
'project-a/src/index.js': js`
|
||||
const className = "content-['project-a/src/index.js']"
|
||||
module.exports = { className }
|
||||
`,
|
||||
'project-b/src/index.html': html`
|
||||
<div class="flex" />
|
||||
`,
|
||||
'project-b/src/index.js': js`
|
||||
const className = "content-['project-b/src/index.js']"
|
||||
module.exports = { className }
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ root, fs, exec }) => {
|
||||
await exec(
|
||||
`${command} --input - --output dist/out.css`,
|
||||
{ cwd: path.join(root, 'project-a') },
|
||||
{
|
||||
stdin: css`
|
||||
@import 'tailwindcss/utilities';
|
||||
@config './tailwind.config.js';
|
||||
@source '../project-b/src/**/*.html';
|
||||
@plugin './plugin.js';
|
||||
`,
|
||||
},
|
||||
)
|
||||
|
||||
await fs.expectFileToContain('project-a/dist/out.css', [
|
||||
candidate`underline`,
|
||||
candidate`flex`,
|
||||
candidate`content-['project-a/src/index.js']`,
|
||||
candidate`content-['project-b/src/index.js']`,
|
||||
candidate`inverted:flex`,
|
||||
candidate`hocus:underline`,
|
||||
candidate`*:flex`,
|
||||
candidate`**:flex`,
|
||||
])
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'production build — (write to stdout)',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`{}`,
|
||||
'pnpm-workspace.yaml': yaml`
|
||||
#
|
||||
packages:
|
||||
- project-a
|
||||
`,
|
||||
'project-a/package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "workspace:^",
|
||||
"@tailwindcss/cli": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'project-a/index.html': html`
|
||||
<div
|
||||
class="underline 2xl:font-bold hocus:underline inverted:flex *:flex **:flex"
|
||||
></div>
|
||||
`,
|
||||
'project-a/plugin.js': js`
|
||||
module.exports = function ({ addVariant }) {
|
||||
addVariant('inverted', '@media (inverted-colors: inverted)')
|
||||
addVariant('hocus', ['&:focus', '&:hover'])
|
||||
}
|
||||
`,
|
||||
'project-a/tailwind.config.js': js`
|
||||
module.exports = {
|
||||
content: ['../project-b/src/**/*.js'],
|
||||
}
|
||||
`,
|
||||
'project-a/src/index.css': css`
|
||||
@import 'tailwindcss/utilities';
|
||||
@config '../tailwind.config.js';
|
||||
@source '../../project-b/src/**/*.html';
|
||||
@plugin '../plugin.js';
|
||||
`,
|
||||
'project-a/src/index.js': js`
|
||||
const className = "content-['project-a/src/index.js']"
|
||||
module.exports = { className }
|
||||
`,
|
||||
'project-b/src/index.html': html`
|
||||
<div class="flex" />
|
||||
`,
|
||||
'project-b/src/index.js': js`
|
||||
const className = "content-['project-b/src/index.js']"
|
||||
module.exports = { className }
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ root, expect, exec }) => {
|
||||
let stdout = await exec(`${command} --input src/index.css --output -`, {
|
||||
cwd: path.join(root, 'project-a'),
|
||||
})
|
||||
|
||||
expect(stdout).toContain(candidate`underline`)
|
||||
expect(stdout).toContain(candidate`flex`)
|
||||
expect(stdout).toContain(candidate`content-['project-a/src/index.js']`)
|
||||
expect(stdout).toContain(candidate`content-['project-b/src/index.js']`)
|
||||
expect(stdout).toContain(candidate`inverted:flex`)
|
||||
expect(stdout).toContain(candidate`hocus:underline`)
|
||||
expect(stdout).toContain(candidate`*:flex`)
|
||||
expect(stdout).toContain(candidate`**:flex`)
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'watch mode',
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ interface ChildProcessOptions {
|
|||
|
||||
interface ExecOptions {
|
||||
ignoreStdErr?: boolean
|
||||
stdin?: string
|
||||
}
|
||||
|
||||
interface TestConfig {
|
||||
|
|
@ -112,7 +113,7 @@ export function test(
|
|||
}
|
||||
if (debug) console.log(`> ${command}`)
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(
|
||||
let child = exec(
|
||||
command,
|
||||
{
|
||||
cwd,
|
||||
|
|
@ -134,6 +135,10 @@ export function test(
|
|||
}
|
||||
},
|
||||
)
|
||||
if (execOptions.stdin) {
|
||||
child.stdin?.write(execOptions.stdin)
|
||||
child.stdin?.end()
|
||||
}
|
||||
})
|
||||
},
|
||||
async spawn(command: string, childProcessOptions: ChildProcessOptions = {}) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export function options() {
|
|||
type: 'string',
|
||||
description: 'Output file',
|
||||
alias: '-o',
|
||||
default: '-',
|
||||
},
|
||||
'--watch': {
|
||||
type: 'boolean | string',
|
||||
|
|
@ -72,8 +73,10 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
|
|||
|
||||
let base = path.resolve(args['--cwd'])
|
||||
|
||||
// Resolve the output as an absolute path.
|
||||
if (args['--output']) {
|
||||
// Resolve the output as an absolute path. If the output is a `-`, then we
|
||||
// don't need to resolve it because this is a flag to indicate that we want to
|
||||
// use `stdout` instead.
|
||||
if (args['--output'] && args['--output'] !== '-') {
|
||||
args['--output'] = path.resolve(base, args['--output'])
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +132,7 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
|
|||
|
||||
// Write the output
|
||||
DEBUG && I.start('Write output')
|
||||
if (args['--output']) {
|
||||
if (args['--output'] && args['--output'] !== '-') {
|
||||
await outputFile(args['--output'], output)
|
||||
} else {
|
||||
println(output)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ if (command) {
|
|||
//
|
||||
// - `tailwindcss -o output.css` // should run the build command, not show the help message
|
||||
// - `tailwindcss > output.css` // should run the build command, not show the help message
|
||||
if ((process.stdout.isTTY && !flags['--output']) || flags['--help']) {
|
||||
if ((process.stdout.isTTY && process.argv[2] === undefined) || flags['--help']) {
|
||||
help({
|
||||
usage: ['tailwindcss [--input input.css] [--output output.css] [--watch] [options…]'],
|
||||
options: { ...build.options(), ...sharedOptions },
|
||||
|
|
|
|||
|
|
@ -67,8 +67,20 @@ export type Result<T extends Arg> = {
|
|||
}
|
||||
|
||||
export function args<const T extends Arg>(options: T, argv = process.argv.slice(2)): Result<T> {
|
||||
for (let [idx, value] of argv.entries()) {
|
||||
if (value === '-') {
|
||||
argv[idx] = '__IO_DEFAULT_VALUE__'
|
||||
}
|
||||
}
|
||||
|
||||
let parsed = parse(argv)
|
||||
|
||||
for (let key in parsed) {
|
||||
if (parsed[key] === '__IO_DEFAULT_VALUE__') {
|
||||
parsed[key] = '-'
|
||||
}
|
||||
}
|
||||
|
||||
let result: { _: string[]; [key: string]: unknown } = {
|
||||
_: parsed._,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue