npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tailwindcss-patch

v9.0.0

Published

patch tailwindcss for exposing context and extract classes

Downloads

26,285

Readme

tailwindcss-patch

Modern tooling to patch Tailwind CSS, capture runtime contexts, and materialise every class that Tailwind can generate. The package now ships with a redesigned architecture focused on clarity, predictable configuration, and first-class Tailwind v4 support.

  • Export runtime contexts for Tailwind v2/v3 without editing source files manually.
  • Traverse Tailwind v4 projects by scanning CSS outputs and content sources.
  • Write class inventories to disk or keep them in memory for tooling integrations.
  • Control caching, filtering, and custom unit extensions from a single, typed entrypoint.

Installation

pnpm add -D tailwindcss-patch
pnpm dlx tw-patch install

Keep the patch applied after installs by adding a prepare hook:

{
  "scripts": {
    "prepare": "tw-patch install"
  }
}

CLI Usage

Run the CLI through tw-patch (or tailwindcss-patch) from your project root.

# Apply runtime patches to the local Tailwind installation
pnpm dlx tw-patch install

# Extract all classes into the configured output file
pnpm dlx tw-patch extract

# Capture every token (candidate) with file/position metadata
pnpm dlx tw-patch tokens --format lines

# Check which patches are applied
pnpm dlx tw-patch status --json

# Migrate deprecated config fields to modern keys
pnpm dlx tw-patch migrate --dry-run

# Restore configs from a migration report backup snapshot
pnpm dlx tw-patch restore --report-file .tw-patch/migrate-report.json --dry-run

# Validate migration report compatibility without modifying files
pnpm dlx tw-patch validate --report-file .tw-patch/migrate-report.json --json

Embed into another CLI

Reuse the same commands inside your own cac program:

import cac from 'cac'
import { mountTailwindcssPatchCommands } from 'tailwindcss-patch'

const cli = cac('my-tool')
mountTailwindcssPatchCommands(cli, {
  commandPrefix: 'tw:', // optional
  commands: ['install', 'tokens'], // mount a subset if needed (defaults to all)
  commandOptions: {
    install: { name: 'patch-install', aliases: ['tw-install'] }, // override names/aliases
  },
})
cli.help()
cli.parse()

Custom command hooks

Hosts can override per-command lifecycles by supplying commandHandlers. Each handler receives a context object (with the resolved cwd, parsed args, memoized loadConfig/createPatcher helpers, and the shared logger) plus a next() callback that runs the built-in action.

mountTailwindcssPatchCommands(cli, {
  commandHandlers: {
    install: async (ctx) => {
      const patcher = await ctx.createPatcher()
      await clearTailwindcssPatcherCache(ctx.cwd)
      await patcher.patch()
      await saveCliPatchTargetRecord({ cwd: ctx.cwd })
    },
    extract: async (ctx, next) => {
      const result = await next() // run the default extract implementation
      ctx.logger.success(`[host] wrote ${result.classList.length} classes`)
      return result
    },
  },
  commandOptions: {
    extract: {
      description: 'Localised extract command',
      appendDefaultOptions: false,
      optionDefs: [
        { flags: '--entry <file>', description: 'Tailwind CSS entry file' },
        { flags: '--preview', description: 'Print a preview instead of writing' },
      ],
    },
  },
})

Skip next() to fully replace a command (e.g. custom init or cache clearing before install). Calling next() returns the default result—ExtractResult, TailwindTokenReport, etc.—so hosts can log metadata or feed it into their own telemetry without re-implementing the commands.

Extract options

| Flag | Description | | ------------------------ | ---------------------------------------------------------------- | | --cwd <dir> | Use a different working directory when loading configuration. | | --output <file> | Override the target file for the generated class list. | | --format <json\|lines> | Switch between JSON output (default) and newline-delimited text. | | --css <file> | Provide a CSS entry file when working with Tailwind v4 projects. | | --no-write | Skip writing to disk and only return the collected classes. |

The CLI loads tailwindcss-patch.config.ts via @tailwindcss-mangle/config. v9 expects the modern registry shape; use tw-patch migrate before upgrading if your config still uses deprecated keys.

Public Type Names

The current alpha exports the modern option type names only:

import type {
  ApplyOptions,
  CacheOptions,
  ExtractOptions,
  TailwindCssOptions,
  TailwindCssPatchOptions,
  TailwindV2Options,
  TailwindV3Options,
  TailwindV4Options,
  NormalizedTailwindCssPatchOptions,
} from 'tailwindcss-patch'

