@aphrody/bun-plugin-tailwind

中文文档
1.4.7发布于 2026/10/23MITTypeScriptESM + CJS近 30 天下载 2862

Tailwind CSS v4 for Bun: Bun.build, the HTML dev server and Bun.serve, a PostCSS plugin on the same engine, and a Material 3 preset

原始使用文档
文档目录8 节
  1. Bun.build
  2. Dev server
  3. Options
  4. PostCSS (Next.js with Turbopack or webpack, Vite)
  5. Material 3
  6. API
  7. Compared with bun-plugin-tailwind
  8. Tests

@aphrody/bun-plugin-tailwind

Tailwind CSS v4 for Bun, on @tailwindcss/node and the Oxide scanner, with no Node.js involved:

  • Bun.build plugin, Bun.serve HTML imports and the bun ./index.html dev server (with hot reload),
  • a PostCSS plugin on the same engine (@aphrody/bun-plugin-tailwind/postcss) for Turbopack, webpack and Vite,
  • a Material 3 preset (theme: "m3") built from @aphrody/m3-tokens and @aphrody/m3-tailwind.
bun add -d @aphrody/bun-plugin-tailwind

tailwindcss itself does not need to be installed: @import "tailwindcss" resolves from the project first, then from the plugin's own dependency.

Bun.build

import tailwind from "@aphrody/bun-plugin-tailwind";

await Bun.build({
  entrypoints: ["./index.html"],
  outdir: "./dist",
  plugins: [tailwind],
});
/* style.css */
@import "tailwindcss";

Any stylesheet that uses a Tailwind feature is compiled: @import "tailwindcss", @source (including not and inline(…)), @plugin, @config (Tailwind v3 JavaScript configs), @theme, @utility, @variant, @custom-variant, @apply, @reference and theme(). Other stylesheets are left to Bun.

Class candidates come from two places:

  1. Tailwind's automatic source detection from the build root (or the working directory), which honours .gitignore, plus every @source.
  2. Every file the build loads (JavaScript, TypeScript, HTML, Vue, Svelte, Astro, MDX, …), so classes in a gitignored or node_modules component imported by the app are found too.

Dev server

# bunfig.toml
[serve.static]
plugins = ["@aphrody/bun-plugin-tailwind"]
bun ./index.html

The same setting applies to HTML imports served by Bun.serve({ routes: { "/": html } }). In development, editing a source file rebuilds the stylesheet and hot-reloads it; editing a stylesheet, a @plugin or a @config file recompiles that root.

Options

import { tailwind } from "@aphrody/bun-plugin-tailwind";

tailwind({
  base: import.meta.dir, // automatic source detection root (default: build root, else cwd)
  sources: ["../ui/src/**/*.tsx", "!**/*.test.tsx"], // extra sources, `!` excludes
  optimize: true, // Lightning CSS pass (`optimize` of @tailwindcss/node); `{ minify: false }` to keep it readable
  minify: true, // shorthand for `optimize: { minify: true }`
  sourcemap: true, // inline source map to the original stylesheets
  moduleGraph: { exclude: /node_modules/ }, // or `false` to scan only the sources
  theme: "m3", // Material 3 preset, see below
  schemeImport: id => sheets[id], // CSS of `@import "m3:theme.css"`-style imports, compiled with the root
});

Bun.build({ minify: true }) already minifies the CSS Bun outputs; optimize is for the plugin's own output (for example with the PostCSS plugin). sourcemap defaults to the build's sourcemap option: with Bun.build({ sourcemap: "linked" }) (or "external", "inline"), Bun composes Tailwind's map with its own, so the CSS map points at your stylesheets and Tailwind's.

An @import of another plugin's scheme (@import "m3:theme.css";) stays an import the bundler resolves through that plugin, so Tailwind never sees its content. When that content holds @theme, @utility or @apply, pass schemeImport(id, importer): the CSS it returns replaces each unconditional import before the compile (recursively, cycles are errors); undefined keeps the import.

PostCSS (Next.js with Turbopack or webpack, Vite)

// postcss.config.mjs
export default {
  plugins: {
    "@aphrody/bun-plugin-tailwind/postcss": {},
  },
};

