AIRI 项目 UnoCSS 配置实战指南:从 uno.config.ts 到 Monorepo 多端样式统一

发布时间:2026/10/15 21:01:41
AIRI 项目 UnoCSS 配置实战指南:从 uno.config.ts 到 Monorepo 多端样式统一
人工智能AI AgentMCP 服务工具调用GUI 自动化语音数字人交互助手【免费下载链接】airi 自托管、归你拥有的 Grok 风格 AI 伴侣与 waifu / 赛博生命灵魂容器目标是接近 Neuro-sama 的高度支持实时语音聊天、Minecraft 和 Factorio 游玩支持 Web / macOS / Windows。项目地址https://gitcode.com/moeru-ai/airi点击查看免费下载本篇技术指南以 airi 仓库的 UnoCSS 配置知识文档为核心系统讲解uno.config.ts的自动发现机制、全部核心配置选项rules、shortcuts、theme、presets、transformers、safelist、content 等以及如何在 Vite 中显式指定配置文件。读完本篇你将掌握一套可直接复用的 UnoCSS 配置方法并了解 airi 如何通过sharedUnoConfig()与mergeConfigs()在 Web、Electron、移动端等十余个子项目中复用同一份样式配置。认识 uno.config.tsUnoCSS 的配置入口UnoCSS 通过项目根目录下专用的配置文件完成全部定制。官方推荐使用独立的uno.config.ts文件以获得最佳的 IDE 支持和 HMR 热更新体验。UnoCSS 会在项目根目录自动查找以下命名之一的配置文件uno.config.{js,ts,mjs,mts}unocss.config.{js,ts,mjs,mts}在 airi 仓库中根目录的 uno.config.ts 与各子项目的uno.config.ts如 apps/component-calling/uno.config.ts、apps/stage-web/uno.config.ts、apps/ui-server-auth/uno.config.ts、docs/uno.config.ts正是这一机制的实践。airi 的 Monorepo 策略是根目录维护一份共享配置sharedUnoConfig()子应用再通过mergeConfigs()叠加各自的特有配置。一个最典型的配置文件骨架如下与 airi 各子项目使用的结构一致// uno.config.ts import { defineConfig, presetAttributify, presetIcons, presetTypography, presetWebFonts, presetWind3, transformerDirectives, transformerVariantGroup } from unocss export default defineConfig({ shortcuts: [ // ... ], theme: { colors: { // ... } }, presets: [ presetWind3(), presetAttributify(), presetIcons(), presetTypography(), presetWebFonts({ fonts: { // ... }, }), ], transformers: [ transformerDirectives(), transformerVariantGroup(), ], })核心配置选项详解UnoCSS 的defineConfig()接受十余个顶层配置项下面逐一展开并结合 airi 仓库中的真实用法给出可复制的示例。rules定义工具类规则rules用于定义 CSS 工具类支持静态与动态两种形式。数组中靠后的规则优先级更高。rules: [ [m-1, { margin: 0.25rem }], [/^m-(\d)$/, ([, d]) ({ margin: ${d / 4}rem })], ]静态规则类名直接映射到 CSS 属性对象如m-1生成margin: 0.25rem。动态规则用正则匹配类名回调函数接收捕获组与上下文对象可访问theme、symbols等。airi 根配置中定义了若干动态规则例如拖拽区域与点状背景[/drag-region/, () ({ app-region: drag })], [/^bg-dotted-\[(.*)\]$/, ([, color], { theme }) { const parsedColor parseColor(color, theme) return { background-image: radial-gradient(circle at 1px 1px, ${colorToString(parsedColor?.cssColor ?? parsedColor?.color ?? color, var(--un-background-opacity))} 1px, transparent 0), --un-background-opacity: parsedColor?.cssColor?.alpha ?? parsedColor?.alpha ?? 1, } }],其中drag-region用于 Electron 窗口的可拖拽区域app-region: drag点状背景规则则利用unocss/preset-mini的parseColor与colorToString工具解析颜色并生成 radial-gradient。相关完整实现见 uno.config.ts。shortcuts组合规则为简写类shortcuts将多条规则合并为一条简写灵感来自 Windi CSS可在构建期展开且支持hover:btn、dark:btn等所有变体组合。shortcuts: { btn: py-2 px-4 font-semibold rounded-lg shadow-md, }airi 中apps/stage-pocket移动端利用 shortcuts 组合了安全区 padding 规则保证 iPhone 刘海屏与 Android 手势条场景下内容不被遮挡// apps/stage-pocket/uno.config.ts shortcuts: [ [px-safe, pl-safe pr-safe], [py-safe, pt-safe pb-safe], ],配合同文件中定义的p-safe、pt-safe等静态规则基于env(safe-area-inset-*)开发者可直接使用p-safe、px-safe py-safe书写安全区适配样式。完整示例见 apps/stage-pocket/uno.config.ts。theme设计令牌Design Tokenstheme对象提供规则、变体、shortcuts 之间共享的设计令牌会被深度合并到默认主题中。theme: { colors: { brand: #942192, }, breakpoints: { sm: 640px, md: 768px, }, }airi 根配置中的 theme 涵盖字体族与动画体系两部分theme: { fontFamily: { sans: DM Sans Variant, DM Sans, ui-sans-serif, system-ui, sans-serif, ..., sans-rounded: Comfortaa Variable, Comfortaa, DM Sans, ..., cute: Nunito Variable, Nunito, ChillRoundM, Kiwi Maru, ..., }, animation: { keyframes: { overlayShow: {from{opacity:0;}to{opacity:1;}}, contentShow: {from:{opacity:0;transform:translate(-50%,-48%) scale(0.96);}to:{...}}, slideUpAndFade: {from{opacity:0;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}, // ... }, durations: { overlayShow: 300ms, contentShow: 150ms, slideUpAndFade: 400ms, // ... }, timingFns: { overlayShow: cubic-bezier(0.16, 1, 0.3, 1), // ... }, }, }通过theme.animation.keyframes/durations/timingFns三段式声明配合 preset-wind4 的动画工具类airi 统一了弹窗overlay、下拉slideUpAndFade、淡入淡出fadeIn/fadeOut等动效节奏。完整动画主题见 uno.config.tsdocs 站点的动画主题含progress、text、swipeOut等见 docs/uno.config.ts。presets预置配置包presets是开箱即用的配置集合一个 preset 可以捆绑多条规则、变体与主题。UnoCSS 核心不预设任何工具类全部由 presets 提供。presets: [ presetWind3(), presetIcons(), ]airi 根配置的 preset 组合代表了典型的生产级用法presets: [ presetWind3(), presetAttributify(), presetTypography(), presetIcons({ scale: 1.2, collections: { ...createExternalPackageIconLoader(proj-airi/lobe-icons), ...createExternalPackageIconLoader(proj-airi/iconify-meteocons), }, }), presetScrollbar(), presetChromatic({ baseHue: 220.44, colors: { primary: 0, complementary: 180, }, }) as Preset, ],要点说明presetWind3()提供 Tailwind CSS v3 / Windi CSS 兼容的工具类是大多数项目的核心presetAttributify()允许将工具类写在 HTML 属性上presetIcons()以纯 CSS 方式按需加载 Iconify 图标集airi 通过createExternalPackageIconLoader从proj-airi/lobe-icons、proj-airi/iconify-meteocons两个包加载图标集合presetChromatic是 airi 自研的色相hue派生预设以baseHue为基准生成 primary 与 complementary 配色presetScrollbar()提供滚动条美化工具类。docs 站点还演示了presetTypography的深度定制通过cssExtend覆盖.prose下链接、代码、列表等元素的默认样式见 docs/uno.config.ts。transformers支持特殊语法transformers在构建期改写源码以支持apply、screen、theme()、icon()等 CSS 指令与变体分组语法。transformers: [ transformerDirectives(), transformerVariantGroup(), ]airi 还自定义了apply的 CSS 自定义属性别名使普通 CSS 也能复用工具类transformers: [ transformerDirectives({ applyVariable: [--at-apply], }), transformerVariantGroup(), ],这样在style中既可写apply py-2 px-4也可写--at-apply: text-center my-0 font-medium。完整示例见 uno.config.ts。variants预处理选择器variants用于在匹配阶段预处理类名并可以改写最终 CSS 输出如添加:hover伪类、包裹media查询。airi 在根配置中定义了一个用于 Storybook 演示的 hover 变体export function presetStoryMockHover(): PresetOrFactoryAwaitable { return { name: story-mock-hover, variants: [ (matcher) { if (!matcher.includes(hover)) { return matcher } return { matcher, selector: (s) { return ${s}, ${s.replace(/:hover$/, )}._hover }, } }, ], } }该变体让hover:类在 Story 环境中也能通过. _hover类名触发样式见 uno.config.ts。extractors自定义提取器extractors负责从源码中提取工具类名。默认提取器已覆盖.vue、.tsx、.md等若需要处理特殊语法如class:foo、class:foo{bar}可追加自定义提取器extractors: [ { name: my-extractor, extract({ code }) { return code.match(/class:[\w-]/g) || [] }, }, ]preflights注入全局原始 CSSpreflights用于在生成结果最前面注入全局 CSS如 reset 或全局字体设置。docs 站点用它定义基础排版与字体栈// docs/uno.config.ts preflights: [ { getCSS: () { return html,:host { line-height: 1.5; -webkit-text-size-adjust: 100%; font-family: DM Sans, ui-sans-serif, system-ui, sans-serif, ...; } code,kbd,samp,pre { font-family: DM Mono, ui-monospace, SFMono-Regular, ...; } }, }, ],完整示例见 docs/uno.config.ts。layers控制 CSS 层顺序layers控制规则输出的 CSS 层级顺序默认值为0。负值层先输出正值层后输出数值越小越靠前layers: { components: -1, default: 1, utilities: 2, }结合 preset-wind4 时其内置层顺序为properties-200CSS property 规则、theme-150主题 CSS 变量、base-100reset 样式。safelist始终生成的工具类safelist中的工具类无论是否被检测到都会进入最终 CSS 输出。这对动态拼接类名的场景至关重要——UnoCSS 在构建期工作classp-${size}这种运行时拼接无法被提取。safelist: [p-1, p-2, p-3]airi 将 safelist 用到了极致不仅支持字符串数组还支持函数动态生成。根配置中的两个工具函数演示了这一高级用法export function safelistAllPrimaryBackgrounds(): string[] { return [undefined, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950].map((shade) { const prefix shade ? bg-primary-${shade} : bg-primary return [ prefix, ...[5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100].map(opacity ${prefix}/${opacity}), ] }).flat() } export function safelistSettingsEntryIcons(): string[] { return [ i-solar:emoji-funny-square-bold-duotone, i-solar:people-nearby-bold-duotone, // ... ] }bg-primary-{50...950}的 12 个色阶与/10、/20等透明度组合被一次性枚举进 safelist保证组件库中动态计算出的背景类始终有对应 CSS图标类则确保设置页入口图标无论是否被静态扫描到都能渲染。最终在配置中合并safelist: [ ...prose prose-sm m-auto text-left.split( ), ...safelistAllPrimaryBackgrounds(), ...safelistSettingsEntryIcons(), ],完整实现见 uno.config.ts 与 uno.config.ts。相关机制在.agents/skills/unocss/references/core-safelist.md中有更完整的函数形式说明safelist 支持字符串、函数两种条目而 blocklist 额外支持正则。blocklist始终排除的工具类blocklist与 safelist 相反命中的工具类永远不会生成。支持字符串精确匹配、正则以及带提示信息的元组形式blocklist: [p-1, /^p-[2-4]$/]content配置工具类提取范围content配置从哪些文件提取工具类分为 pipeline构建管道内最高效、filesystem管道外文件与 inline内联文本/异步内容三种来源。pipeline 方式默认覆盖.vue、.tsx、.md、.html等默认不覆盖.js/.tscontent: { pipeline: { include: [/\.(vue|svelte|tsx|html)($|\?)/], }, filesystem: [src/**/*.php], }airi 根配置扩展了 pipeline 的 include将.js/.ts文件与共享 UI 包也纳入扫描以支持 shadcn-vue 等组件库的样式提取content: { pipeline: { include: [ /\.(vue|svelte|[jt]sx|mdx?|astro|elm|php|phtml|html)($|\?)/, (components|src)/**/*.{js,ts,vue}, **/stage-ui/**/*.{vue,js,ts}, **/ui/**/*.{vue,js,ts}, ], exclude: [ /\/node_modules\//, ], }, },注意其中注释DO NOT SCAN THE BLACK HOLE指向的node_modules被显式排除避免扫描黑洞。完整配置见 uno.config.ts。docs 站点则演示了 filesystem 用法从 Markdown 内容中提取工具类// docs/uno.config.ts content: { filesystem: [ .vitepress/**/*.{js,ts,vue}, content/**/*.md, ], },separators变体分隔符separators定义变体前缀与类名之间的分隔字符默认值为[:, -]。例如默认支持hover:m-2冒号分隔若自定义分隔符需保持与默认值一致或按需覆盖。outputToCssLayers输出为 CSS Cascade LayersoutputToCssLayers将 UnoCSS 层输出为原生 CSS Cascade LayersoutputToCssLayers: true也可用对象形式自定义层名映射outputToCssLayers: { cssLayerName: (layer) { if (layer default) return utilities if (layer shortcuts) return utilities.shortcuts } }指定配置文件位置当配置文件不在项目根目录如 Monorepo 中共享配置放在公共目录时可在 Vite 插件中通过configFile显式指定// vite.config.ts import UnoCSS from unocss/vite export default defineConfig({ plugins: [ UnoCSS({ configFile: ../my-uno.config.ts, }), ], })airi 的各个 app 均在vite.config.ts中直接挂载Unocss()插件让 UnoCSS 自动发现同目录下的uno.config.ts例如 apps/component-calling/vite.config.tsimport Unocss from unocss/vite export default defineConfig({ plugins: [ VueRouter({ /* ... */ }), Vue(), // https://github.com/antfu/unocss // see uno.config.ts for config Unocss(), ], })接入后还需在入口处引入生成的 CSS。airi 的浏览器测试代码展示了标准用法——先引入 reset再引入virtual:uno.cssimport unocss/reset/tailwind.css import virtual:uno.css例如 apps/stage-tamagotchi/src/renderer/components/InteractiveArea.browser.test.ts。AIRI 实战Monorepo 共享配置与多端覆盖airi 是包含 Web、Electron 桌面端、移动端stage-pocket等多目标形态的 Monorepo。其 UnoCSS 配置设计值得借鉴根目录维护共享配置各子应用叠加差异。1. 共享配置工厂函数根目录 uno.config.ts 导出sharedUnoConfig()工厂函数集中了预设、转换器、safelist、内容扫描范围、主题等全部公共配置同时导出presetWebFontsFonts(provider)字体工厂按 provider 参数fontsource或none切换字体加载策略export function presetWebFontsFonts(provider: fontsource | none): Recordstring, string | WebFontMeta | (string | WebFontMeta)[] { return { sans: { name: provider fontsource ? DM Sans : DM Sans Variable, provider, }, serif: { name: DM Serif Display, provider }, mono: { name: DM Mono, provider }, cutejp: { name: Kiwi Maru, provider, subsets: [latin, japanese] }, cuteen: { name: provider fontsource ? Nunito : Nunito Variable, provider }, jura: { name: provider fontsource ? Jura : Jura Variable, provider }, gugi: { name: Gugi, provider }, quicksand: { name: provider fontsource ? Quicksand : Quicksand Variable, provider }, urbanist: { name: provider fontsource ? Urbanist : Urbanist Variable, provider }, comfortaa: { name: provider fontsource ? Comfortaa : Comfortaa Variable, provider }, m-plus-rounded: { name: M PLUS Rounded 1c, provider }, quanlai: { name: cjkfonts AllSeto, provider: none }, xiaolai: { name: Xiaolai SC, provider: none }, } }这套字体表覆盖了拉丁、日文Kiwi Maru与中文cjkfonts AllSeto、Xiaolai SC等多语言场景完整实现见 uno.config.ts。2. mergeConfigs 叠加差异各子应用通过mergeConfigs([sharedUnoConfig(), {...}])继承共享配置。以桌面端 Electron 应用为例它额外启用本地字体处理createLocalFontProcessor避免运行时向外部服务请求字体// apps/stage-tamagotchi/uno.config.ts import { createLocalFontProcessor } from unocss/preset-web-fonts/local import { defineConfig, mergeConfigs, presetWebFonts } from unocss export default mergeConfigs([ sharedUnoConfig(), defineConfig({ presets: [ presetWebFonts({ fonts: { ...presetWebFontsFonts(none), }, timeouts: { warning: 5000, failure: 10000, }, processors: createLocalFontProcessor(), }), ], }), ])同样的本地字体方案被 apps/stage-tamagotchi-kirie/uno.config.ts 复用而 Web 端与 component-calling、ui-server-auth 等应用则使用fontsourceprovider自托管开源字体。桌面端所依赖的 DM Sans、Kiwi Maru 等字体包fontsource-variable/dm-sans、fontsource/kiwi-maru等均列于 apps/stage-tamagotchi/package.json。3. 真实线上问题修复Netlify 构建超时根配置顶部有一段针对生产环境的修复代码是配置 源码结合解决真实问题的典范。在 Netlify 构建时unocss/preset-web-fonts插件拉取字体元数据会出现AggregateError [ETIMEDOUT]Happy Eyeballs 算法默认 250ms 的autoSelectFamilyAttemptTimeout过短。修复方式是将 Node.js 连接族自动选择超时提升到 1000msimport { setDefaultAutoSelectFamilyAttemptTimeout } from node:net // ... setDefaultAutoSelectFamilyAttemptTimeout(1000)对应源码注释完整记录了错误栈与排查过程见 uno.config.ts。这提醒我们接入 web 字体类 preset 时网络不稳定的 CI/构建环境需要关注字体拉取超时问题。4. 编码规范约束airi 还通过.agents/skills/enforce-rules-for-unocss/SKILL.md固化 UnoCSS 使用规范其中与本主题直接相关的两条值得在配置层注意优先使用 UnoCSS 而非 TailwindVue 模板中建议绑定分组 class 数组如:class[px-2 py-1, flex items-center]而非长内联字符串需要标准化或复用的样式应抽象进uno.config.ts的 shortcuts 与 rules 中而不是散落在组件里。这解释了为什么 airi 会持续把p-safe、bg-dotted-[...]、mask-[...]等能力沉淀进配置文件。小结UnoCSS 的配置文件是整套原子化 CSS 体系的控制面板rules/shortcuts定义工具能力theme承载设计令牌presets/transformers组装开箱即用的功能safelist/blocklist管理输出边界content划定提取范围layers/preflights控制 CSS 输出顺序。airi 仓库在此基础上给出了可借鉴的 Monorepo 落地范式——用sharedUnoConfig()mergeConfigs()实现共享与覆盖用字体工厂函数统一多语言字体策略用createLocalFontProcessor适配桌面端离线场景并在 uno.config.ts 中沉淀了 Netlify 超时等真实问题的修复方案。若你的项目同样需要多端一致的样式基础设施可直接对照 airi 的配置结构进行裁剪复用。赞分享人工智能AI AgentMCP 服务工具调用GUI 自动化语音数字人交互助手【免费下载链接】airi 自托管、归你拥有的 Grok 风格 AI 伴侣与 waifu / 赛博生命灵魂容器目标是接近 Neuro-sama 的高度支持实时语音聊天、Minecraft 和 Factorio 游玩支持 Web / macOS / Windows。项目地址https://gitcode.com/moeru-ai/airi点击查看免费下载相关推荐UnoCSS 配置完全指南基于 AIRI 开源仓库解读 uno.config.ts 与全部核心配置项UnoCSS 配置完全指南基于 AIRI 开源仓库解读 uno.config.ts 与全部核心配置项 UnoCSS 是一套即时按需生成的原子化 CSS 引AI 应用人工智能大模型数字人AI Agent语音前端后端桌面应用移动开发即时通讯3D渲染在Unibest项目中使用TailwindCSS替代UnoCSS的技术实践在Unibest项目中使用TailwindCSS替代UnoCSS的技术实践 在Unibest项目中开发者经常会面临CSS工具链的选择问题。UnoCSS和Tai前端移动开发小程序UnoCSS 配置文件全解从 uno.config.ts 到 rules、theme、presets 等全部配置选项UnoCSS 配置文件全解从 uno.config.ts 到 rules、theme、presets 等全部配置选项 本文以 UnoCSS 的官方配置文档为核AI 技能人工智能上一篇Rufus 快速上手指南10 分钟做出 Windows 11 U 盘启动盘下一篇Visual C 运行库修复VisualCppRedist AIO 三步装齐 2005-2022 全套组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考