airi 与 UnoCSS:基于 @unocss/nuxt 的 Nuxt 集成接入与配置完全指南
本文以仓库内技能文档 integrations-nuxt.md 为核心骨架,讲解 UnoCSS 官方 Nuxt 模块
@unocss/nuxt的安装、支持矩阵、uno.config.ts配置、Nuxt Layers 配置合并、组件内使用方式与调试手段;同时以 airi 仓库中大量 Vite 应用的 UnoCSS 真实工程实践(根配置 uno.config.ts、apps/stage-web/uno.config.ts)作为对照,帮助读者把"Vite 侧已经很成熟的 UnoCSS 玩法"平移、迁移到 Nuxt 项目。
导读
UnoCSS 是即时按需生成的原子化 CSS 引擎,其核心本身不预设任何工具类,所有工具类由 preset 提供;airi 仓库的前端应用(stage-web、ui-server-auth、stage-ui 等)全部基于 Vite 插件接入 UnoCSS。如果你的下一个前端工程选择了 Nuxt(或 Nuxt Bridge / Nuxt 2),UnoCSS 官方提供了 @unocss/nuxt 模块,让配置与使用体验与 Vite 侧几乎一致,还额外带来 uno.css 自动注入与 Nuxt Layers 配置合并两大能力。读完本文,你将掌握:在 Nuxt 工程中从零接入 UnoCSS 的完整步骤、uno.config.ts 与 nuxt.config.ts 的职责划分、如何复用并合并多个 Layers 的 UnoCSS 配置,以及在 SFC 组件中使用工具类与 attributify 写法的正确姿势。
一、认识 @unocss/nuxt 与它在 UnoCSS 生态中的位置
UnoCSS 的集成方式按其承载工具分为若干官方入口。在 airi 仓库内,Vite 应用统一采用 unocss/vite 插件方式接入,例如 apps/stage-web/vite.config.ts、packages/stage-ui/vite.config.ts、apps/ui-server-auth/vite.config.ts 都以 import Unocss from 'unocss/vite' 引入插件,并在 main.ts 中显式导入 uno.css:
// apps/stage-web/src/main.ts(节选)
import '@unocss/reset/tailwind.css'
import 'uno.css'
而针对 Nuxt,UnoCSS 提供的是 Nuxt module:@unocss/nuxt。它把上面两步"插件注册 + 入口 CSS 注入"全部封装进 Nuxt 的 modules 机制,无需手工在 main.ts 写 virtual:uno.css 导入。技能文档体系在 SKILL.md 的 Integrations 一节将其与 integrations-vite.md 并列,两者分别对应 Vite 与 Nuxt 两条主流接入路径,本文聚焦 Nuxt 一侧。
需要特别说明:Nuxt 模块底层仍然构建在 Vite/Webpack 的 UnoCSS 插件之上,因此你在 Vite 侧积累的所有知识——preset、shortcuts、transformers、content 抽取管线——在 Nuxt 工程中完全适用。
二、安装与最小接入
2.1 安装依赖
在 Nuxt 项目根目录执行:
pnpm add -D unocss @unocss/nuxt
airi 采用 pnpm workspace 的"catalog 化"依赖管理模式,各应用的 package.json 中依赖以 "catalog:" 引用(例如 apps/stage-web/package.json 中的 "@unocss/reset": "catalog:")。若你所在的 monorepo 同样维护了版本目录(catalog),也可以把 unocss、@unocss/nuxt 收敛到同一份版本中,保证所有前端应用使用完全一致的 UnoCSS 版本。
2.2 注册模块
在 nuxt.config.ts 中把模块加入 modules 数组:
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@unocss/nuxt',
],
})
注意这里不需要给模块传任何选项——UnoCSS 模块的设计哲学与仓库根 uno.config.ts 一致:一切规则、预设、主题都收敛到独立的 uno.config.ts 中,nuxt.config.ts 只负责"启用模块"。
2.3 创建 UnoCSS 配置文件
// uno.config.ts
import { defineConfig, presetWind3 } from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
],
})
presetWind3() 是 Tailwind CSS v3 / Windi CSS 兼容预设,也是 airi 仓库所有应用的统一选择(见根 uno.config.ts 中的 sharedUnoConfig())。详细能力清单可参考技能文档 preset-wind3。
关键差异:
uno.css由模块自动注入。 在 Vite 接入方式下,你必须手动在入口文件import 'virtual:uno.css'(airi 各 Vite 应用正是如此,见 apps/ui-server-auth/src/main.ts);而 Nuxt 模块会在构建流程中自动注入uno.css入口,无需也无法再手动添加这条 import。这正是下面 「与 Vite 集成的关键差异」 中列出的第一条差异。
三、支持矩阵:看清你的 Nuxt 版本与构建工具组合
@unocss/nuxt 对不同 Nuxt 版本与底层构建工具的覆盖并不完全一致,官方支持状态如下:
| 构建工具 | Nuxt 2 | Nuxt Bridge | Nuxt 3 |
|---|---|---|---|
| Webpack Dev | ✅ | ✅ | 🚧 |
| Webpack Build | ✅ | ✅ | ✅ |
| Vite Dev | - | ✅ | ✅ |
| Vite Build | - | ✅ | ✅ |
从矩阵可以读出三条实用结论:
- Nuxt 3 的默认开发体验走 Vite Dev/Build 路线,这两条路径都是 ✅,因此在新项目(Nuxt 3)上无需担心;
- Nuxt 2 + Webpack 是唯一全量支持组合(Dev 与 Build 均为 ✅),老项目升级 UnoCSS 可行;
- Webpack Dev 在 Nuxt 3 下标记 🚧,即"尚未就绪/构建中",如果你的 Nuxt 3 项目被迫使用 Webpack(而非 Vite),开发态的热更新能力可能受限,生产 Build(✅)不受影响;
- Nuxt 2 与 Vite 的组合不存在(-),因为 Nuxt 2 的底层仅支持 Webpack 构建。
规划项目技术栈时,请优先把这一矩阵纳入选型依据。
四、配置方式详解
4.1 推荐:使用独立的 uno.config.ts
把配置放在独立文件中可以获得最佳 IDE 支持(语言服务能直接读取该文件提供补全与悬停提示),同时也让配置天然可被 Vitest、Storybook(histoire)、脚本等非 Nuxt 运行时复用。airi 仓库正是"单份共享配置 + 各应用 merge 覆盖"的范本:根 uno.config.ts 导出 sharedUnoConfig(),随后各应用在自身 uno.config.ts 中 mergeConfigs 叠加差异。
一个覆盖主流需求的 uno.config.ts 示例:
// uno.config.ts
import { defineConfig, presetWind3, presetIcons } from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
presetIcons(),
],
shortcuts: {
'btn': 'py-2 px-4 font-semibold rounded-lg',
},
})
presets:工具类来源。presetWind3()提供类 Tailwind 的全部工具;presetIcons()让纯 CSS 图标可用(结合 Iconify 图标集,详见 preset-icons)。shortcuts:把一段工具类组合绑定为语义化类名。这里btn会被展开为 padding、font-weight、圆角四条规则。
airi 中 shortcut 的更贴近生产级的用法可见根 uno.config.ts 的自定义规则区(例如 mask-[...]、bg-dotted-[...]、drag-region),以及 apps/stage-web/uno.config.ts 中通过 mergeConfigs 追加 transition-colors-none 规则、叠加 presetWebFonts 的写法——这种"基座配置 + 应用级追加"的工程模式,与下文 Nuxt Layers 的合并机制同构。
4.2 Nuxt Layers 支持:自动合并来自 Layer 的 UnoCSS 配置
Nuxt Layers 允许把应用拆分为可复用的"层"。默认情况下 @unocss/nuxt 只读取当前项目根目录的配置;开启 nuxtLayers 后,模块会自动发现并合并各 Layer 暴露的 UnoCSS 配置。
首先在 nuxt.config.ts 中开启:
// nuxt.config.ts
export default defineNuxtConfig({
unocss: {
nuxtLayers: true,
},
})
随后,根应用的 uno.config.ts 应从 Nuxt 生成的合并结果文件读取配置:
// uno.config.ts
import config from './.nuxt/uno.config.mjs'
export default config
这样,Nuxt 会把所有 Layer 的 UnoCSS 配置自动合并后写入 .nuxt/uno.config.mjs,根配置直接以它为最终结果。
如果你还想在合并结果之上追加自己的覆盖,用 @unocss/core 导出的 mergeConfigs 组合:
// uno.config.ts
import { mergeConfigs } from '@unocss/core'
import config from './.nuxt/uno.config.mjs'
export default mergeConfigs([config, {
// Your overrides
shortcuts: {
'custom': 'text-red-500',
},
}])
mergeConfigs 是 UnoCSS 官方提供的配置合并函数,会深度合并 presets / shortcuts / rules / theme 等字段。airi 仓库对它的使用与此完全同构:根 uno.config.ts 用 mergeConfigs([sharedUnoConfig(), histoireUnoConfig()]) 合并共享配置与 Histoire 专用配置,apps/stage-web/uno.config.ts 又基于根共享配置 mergeConfigs 出自己的 Web 端专属配置。可见这套"基座 + 覆盖"的合并哲学在 Vite 应用与 Nuxt Layers 场景中是同一套心智模型。
4.3 完整常用配置范例
技能文档给出了一个覆盖绝大多数实际项目需求的"全家桶"配置,值得直接作为模板:
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@unocss/nuxt',
],
})
// uno.config.ts
import {
defineConfig,
presetAttributify,
presetIcons,
presetTypography,
presetWebFonts,
presetWind3,
transformerDirectives,
transformerVariantGroup,
} from 'unocss'
export default defineConfig({
presets: [
presetWind3(),
presetAttributify(),
presetIcons({
scale: 1.2,
}),
presetTypography(),
presetWebFonts({
fonts: {
sans: 'DM Sans',
mono: 'DM Mono',
},
}),
],
transformers: [
transformerDirectives(),
transformerVariantGroup(),
],
shortcuts: [
['btn', 'px-4 py-1 rounded inline-block bg-teal-600 text-white cursor-pointer hover:bg-teal-700 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'],
],
})
各成员的角色与参考文档如下:
| 成员 | 作用 | 深入参考 |
|---|---|---|
presetWind3() |
Tailwind v3 / Windi 兼容核心工具集 | preset-wind3 |
presetAttributify() |
允许把工具类写到 HTML 属性上(见第五节) | preset-attributify |
presetIcons({ scale: 1.2 }) |
纯 CSS 图标,scale 控制图标尺寸缩放比 |
preset-icons |
presetTypography() |
提供 prose 等排版类 |
preset-typography |
presetWebFonts({ fonts }) |
按需加载 Web 字体(Google Fonts / Fontsource 等提供商) | preset-web-fonts |
transformerDirectives() |
让 CSS 中可用 @apply、theme() 等指令 |
transformer-directives |
transformerVariantGroup() |
支持 hover:(...) 这类变体分组简写 |
transformer-variant-group |
shortcuts |
语义化复合类(数组写法支持更复杂展开) | core-shortcuts |
提示:上面的
sans: 'DM Sans'、mono: 'DM Mono'恰好也是 airi 的默认字体栈成员。airi 根 uno.config.ts 的presetWebFontsFonts('fontsource')工具函数把sans/serif/mono/日文可爱字体Kiwi Maru等多语言字体族统一交给 Fontsource 提供商按需加载,apps/stage-web/uno.config.ts 还在实际部署中为字体请求设置了timeouts: { warning: 5000, failure: 10000 }——如果你在 CI/无外网环境(如 Netlify)构建,这套"字体提供商超时"的坑位与解法(根配置中setDefaultAutoSelectFamilyAttemptTimeout(1000)的注释说明)值得提前借鉴。
五、在组件中使用
5.1 常规 class 写法
<template>
<div class="p-4 text-center">
<h1 class="text-3xl font-bold text-blue-600">
Hello UnoCSS!
</h1>
<button class="btn mt-4">
Click me
</button>
</div>
</template>
text-3xl font-bold text-blue-600 由 presetWind3 生成;btn 则由 shortcut 展开为上一节配置中完整的按钮样式串(含 hover: 与 disabled: 变体)。
工程建议(同样写在本仓库 SKILL.md 中):优先使用基础的
class写法;只有当团队对 attributify 模式与 preset 集合足够熟悉、且 IDE 插件配置完整时,再启用 attributify 等进阶能力。
5.2 Attributify 模式
如果开启了 presetAttributify(),工具类可以"属性化"书写,把同类工具合并到同一个属性里、以空格分词:
<template>
<div p="4" text="center">
<h1 text="3xl blue-600" font="bold">
Hello UnoCSS!
</h1>
</div>
</template>
这里 p="4" 等价于 p-4,text="3xl blue-600" 等价于 text-3xl text-blue-600,font="bold" 等价于 font-bold。它显著提升了模板的可读性,但要求编辑器能正确识别这类"虚拟属性",否则会收到属性类型报错——这是选用 attributify 前需要确认的前置条件。写法细节参见 preset-attributify。
六、Inspector:开发态的可视化调试面板
在开发模式下,访问:
/_nuxt/__unocss
即可打开 UnoCSS inspector。它能做三件事:检查生成的 CSS 规则(某条工具类最终产出了什么样式)、查看每个文件实际命中了哪些工具类、以及在 REPL 中即时验证尚未写进组件的工具类是否按预期生效。
注意这里的路径前缀是 /_nuxt/__unocss,与 Vite 接入时访问的 http://localhost:5173/__unocss(见 integrations-vite.md)不同——这是 Nuxt 约定路由前缀导致的两者差异之一。排查"某个类为什么没生效"时,inspector 是最快的定位工具:若类未出现在列表中,多半是内容抽取(extracting)没有覆盖到该文件,而非规则本身写错。
七、与 Vite 集成的关键差异对照表
从 integrations-vite.md 与本文内容对读,Nuxt 模块相对 Vite 插件的差异可归纳为四点:
- 无需
virtual:uno.css手动导入:Nuxt 模块自动注入uno.css;Vite 集成要求在入口写import 'virtual:uno.css'。 - 配置文件发现机制一致:两者都自动读取项目根目录的
uno.config.*/unocss.config.*文件,规则相同,迁移成本低。 - Vite 插件的全部功能在 Nuxt 下均可用:preset、shortcuts、transformers、content 抽取管线等行为保持一致。
- 额外获得 Nuxt Layers 配置合并:
nuxtLayers: true可跨 Layer 自动合并 UnoCSS 配置,这是纯 Vite 接入没有的能力。
从 airi 仓库的实际代码可以直观看到第 1 条的差异落地:四个 Vite 应用都要在入口手动 import 'uno.css'(如 apps/stage-web/src/main.ts、apps/ui-server-auth/src/main.ts、apps/component-calling/src/main.ts),而这些样板在 Nuxt 工程中会被模块自动处理掉。
八、进阶注意:内容抽取与生产可用性
UnoCSS 的"按需生成"依赖 content 抽取管线:它默认扫描哪些文件、类名如何从源码中被提取,直接决定了样式是否完整。Nuxt 场景需要注意:
.vue文件默认在抽取范围内,组件的class/ attributify 属性都能被识别;而.js/.ts文件默认不被抽取。- 若你在脚本里动态拼接工具类字符串(例如把
bg-primary text-white作为常量写在.ts里),需要扩大content.pipeline.include。airi 根 uno.config.ts 提供了一个成熟的管线配置样本:include 中追加'(components|src)/**/*.{js,ts,vue}'与组件库目录,同时 exclude 掉node_modules,以避免误扫进依赖体积;此外还可借助// @unocss-include魔法注释实现文件级精确收录(细节见 integrations-vite.md 与 core-extracting)。 - 动态类名不会全部被抽取:运行时才能确定完整类名的场景,应使用 safelist 显式罗列(见 core-safelist),airi 根配置的
safelistAllPrimaryBackgrounds()即为按主色阶与透明度批量生成 safelist 的实践。
结语
@unocss/nuxt 让 Nuxt 工程获得与 Vite 场景几乎一致的 UnoCSS 开发体验,并以"自动注入入口 CSS"和"Nuxt Layers 配置合并"进一步降低样板代码。接入路径遵循三段式:pnpm add -D unocss @unocss/nuxt → nuxt.config.ts 注册模块 → 根目录创建 uno.config.ts 声明 presets/shortcuts/transformers。选型时对照支持矩阵确认 Nuxt 版本与构建工具组合;复杂 monorepo 中则善用 mergeConfigs + nuxtLayers 实现"共享基座 + 分层覆盖"。文中所引 airi 仓库 根 uno.config.ts 与 apps/stage-web/uno.config.ts 里的 preset 组合、自定义规则、safelist 与管线配置,均可作为 Nuxt 工程落地同一套样式体系时的直接蓝本。
进一步阅读:本仓库技能文档可继续深入 Vite 集成、配置总览 core-config、shortcuts、attributify 预设 等章节,以补齐从"能跑"到"用好"的每一环。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00