It takes the same options as the Bun plugin (except moduleGraph), reports the files and directories it read as PostCSS dependency / dir-dependency messages so the host rebuilds on change, and chains its source map. It works under Node.js too (dist/, ES modules and CommonJS).

In a Next.js app, @aphrody/next-bun uses the Bun plugin when it builds with Bun.build (withBun) and Turbopack uses this PostCSS plugin.

Material 3

tailwind({ theme: "m3" });
tailwind({
  theme: { seed: "#0b57d0", variant: "vibrant", contrastLevel: 0.5 },
});
tailwind({ theme: { seed: false } }); // colours set at runtime (applyDynamicColor, <m3-theme>, M3Html)

theme adds, right after @import "tailwindcss", the sheets published by Aphrody M3:

OptionSheetGives
tokens@aphrody/m3-tokens/m3-tokens.css--md-sys-* motion, elevation, state, shape tokens
expressive@aphrody/m3-tokens/expressive.cssM3 Expressive shapes and springs
preset@aphrody/m3-tailwind/preset.cssbg-primary, text-body-large, rounded-large, shadow-elevation-2, …
seedgeneratedthe 49 --md-sys-color-* roles, light and dark (.dark, OS, .light)

Each defaults to on; the seed defaults to the M3 baseline #6750A4. @aphrody/bun-plugin-tailwind/m3 exports m3SchemeCss(seed, options) and m3Prelude(theme) for other tools.

API

@aphrody/bun-plugin-tailwind/core exports TailwindRoot, the engine both plugins use:

import { TailwindRoot } from "@aphrody/bun-plugin-tailwind/core";

const root = new TailwindRoot("src/style.css", process.cwd(), {
  sourcemap: true,
});
const { css, map, dependencies, globs, scannedFiles } = await root.generate(
  await Bun.file("src/style.css").text(),
);

A root keeps its compiler and candidates between calls and recompiles when the stylesheet, an imported stylesheet, a plugin or a config changed.

Compared with bun-plugin-tailwind

Everything the bun-plugin-tailwind package published by Tailwind Labs does (CSS roots, Oxide scanning, module graph candidates, rebuilds on change, dev server), plus: named factory with options, sources, moduleGraph control, Lightning CSS optimize/minify, source maps, roots that only use @theme/@variant, tailwindcss resolved without installing it, a PostCSS plugin and a CommonJS/Node.js build, and the Material 3 preset. It uses the public @tailwindcss/oxide package instead of a bundled native addon, so it runs wherever Oxide has a prebuilt binary.

Tests

bun test test/integration/bun-plugin-tailwind/

版本与发布记录

@aphrody/bun-plugin-tailwind 共发布 10 个版本,首次发布于 2026/10/09;过去 12 个月发布了 10 个版本。

版本发布日期距今
1.4.7latest2026/10/2315 天前
1.4.6-aphrody.32026/10/1820 天前
1.4.6-aphrody.22026/10/1820 天前
1.4.6-aphrody.12026/10/1721 天前
0.1.02026/10/1028 天前
0.1.0-aphrody.42026/10/0929 天前

关于 @aphrody/bun-plugin-tailwind 的常见问题

@aphrody/bun-plugin-tailwind 是什么?

Tailwind CSS v4 for Bun: Bun.build, the HTML dev server and Bun.serve, a PostCSS plugin on the same engine, and a Material 3 preset

如何安装 @aphrody/bun-plugin-tailwind?

在项目目录运行 npm install @aphrody/bun-plugin-tailwind,或使用 pnpm add / yarn add / bun add。

@aphrody/bun-plugin-tailwind 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@aphrody/bun-plugin-tailwind 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@aphrody/bun-plugin-tailwind 可以商用吗?

@aphrody/bun-plugin-tailwind 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@aphrody/bun-plugin-tailwind 的下载量有多少?

根据 npm 官方下载统计,@aphrody/bun-plugin-tailwind 在 2026/10/06 – 2026/11/04 这 30 天内被下载 2,862 次,日均约 95 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@aphrody/bun-plugin-tailwind 还在维护吗?

最新版本 1.4.7 发布于 2026/10/23(15 天前);至今共发布 10 个版本,其中过去 12 个月发布了 10 个;首次发布于 2026/10/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。