Older aliases such as TailwindcssPatchOptions, TailwindLocatorOptions, and TailwindTargetOptions are intentionally removed in the alpha line.

v9 upgrade flow

  1. Run pnpm dlx tw-patch migrate --dry-run to preview required config rewrites.
  2. Apply the migration, or rewrite the config manually to modern registry fields.
  3. Confirm every config sets registry.tailwindcss.version explicitly.
  4. Upgrade to v9 and rerun tw-patch install / tw-patch extract in your project.

Legacy to v9 example:

// before
export default defineConfig({
  registry: {
    output: {
      file: '.tw-patch/tw-class-list.json',
    },
    tailwind: {
      package: 'tailwindcss',
      classic: {
        cwd: 'apps/web',
      },
    },
  },
})

// after
export default defineConfig({
  registry: {
    extract: {
      file: '.tw-patch/tw-class-list.json',
    },
    tailwindcss: {
      version: 3,
      packageName: 'tailwindcss',
      v3: {
        cwd: 'apps/web',
      },
    },
  },
})

Migrate options

| Flag | Description | | ---------------------- | --------------------------------------------------------------------- | | --cwd <dir> | Working directory used to locate config files. | | --config <file> | Migrate only one specific config file path. | | --workspace | Recursively scan the workspace for supported config filenames. | | --max-depth <n> | Maximum recursion depth for --workspace mode (default: 6). | | --include <glob> | Only migrate files matching this glob pattern (repeatable). | | --exclude <glob> | Skip files matching this glob pattern (repeatable). | | --report-file <file> | Write the migration report JSON to this file. | | --backup-dir <dir> | Store pre-migration file backups in this directory. | | --check | Check mode for CI. Exits with an error if files still need migration. | | --json | Print the migration report as JSON. | | --dry-run | Preview planned changes without writing files. |

tw-patch migrate scans tailwindcss-patch.config.* and tailwindcss-mangle.config.* in the target directory. With --workspace, it recursively scans sub-projects (excluding folders like node_modules, .git, and dist). Use --include / --exclude to control monorepo scanning ranges. It rewrites deprecated keys (for example registry.output -> registry.extract, registry.tailwind -> registry.tailwindcss) and prints a per-file change summary.

When writing files, migration uses a transactional strategy by default: if a later file write fails, already written migration files are rolled back to avoid partial updates. Use --backup-dir if you want explicit backup snapshots for audit/manual recovery. Use --report-file to keep a machine-readable migration artifact.

Migration reports now include envelope metadata: reportKind, schemaVersion, generatedAt, and tool (name / version). This metadata helps restore tooling validate report compatibility.

Restore options

| Flag | Description | | ---------------------- | ------------------------------------------------------------------------- | | --cwd <dir> | Working directory used to resolve report and target paths. | | --report-file <file> | Migration report file path (defaults to .tw-patch/migrate-report.json). | | --dry-run | Preview restore targets without writing files. | | --strict | Fail when any backup file in the report is missing. | | --json | Print restore summary as JSON. |

tw-patch restore validates report schema metadata when available. Reports with unsupported reportKind or newer schemaVersion are rejected to avoid unsafe restores. Legacy reports without metadata are still supported. With --json, restore output includes reportKind / reportSchemaVersion when report metadata is present.

Validate options

| Flag | Description | | ---------------------- | ------------------------------------------------------------------------- | | --cwd <dir> | Working directory used to resolve report paths. | | --report-file <file> | Migration report file path (defaults to .tw-patch/migrate-report.json). | | --strict | Fail when any backup file in the report is missing. | | --json | Print validation result as JSON. |

tw-patch validate performs migration report compatibility checks without writing restored files. It runs report schema validation and scans backup references in dry-run mode. On failure, validate uses dedicated exit codes for CI: 21 report incompatibility, 22 strict missing backups, 23 I/O errors, 24 unknown errors. With --json, validate emits a stable payload: success => { ok: true, ...restoreFields }, failure => { ok: false, reason, exitCode, message }.

Schemas are published at package subpaths: tailwindcss-patch/migration-report.schema.json, tailwindcss-patch/restore-result.schema.json, tailwindcss-patch/validate-result.schema.json. Programmatic consumers can also import report helpers/types from package entry: migrateConfigFiles, restoreConfigFiles, MIGRATION_REPORT_KIND, MIGRATION_REPORT_SCHEMA_VERSION, ConfigFileMigrationReport, VALIDATE_EXIT_CODES.

CI recipe

