Open-Source Wikis

/

Tailwind CSS

/

Packages

/

@tailwindcss/webpack

tailwindlabs/tailwindcss

@tailwindcss/webpack

Active contributors: Robin

Purpose

A Webpack loader that processes Tailwind input CSS. The loader is implemented in a single file: packages/@tailwindcss-webpack/src/index.ts (~287 lines). The package is the youngest first-party adapter — first commit on 2026-01-29, shipped in v4.2.0 (Feb 2026).

Directory layout

packages/@tailwindcss-webpack/
├── package.json                      # peerDependencies: { webpack: ^5 }
├── README.md
├── tsconfig.json
├── tsup.config.ts
└── src/
    └── index.ts                      # the entire loader (~287 lines)

Key abstractions

Symbol Description
tailwindLoader(this, source) Default export. Webpack invokes this for every CSS file the loader is registered on.
LoaderOptions base?: string, optimize?: boolean | { minify?: boolean }.
CacheEntry Per-resource cache: compiler, scanner, candidates, mtimes, full-rebuild paths.
getCacheKey(resourceId, opts) Stable key combining resource path, base, and optimize settings.

How it integrates with Webpack

graph TD
    A[Webpack invokes tailwindLoader] --> B[Quick bail check<br/>regex for any Tailwind directive]
    B -->|no Tailwind features| C[Return source unchanged]
    B -->|tailwind features| D[Load/create CacheEntry by resourceId]
    D --> E[Compare mtimes for compiler, plugins, configs]
    E -->|change detected| F[Recompile]
    E -->|unchanged| G[Reuse compiler]
    F --> H[Setup or refresh Scanner]
    G --> H
    H --> I[scan candidates]
    I --> J[compiler.build candidates]
    J --> K{shouldOptimize?}
    K -->|yes| L[lightningcss optimize]
    K -->|no| M[skip]
    L --> N[callback null result]
    M --> N
    N --> O[Webpack continues pipeline]

The "Quick bail check" is a single regex that looks for any of @import, @reference, @theme, @variant, @config, @plugin, @apply, or @tailwind. If none match, the loader passes the source through unchanged. This is the same optimization the Vite and PostCSS adapters perform via the Features bit-set, but Webpack's hot path can skip the parse entirely with the regex check.

Cache invalidation

The loader records mtimes for:

  • The input CSS file itself.
  • Every file the compiler reported via onDependency (typically JS plugins and configs loaded by @plugin / @config).

When any of those mtimes changes, the loader sets rebuildStrategy = 'full', calls clearRequireCache(...) from @tailwindcss/node/require-cache, and rebuilds the compiler from scratch.

It also informs Webpack about every dependency:

  • this.addDependency(absolutePath) — for every file the scanner found.
  • this.addContextDependency(globBase) — for every glob root.

This wiring is what makes Webpack's watcher rebuild correctly when project files change.

CSS modules

If the input file ends with .module.css, the loader disables the @property polyfill:

polyfills: isCSSModuleFile ? Polyfills.All ^ Polyfills.AtProperty : Polyfills.All,

The reason: @property declarations would create global * rules, which CSS Modules considers non-pure and would reject. Skipping the polyfill keeps the build green at the cost of slightly less robust browser support when targeting the CSS-Modules path.

Error handling

On any error, the loader deletes its cache entry for the resource and rethrows via the async callback. The cache deletion forces the next call to do a full rebuild — which is usually what the user wants after fixing a broken config.

catch (error) {
  let key = getCacheKey(resourceId, options)
  cache.delete(key)
  callback(error as Error)
}

Source detection

The scanner is constructed differently depending on what the input CSS specified:

let sources = (() => {
  if (compiler.root === 'none') return []; // explicit @source none
  if (compiler.root === null)
    return [{ base, pattern: '**/*', negated: false }]; // default
  return [{ ...compiler.root, negated: false }]; // @import "..." source(...)
})().concat(compiler.sources);

This is the same logic the other adapters use, just inlined.

Integration points

  • Reads from @tailwindcss/node for compile, env, Features, Instrumentation, normalizePath, optimize, Polyfills, and clearRequireCache.
  • Reads from @tailwindcss/oxide for the Scanner.
  • Hooks into Webpack via the standard async loader interface (this.async(), this.addDependency, this.addContextDependency, this.getOptions, this.resourcePath, this.resource).

Entry points for modification

  • The loader function at tailwindLoader in index.ts. Add features here.
  • The cache shape is the CacheEntry interface — extend it if you need new per-resource state.
  • The bail check regex is the early-exit guard; loosen or tighten it if you change the directive surface.

For Vite or PostCSS equivalents see vite and postcss.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

@tailwindcss/webpack – Tailwind CSS wiki | Factory