Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Add support for prefixes ([#14501](https://github.com/tailwindlabs/tailwindcss/pull/14501))
- Expose timing information in debug mode ([#14553](https://github.com/tailwindlabs/tailwindcss/pull/14553))
- _Experimental_: Add template codemods for migrating `bg-gradient-*` utilities to `bg-linear-*` ([#14537](https://github.com/tailwindlabs/tailwindcss/pull/14537]))
- _Experimental_: Migrate `@import "tailwindcss/tailwind.css"` to `@import "tailwindcss"` ([#14514](https://github.com/tailwindlabs/tailwindcss/pull/14514))

Expand Down
22 changes: 20 additions & 2 deletions packages/@tailwindcss-cli/src/commands/build/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import watcher from '@parcel/watcher'
import { compile } from '@tailwindcss/node'
import { compile, env } from '@tailwindcss/node'
import { clearRequireCache } from '@tailwindcss/node/require-cache'
import { Scanner, type ChangedContent } from '@tailwindcss/oxide'
import { Features, transform } from 'lightningcss'
Expand Down Expand Up @@ -98,10 +98,12 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
// Optimize the output
if (args['--minify'] || args['--optimize']) {
if (css !== previous.css) {
env.DEBUG && console.time('[@tailwindcss/cli] Optimize CSS')
let optimizedCss = optimizeCss(css, {
file: args['--input'] ?? 'input.css',
minify: args['--minify'] ?? false,
})
env.DEBUG && console.timeEnd('[@tailwindcss/cli] Optimize CSS')
previous.css = css
previous.optimizedCss = optimizedCss
output = optimizedCss
Expand All @@ -111,11 +113,13 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
}

// Write the output
env.DEBUG && console.time('[@tailwindcss/cli] Write output')
if (args['--output']) {
await outputFile(args['--output'], output)
} else {
println(output)
}
env.DEBUG && console.timeEnd('[@tailwindcss/cli] Write output')
}

let inputBasePath =
Expand Down Expand Up @@ -206,18 +210,24 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
})

// Scan the directory for candidates
env.DEBUG && console.time('[@tailwindcss/cli] Scan for candidates')
let candidates = scanner.scan()
env.DEBUG && console.timeEnd('[@tailwindcss/cli] Scan for candidates')

// Setup new watchers
cleanupWatchers = await createWatchers(watchDirectories(base, scanner), handle)

// Re-compile the CSS
env.DEBUG && console.time('[@tailwindcss/cli] Build CSS')
compiledCss = compiler.build(candidates)
env.DEBUG && console.timeEnd('[@tailwindcss/cli] Build CSS')
}

// Scan changed files only for incremental rebuilds.
else if (rebuildStrategy === 'incremental') {
env.DEBUG && console.time('[@tailwindcss/cli] Scan for candidates')
let newCandidates = scanner.scanFiles(changedFiles)
env.DEBUG && console.timeEnd('[@tailwindcss/cli] Scan for candidates')

// No new candidates found which means we don't need to write to
// disk, and can return early.
Expand All @@ -227,7 +237,9 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
return
}

env.DEBUG && console.time('[@tailwindcss/cli] Build CSS')
compiledCss = compiler.build(newCandidates)
env.DEBUG && console.timeEnd('[@tailwindcss/cli] Build CSS')
}

await write(compiledCss, args)
Expand Down Expand Up @@ -257,7 +269,13 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
process.stdin.resume()
}

await write(compiler.build(scanner.scan()), args)
env.DEBUG && console.time('[@tailwindcss/cli] Scan for candidates')
let candidates = scanner.scan()
env.DEBUG && console.timeEnd('[@tailwindcss/cli] Scan for candidates')
env.DEBUG && console.time('[@tailwindcss/cli] Build CSS')
let output = compiler.build(candidates)
env.DEBUG && console.timeEnd('[@tailwindcss/cli] Build CSS')
await write(output, args)

let end = process.hrtime.bigint()
eprintln(header())
Expand Down
40 changes: 40 additions & 0 deletions packages/@tailwindcss-node/src/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export const DEBUG = resolveDebug(process.env.DEBUG)

function resolveDebug(debug: typeof process.env.DEBUG) {
if (debug === undefined) {
return false
}

// Environment variables are strings, so convert to boolean
if (debug === 'true' || debug === '1') {
return true
}

if (debug === 'false' || debug === '0') {
return false
}

// Keep the debug convention into account:
// DEBUG=* -> This enables all debug modes
// DEBUG=projectA,projectB,projectC -> This enables debug for projectA, projectB and projectC
// DEBUG=projectA:* -> This enables all debug modes for projectA (if you have sub-types)
// DEBUG=projectA,-projectB -> This enables debug for projectA and explicitly disables it for projectB

if (debug === '*') {
return true
}

let debuggers = debug.split(',').map((d) => d.split(':')[0])

// Ignoring tailwindcss
if (debuggers.includes('-tailwindcss')) {
return false
}

// Including tailwindcss
if (debuggers.includes('tailwindcss')) {
return true
}

return false
}
2 changes: 2 additions & 0 deletions packages/@tailwindcss-node/src/index.cts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as Module from 'node:module'
import { pathToFileURL } from 'node:url'
import * as env from './env'
export * from './compile'
export * from './normalize-path'
export { env }

// In Bun, ESM modules will also populate `require.cache`, so the module hook is
// not necessary.
Expand Down
2 changes: 2 additions & 0 deletions packages/@tailwindcss-node/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as Module from 'node:module'
import { pathToFileURL } from 'node:url'
import * as env from './env'
export * from './compile'
export * from './normalize-path'
export { env }

// In Bun, ESM modules will also populate `require.cache`, so the module hook is
// not necessary.
Expand Down
20 changes: 18 additions & 2 deletions packages/@tailwindcss-postcss/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { compile } from '@tailwindcss/node'
import { compile, env } from '@tailwindcss/node'
import { clearRequireCache } from '@tailwindcss/node/require-cache'
import { Scanner } from '@tailwindcss/oxide'
import fs from 'fs'
Expand Down Expand Up @@ -61,21 +61,26 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin {
{
postcssPlugin: 'tailwindcss',
async OnceExit(root, { result }) {
env.DEBUG && console.time('[@tailwindcss/postcss] Total time in @tailwindcss/postcss')
let inputFile = result.opts.from ?? ''
let context = cache.get(inputFile)
let inputBasePath = path.dirname(path.resolve(inputFile))

async function createCompiler() {
env.DEBUG && console.time('[@tailwindcss/postcss] Setup compiler')
clearRequireCache(context.fullRebuildPaths)

context.fullRebuildPaths = []

return compile(root.toString(), {
let compiler = compile(root.toString(), {
base: inputBasePath,
onDependency: (path) => {
context.fullRebuildPaths.push(path)
},
})

env.DEBUG && console.timeEnd('[@tailwindcss/postcss] Setup compiler')
return compiler
}

// Setup the compiler if it doesn't exist yet. This way we can
Expand Down Expand Up @@ -126,7 +131,9 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin {
sources: context.compiler.globs,
})

env.DEBUG && console.time('[@tailwindcss/postcss] Scan for candidates')
let candidates = scanner.scan()
env.DEBUG && console.timeEnd('[@tailwindcss/postcss] Scan for candidates')

// Add all found files as direct dependencies
for (let file of scanner.files) {
Expand Down Expand Up @@ -154,17 +161,26 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin {
if (rebuildStrategy === 'full') {
context.compiler = await createCompiler()
}

env.DEBUG && console.time('[@tailwindcss/postcss] Build CSS')
css = context.compiler.build(candidates)
env.DEBUG && console.timeEnd('[@tailwindcss/postcss] Build CSS')

// Replace CSS
if (css !== context.css && optimize) {
env.DEBUG && console.time('[@tailwindcss/postcss] Optimize CSS')
context.optimizedCss = optimizeCss(css, {
minify: typeof optimize === 'object' ? optimize.minify : true,
})
env.DEBUG && console.timeEnd('[@tailwindcss/postcss] Optimize CSS')
}
context.css = css

env.DEBUG && console.time('[@tailwindcss/postcss] Update PostCSS AST')
root.removeAll()
root.append(postcss.parse(optimize ? context.optimizedCss : context.css, result.opts))
env.DEBUG && console.timeEnd('[@tailwindcss/postcss] Update PostCSS AST')
env.DEBUG && console.timeEnd('[@tailwindcss/postcss] Total time in @tailwindcss/postcss')
},
},
],
Expand Down
16 changes: 12 additions & 4 deletions packages/@tailwindcss-vite/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { compile, normalizePath } from '@tailwindcss/node'
import { compile, env, normalizePath } from '@tailwindcss/node'
import { clearRequireCache } from '@tailwindcss/node/require-cache'

import { Scanner } from '@tailwindcss/oxide'
import { Features, transform } from 'lightningcss'
import path from 'path'
Expand Down Expand Up @@ -92,7 +91,10 @@ export default function tailwindcss(): Plugin[] {
if (generated === false) {
return
}
return optimizeCss(generated, { minify })
env.DEBUG && console.time('[@tailwindcss/vite] Optimize CSS')
let result = optimizeCss(generated, { minify })
env.DEBUG && console.timeEnd('[@tailwindcss/vite] Optimize CSS')
return result
}

// Manually run the transform functions of non-Tailwind plugins on the given CSS
Expand Down Expand Up @@ -378,9 +380,11 @@ class Root {
// This should not be here, but right now the Vite plugin is setup where we
// setup a new scanner and compiler every time we request the CSS file
// (regardless whether it actually changed or not).
env.DEBUG && console.time('[@tailwindcss/vite] Scan for candidates')
for (let candidate of this.scanner.scan()) {
this.candidates.add(candidate)
}
env.DEBUG && console.timeEnd('[@tailwindcss/vite] Scan for candidates')

// Watch individual files found via custom `@source` paths
for (let file of this.scanner.files) {
Expand All @@ -404,6 +408,10 @@ class Root {

this.requiresRebuild = true

return this.compiler.build([...this.getSharedCandidates(), ...this.candidates])
env.DEBUG && console.time('[@tailwindcss/vite] Build CSS')
let result = this.compiler.build([...this.getSharedCandidates(), ...this.candidates])
env.DEBUG && console.timeEnd('[@tailwindcss/vite] Build CSS')

return result
}
}