# 1) fail fast when workspace configs still need migration
pnpm dlx tw-patch migrate --workspace --check --report-file .tw-patch/migrate-report.json

# 2) validate report schema/backup references and keep machine-readable output
set +e
pnpm dlx tw-patch validate --report-file .tw-patch/migrate-report.json --strict --json > .tw-patch/validate-result.json
status=$?
set -e

case "$status" in
  0)  echo "validate ok" ;;
  21) echo "report schema/kind incompatible"; exit 1 ;;
  22) echo "missing backups under --strict"; exit 1 ;;
  23) echo "I/O failure while reading report/backups"; exit 1 ;;
  *)  echo "unknown validate failure"; exit "$status" ;;
esac

GitHub Actions templates:

  • single job: packages/tailwindcss-patch/examples/github-actions/validate-migration-report.yml
  • monorepo matrix shards (root/apps/packages): packages/tailwindcss-patch/examples/github-actions/validate-migration-report-matrix.yml
  • monorepo affected shards (PR diff-aware): packages/tailwindcss-patch/examples/github-actions/validate-migration-report-affected.yml
  • shared composite action (used by all templates): packages/tailwindcss-patch/examples/github-actions/actions/validate-migration-report/action.yml
  • affected-shard resolver script: packages/tailwindcss-patch/examples/github-actions/scripts/resolve-shards.mjs
  • resolver JSON contract schema: packages/tailwindcss-patch/examples/github-actions/resolve-shards-result.schema.json
  • resolver dispatch snapshot fixture: packages/tailwindcss-patch/examples/github-actions/resolve-shards-result.dispatch.snapshot.json

For the affected-shards template, you can customize shard matching and run-all triggers by adding .tw-patch/ci-shards.json in your repo. A sample config is available at packages/tailwindcss-patch/examples/github-actions/ci-shards.example.json.

The shared composite action now supports optional environment bootstrap inputs: setup-pnpm, setup-node, node-version, cache-dependency-path, install-deps, and install-command. This lets you choose between action-managed setup or workflow-managed setup depending on your CI strategy.

CI copy checklist

  1. Pick one workflow template based on your repository shape: validate-migration-report.yml (single job), validate-migration-report-matrix.yml (fixed shards), or validate-migration-report-affected.yml (PR diff-aware shards).
  2. Always copy the shared composite action: packages/tailwindcss-patch/examples/github-actions/actions/validate-migration-report/action.yml.
  3. If you use the affected-shards template, also copy: packages/tailwindcss-patch/examples/github-actions/scripts/resolve-shards.mjs, packages/tailwindcss-patch/examples/github-actions/resolve-shards-result.schema.json, packages/tailwindcss-patch/examples/github-actions/resolve-shards-result.dispatch.snapshot.json.
  4. If your workspace paths differ from defaults, add .tw-patch/ci-shards.json (based on ci-shards.example.json) and adjust shard patterns/report files.
  5. Confirm the composite action inputs match your runner setup: action-managed setup (setup-pnpm/setup-node/install-deps) or pre-provisioned setup (false + custom install command).
  6. Keep permissions.contents: read and ensure pnpm-lock.yaml path matches cache-dependency-path.

CI troubleshooting

  • uses: ./.../validate-migration-report not found: the workflow references a local action path; copy the action directory with the workflow file.
  • No affected shards for migration report validation. in PR: either files are outside configured shard patterns or base diff resolution returned empty; verify .tw-patch/ci-shards.json and PR base branch.
  • Unknown scope in composite action: scope currently accepts only all, root, apps, packages unless you customize action logic.
  • validate exits 21/22/23: 21 incompatible report schema/kind, 22 missing backups under --strict, 23 report/backup I/O failure.
  • Resolver snapshot diff failure in workflow-lint: you changed resolver contract behavior; update both schema/snapshot fixtures and corresponding tests in one commit.

Token report options

| Flag | Description | | -------------------------------------- | ----------------------------------------------------------------------------------------- | | --cwd <dir> | Use a different working directory when loading configuration. | | --output <file> | Override the token report target file (defaults to .tw-patch/tw-token-report.json). | | --format <json\|lines\|grouped-json> | Choose between a JSON payload (default), newline summaries, or JSON grouped by file path. | | --group-key <relative\|absolute> | Control grouped-json keys (defaults to relative paths). | | --no-write | Skip writing to disk and only print a preview. |

Programmatic API

import { TailwindcssPatcher } from 'tailwindcss-patch'

