
UnoCSS Processors 完整指南在 CSS 生成后精加工每一层样式【免费下载链接】unocssThe instant on-demand atomic CSS engine.项目地址: https://gitcode.com/GitHub_Trending/un/unocssProcessors处理器是 UnoCSS 提供的一组钩子hook用于在 CSS 生成完成之后、对外暴露之前对每一层layer的样式进行二次加工。与在提取前改写源码的 Transformers 不同Processors 直接作用于已生成的 CSS 文本可用于添加 banner 注释、压缩、做浏览器兼容转换等场景。读完本文你将掌握 Processor 的定义方式、执行流程、排序规则与上下文信息并能基于仓库源码理解其底层实现从而编写出可复用的自定义处理器。Processors 与 Transformers两个阶段两种职责UnoCSS 的整个流水线可以分为两个截然不同的阶段Processors 和 Transformers 分别作用于其中Transformers转换器在源码提取之前修改源代码。例如transformer-variant-group会把hover:(bg-red-500 text-white)这类分组写法展开为标准工具类。它们处理的是还没被识别的源码文本详见 docs/config/transformers.md。Processors处理器在UnoCSS 生成完 CSS 层之后运行。它们接收某一层已经生成好的 CSS 字符串返回要替换它的新 CSS 字符串。它们处理的是已经生成的 CSS 产物。两者的定位差异决定了 Processors 非常适合做任何面向最终 CSS 产物的工作比如给生产构建的 CSS 追加版本注释或版权 banner对生成的 CSS 做 minify压缩将现代 CSS 语法编译为指定浏览器目标支持的语法统一调整某些层级的输出格式。定义一个 Processor在类型层面一个 Processor 就是一个实现了CSSProcessor接口的对象。其定义位于 packages-engine/core/src/types.ts#L860-L864export interface CSSProcessorTheme extends object object { name: string order?: number process: (css: string, context: CSSProcessorContextTheme) Awaitablestring }三个字段的含义name处理器名称必填。它用于在合并配置时去重详见下文处理器合并小节order可选处理器执行顺序数值越小越先执行缺省按0处理process核心方法接收当前层的 CSS 字符串与上下文返回替换后的 CSS。返回值可以是同步字符串也支持Promisestring异步处理器。官方文档给出一个添加 banner的完整示例在uno.config.ts中注册import type { CSSProcessor } from unocss/core import { defineConfig } from unocss const banner: CSSProcessor { name: add-banner, order: 10, process(css, { layer, envMode }) { if (envMode ! build) return css return /* generated layer: ${layer} */\n${css} }, } export default defineConfig({ processors: [banner], })这个示例同时演示了两个实用点按环境区分行为通过envMode判断当前是开发模式还是生产构建只在build时插入 banner避免开发调试时 CSS 被额外注释干扰按层区分行为通过layer拿到当前处理的是哪一层可以针对特定层做差异化处理。处理流程每一层 CSS 如何被加工对于每一个非空的 CSS 层UnoCSS 会执行以下步骤生成原始层 CSS包括该层的 preflights、以及开启后包裹的 CSS 层包装器或层标记例如/* layer: default */注释或layer xxx { ... }包装按order升序排序所有处理器顺序串联执行每个处理器依次接收上一处理器的输出作为输入形成一条流水线缓存处理结果处理后的层被缓存通过getLayer()、getLayers()和最终的css结果对外暴露。这条流水线可以用下面的示意图表达generated layer - processor 1 - processor 2 - processed layer output源码层面的实现位于 packages-engine/core/src/generator.ts#L519-L530。processLayer函数先对处理器数组做一次slice().sort()按order升序然后用for...of循环把每个处理器的输出喂给下一个处理器const processors this.config.processors?.slice().sort((a, b) (a.order || 0) - (b.order || 0)) ?? [] const processLayer async (css: string, layer: string) { let processed css const context: CSSProcessorContextTheme { layer, theme: this.config.theme, envMode: this.config.envMode || build, } for (const processor of processors) processed await processor.process(processed, context) return processed }注意这里对order的判断是a.order || 0这与文档中未显式指定order的处理器使用0的规则完全一致见 packages-engine/core/src/generator.ts#L519。在实际的generate()调用中所有层会通过Promise.all并行执行各自的processLayerpackages-engine/core/src/generator.ts#L559-L562await Promise.all(layers.map(async (layer) { const raw getRawLayer(layer) processedLayerCache[layer] raw ? await processLayer(raw, layer) : raw }))这意味着不同的层可能被并发处理。因此官方文档特别提醒处理器内部应避免依赖在层之间共享的可变状态否则并发执行时可能出现竞态问题。Context处理器能拿到哪些信息process()的第二个参数是CSSProcessorContext其类型定义同样在 packages-engine/core/src/types.ts#L843-L858interface CSSProcessorContextTheme extends object object { layer: string theme: Theme envMode: dev | build }三个字段的含义与用途字段含义典型用途layer当前正在处理的 CSS 层名称判断当前层是否为default/preflights/ 自定义层做定向处理theme解析后的 UnoCSS 主题对象读取主题中的颜色、断点等设计变量据此改写 CSSenvMode环境模式dev开发或build生产构建只在生产构建时启用压缩、加 banner 等操作envMode的默认值在配置解析阶段被确定为build见 packages-engine/core/src/config.ts#L232 的envMode: config.envMode || build也可以通过defineConfig显式指定。关于层layer的更多背景比如如何给规则设置层、如何控制层顺序、如何输出 CSS Cascade Layers可以参考 docs/config/layers.md。处理器顺序order 决定执行次序Processors 的排序规则非常简单order越小越先执行未指定order时默认为0。官方文档给出的示例processors: [ { name: minify, order: 20, process: minify }, { name: prefix, order: 10, process: addPrefixes }, ]在这个例子中prefixorder: 10会先于minifyorder: 20执行即先补前缀、再压缩。这一顺序在 packages-engine/core/src/generator.ts#L519 的sort((a, b) (a.order || 0) - (b.order || 0))中得以落实。设计自己的处理器时合理分配order很关键例如先压缩再追加注释和先追加注释再压缩的产物截然不同请根据你的实际目标确定各处理器的相对顺序。处理器合并preset 与用户配置的去重规则Preset预设和用户配置声明的 processors 会被合并在一起。合并逻辑在 packages-engine/core/src/config.ts#L254processors: uniqueBy(getMerged(processors), (a, b) a.name b.name),getMerged会将所有来源presets 用户配置的processors扁平化合并见 packages-engine/core/src/config.ts#L175-L177随后uniqueBy依据name去重同名处理器只保留一个。这正是CSSProcessor接口中name字段为必填的原因——它是处理器身份的唯一标识。这一机制意味着如果你想覆盖某个 preset 自带的处理器定义一个同名处理器即可替换掉它如果你定义了两个同名但不同实现的处理器后者按合并顺序会取代前者而不会重复执行给处理器起一个全局唯一、描述性强的名字如add-banner、unocss/processor-lightningcss有助于避免意外的冲突与覆盖。错误处理与 setLayer重复处理防护错误传播如果某个处理器抛出异常该层的生成将失败错误会向上传递给generate()的调用方。从 packages-engine/core/src/generator.ts#L520-L530 可以看到processLayer内部没有对单个处理器做 try/catch任何await processor.process(...)抛出的错误都会沿 Promise 链向外传播。setLayer 的重新处理GenerateResult暴露了setLayer(layer, callback)接口允许你在生成后修改某一层的内容类型定义见 packages-engine/core/src/types.ts#L984。它的实现位于 packages-engine/core/src/generator.ts#L551-L557const setLayer async (layer: string, callback: (content: string) Promisestring) { const raw await callback(getRawLayer(layer)) const processed await processLayer(raw, layer) rawLayerCache[layer] raw processedLayerCache[layer] processed return processed }这里有一个精心设计的细节callback 接收到的是原始未经处理的 CSSgetRawLayer(layer)而不是已经过处理器加工的输出。UnoCSS 随后会把 callback 返回的新 CSS从头到尾再完整跑一遍处理器链。这样设计是为了防止处理器被反复应用到它们自己的上一次输出上从而避免处理结果被二次处理导致的重复压缩、重复加注释等问题。官方处理器Lightning CSS ProcessorUnoCSS 官方提供了一款开箱即用的处理器——Lightning CSS processorunocss/processor-lightningcss文档位于 docs/processors/lightningcss.md。它基于 Lightning CSS 对每个生成的层做压缩、现代语法编译和浏览器兼容转换。安装pnpm add -D unocss/processor-lightningcss # 或 npm install -D unocss/processor-lightningcss / yarn add -D ...在uno.config.ts中注册import processorLightningCSS from unocss/processor-lightningcss import { defineConfig } from unocss export default defineConfig({ processors: [ processorLightningCSS({ targets: { chrome: 111 16, safari: 15 16, }, }), ], })其源码实现位于 packages-presets/processor-lightningcss/src/index.ts核心逻辑值得展开看看process: async (css, { layer, envMode }) { if (!getEnvFlags().isNode) { warnOnce(unocss/processor-lightningcss is not supported in non-Node.js environments; returning CSS unchanged) return css } const result transform({ code: Buffer.from(css), filename: ${layer ?? uno}.css, minify: envMode build, ...options, }) return result.code.toString() }几个值得注意的实现要点Node.js only它使用 Lightning CSS 的原生 Node.js 构建专为构建期设计。当在非 Node.js 环境中被调用时UnoCSS 会通过warnOnce发出一次警告并原样返回 CSSwarnOnce保证只警告一次不会刷屏。对应测试见 packages-presets/processor-lightningcss/test/index.test.ts#L54-L69。以层名作为文件名filename被设置为${layer ?? uno}.css例如utilities层会以utilities.css传给 Lightning CSS使转换错误信息更易定位。测试 packages-presets/processor-lightningcss/test/index.test.ts#L22-L28 专门验证了这一点。minify 默认值与 envMode 联动默认在envMode build时压缩、dev时不压缩也可通过minify选项显式覆盖。targets通过targets指定浏览器目标如chrome: 111 16控制 Lightning CSS 应用哪些兼容性转换。处理器接受 Lightning CSS 的TransformOptions除code和filename由 UnoCSS 自行提供外层名会作为文件名传入。测试 packages-presets/processor-lightningcss/test/index.test.ts#L30-L52 同时验证了每个生成的层都会被处理且setLayer后重新处理这一完整行为它构造了两个不同层的规则生成后断言getLayer(a)与getLayer(b)均已被压缩随后调用setLayer修改内容并验证处理器链被重新应用。实战小结何时使用 Processor综合文档与源码可以归纳出适合使用 Processor 的典型场景给产物加元信息如 banner、构建时间、版本注释CSS 后处理压缩、去重、格式化兼容性转换面向特定浏览器目标编译现代 CSS 语法产物审计统计每层 CSS 大小、记录层名等。而改写源码以支持某种写法约定这类需求则应交给 Transformersdocs/config/transformers.md处理。记住这一职责划分Processors 改的是生成的 CSSTransformers 改的是输入的源码。编写自己的处理器时最后再回顾四条核心准则name必填且全局唯一否则可能与 preset 中的处理器冲突用order控制执行次序小心串联顺序对产物的影响不要依赖跨层的共享可变状态因为不同层会被并发处理如需在生成后修改层内容通过setLayer传入的 callback 拿到的是原始 CSS修改后会自动重跑完整处理器链。【免费下载链接】unocssThe instant on-demand atomic CSS engine.项目地址: https://gitcode.com/GitHub_Trending/un/unocss创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考