const patcher = new TailwindcssPatcher({
  projectRoot: process.cwd(),
  cache: {
    enabled: true,
    dir: '.tw-patch/cache',
    strategy: 'merge',
    driver: 'file',
  },
  extract: {
    write: true,
    file: '.tw-patch/tw-class-list.json',
    format: 'json',
  },
  apply: {
    overwrite: true,
    exposeContext: { refProperty: 'runtimeContexts' },
    extendLengthUnits: {
      units: ['rpx'],
    },
  },
  tailwindcss: {
    version: 4,
    v4: {
      base: './src',
      cssEntries: ['dist/tailwind.css'],
    },
  },
})

await patcher.patch()
const { classList, filename } = await patcher.extract()
const tokenReport = await patcher.collectContentTokens()
console.log(tokenReport.entries[0]) // { rawCandidate, file, line, column, ... }
const groupedTokens = await patcher.collectContentTokensByFile()
console.log(groupedTokens['src/button.tsx'][0].rawCandidate)
// Preserve absolute file paths:
// await patcher.collectContentTokensByFile({ key: 'absolute', stripAbsolutePaths: false })
const patchStatus = await patcher.getPatchStatus()
console.log(patchStatus.entries)

The constructor accepts the modern object shown above only in v9.

Migration mapping:

  • cwd -> projectRoot
  • overwrite -> apply.overwrite
  • tailwind -> tailwindcss
  • features -> apply
  • output -> extract

Deprecated fields are rejected at runtime in v9. Run tw-patch migrate --dry-run to preview required rewrites.

Use cache.driver to switch between the default file-backed cache, an in-memory cache (memory), or a no-op cache (noop) when filesystem permissions are restricted.

Cache governance (schema v2)

tailwindcss-patch now isolates cache entries by context fingerprint to prevent cross-project pollution in monorepos.

  • Cache file format uses an indexed schema (schemaVersion: 2) with per-context entries.
  • A cache hit requires both fingerprint and metadata consistency.
  • Legacy array caches are read safely and treated as misses, then lazily rebuilt on write.
  • Writes are protected by lock file + atomic temp-file rename to avoid concurrent corruption.

Fingerprint components:

  • realpath-normalized process.cwd()
  • realpath-normalized project root / cache cwd
  • Tailwind config absolute path (if found) + config mtime
  • Tailwind package root + version
  • tailwindcss-patch package version
  • deterministic hash of key patch options (stable key ordering)

The fingerprint is computed once in the patcher constructor and reused during all cache operations.

Clearing cache explicitly

// default: clear current context only
const current = await patcher.clearCache()
// => { scope: 'current', filesRemoved, entriesRemoved, contextsRemoved }

// clear all contexts from the cache index
const all = await patcher.clearCache({ scope: 'all' })

Debug observability:

  • cache hit logs include fingerprint + schema
  • cache miss logs include miss reason and mismatch details (config/version/path/options)

Helper utilities

  • normalizeOptions – normalise raw user input to the runtime shape.
  • CacheStore – read/write class caches (file, memory, or noop drivers) respecting merge or overwrite semantics.
  • extractProjectCandidatesWithPositions – gather Tailwind tokens for every configured source file with location metadata.
  • groupTokensByFile – convert a token report into a { [filePath]: TailwindTokenLocation[] } map.
  • extractValidCandidates – scan Tailwind v4 CSS/content sources with the Tailwind Oxide scanner.
  • runTailwindBuild – run the Tailwind PostCSS plugin for v2/v3 projects to prime runtime contexts.

All helpers are exported from the package root for direct consumption in custom tooling.

Configuration Example

// tailwindcss-patch.config.ts
import { defineConfig } from 'tailwindcss-patch'

export default defineConfig({
  registry: {
    projectRoot: '.',
    extract: {
      file: '.tw-patch/tw-class-list.json',
      removeUniversalSelector: true,
      format: 'json',
    },
    tailwindcss: {
      version: 4,
      v4: {
        cssEntries: ['dist/tailwind.css'],
        sources: [{ base: 'src', pattern: '**/*.{html,tsx}', negated: false }],
      },
    },
    apply: {
      overwrite: true,
      exposeContext: true,
      extendLengthUnits: {
        units: ['rpx'],
      },
    },
  },
})

defineConfig supports both modern registry fields (projectRoot, tailwindcss, apply, extract) and historical keys. The patcher normalizer handles both and always prefers modern fields when both are present.

Migration

Breaking changes, module moves, and upgrade paths are documented in MIGRATION.md. Review it when updating from tailwindcss-patch v7.x or earlier.

License

MIT © ice breaker