UnoCSS MDC Extractor 指南:为 Markdown 组件语法提取原子类
【免费下载链接】unocssThe instant on-demand atomic CSS engine.项目地址: https://gitcode.com/GitHub_Trending/un/unocss
UnoCSS 的@unocss/extractor-mdc是一个专用于 MDC(Markdown Components) 语法的提取器,它能在.md、.mdc、.markdown文件中识别{.class1.class2}这种行内属性写法,并精准抽出其中的原子类。读完本文,你将掌握该提取器的安装配置、底层正则实现原理、与核心抽取管线的协作方式,以及如何用测试用例验证提取结果。
MDC 是什么,为什么需要专用提取器
MDC 是 Nuxt Content 推出的 Markdown 组件扩展语法,它允许在 Markdown 文本中直接给标题、链接、图片等元素附加类名与属性,写法形如:
# Title{.text-2xl.font-bold} Hello [World]{.text-blue-500} image{.w-32.h-32}这里{.text-2xl.font-bold}不是普通的代码块或行内代码,而是嵌在纯文本里的"花括号 + 点号"标记。UnoCSS 默认的提取器按空格切分候选词,并不会把.text-2xl.font-bold识别为可用的类名 token,因此这类类名会被漏掉、不会生成对应 CSS。MDC 提取器文档 正是为解决这一场景而生。
安装
@unocss/extractor-mdc是一个独立的 preset 包(包内源码见 packages-presets/extractor-mdc/src/index.ts,版本定义见 packages-presets/extractor-mdc/package.json),按你使用的包管理器任选其一安装:
pnpm add -D @unocss/extractor-mdcyarn add -D @unocss/extractor-mdcnpm install -D @unocss/extractor-mdcbun add -D @unocss/extractor-mdc它只依赖@unocss/core提供的类型与运行时接口,sideEffects: false,可以安全地参与 tree-shaking。
配置:接入 uno.config.ts
在项目根目录的uno.config.ts中注册提取器:
import extractorMdc from '@unocss/extractor-mdc' import { defineConfig } from 'unocss' export default defineConfig({ extractors: [ extractorMdc(), ], })extractors是 UnoCSS 配置中的顶级数组,核心引擎会按数组顺序逐个调用每个提取器(详见后文"抽取管线"一节)。注册之后,提取器会对.md、.mdc、.markdown三种扩展名的文件生效,从行内属性中提取类名。
工作原理:源码级拆解
整个提取器的实现极其精简,全部逻辑只有十几行(packages-presets/extractor-mdc/src/index.ts):
import type { Extractor } from '@unocss/core' export default function extractorMdc(): Extractor { return { name: '@unocss/extractor-mdc', async extract(ctx) { if (!/\.(?:md|mdc|markdown)$/i.test(ctx.id ?? '')) return ctx.code.match(/\.[\w:/\-]+/g)?.forEach((c) => { ctx.extracted.add(c.slice(1)) }) }, } }可以拆成三个要点理解:
- 文件类型过滤:通过
ctx.id匹配\.(?:md|mdc|markdown)$(不区分大小写),只有 Markdown 系列文件才进入提取逻辑;其他文件直接return跳过,不影响默认提取器对普通代码的抽取。 - 候选词正则:
/\.[\w:/\-]+/g匹配所有"点号开头、后跟单词字符/冒号/斜杠/连字符"的连续片段。这个字符集设计很关键:\w覆盖字母、数字、下划线,匹配text-2xl、font-bold、w-32等常规类名;:支持 UnoCSS 变体写法,如hover:border-red/10;/支持任意值中的斜杠,如bg-red:10、border-red/10这类带透明度的颜色工具类;-覆盖连字符类名。
- 去掉点号入池:
c.slice(1)去掉前导.,把text-2xl、font-bold等纯 token 加入ctx.extracted集合,交由后续规则匹配阶段解析成具体 CSS。
对照官方测试用例
仓库配套测试 packages-presets/extractor-mdc/test/extractor-mdc.test.ts 直接验证了上述行为:
import { createGenerator } from '@unocss/core' import { expect, it } from 'vitest' import extractorMdc from '../src/index' it('extractorMdc', async () => { const uno = await createGenerator({ extractors: [extractorMdc()], }) async function extract(code: string) { return Array.from(await uno.applyExtractors(code, 'file.mdc')) } expect(await extract(` # Hello{.text-red.foo} Foo{.text-green.bg-red:10.hover:border-red/10} Bar{class="text-blue"} `)).toMatchInlineSnapshot(/* ... */) })快照结果显示:text-red、foo、text-green、bg-red:10、hover:border-red/10均被抽出,同时Bar{class="text-blue"}中的text-blue也会被默认提取机制识别——这说明 MDC 提取器与常规class="..."属性抽取可以共存,互不冲突。
抽取管线:提取器如何与核心引擎协作
extractorMdc()返回的对象满足核心层定义的Extractor接口(packages-engine/core/src/types.ts):
export interface ExtractorContext { readonly original: string code: string id?: string extracted: Set<string> | CountableSet<string> envMode?: 'dev' | 'build' } export interface Extractor { name: string order?: number extract?: (ctx: ExtractorContext) => Awaitable<Set<string> | CountableSet<string> | string[] | undefined | void> }核心引擎在applyExtractors(packages-engine/core/src/generator.ts)中遍历config.extractors,把原始源码与文件 id 组装成ExtractorContext传给每个提取器,再将各提取器返回的 token 合并进同一个集合:
for (const extractor of this.config.extractors) { const result = await extractor.extract?.(context) if (!result) continue for (const token of result) extracted.add(token) }因此:
- 一个文件会经过所有注册的提取器,默认提取器负责
class="..."、模板表达式等常规场景,MDC 提取器专门补足花括号语法,两者输出汇入同一 token 池; - 提取器返回
undefined即表示"本次跳过",MDC 提取器对非 Markdown 文件正是这样处理的; - 最终的 token 集合会继续进入规则匹配阶段,被解析为原子 CSS 并注入产物。
典型使用场景与注意事项
适用场景:基于 Nuxt Content 或任何使用 MDC 语法的 Markdown 内容体系,在正文中直接为标题、链接、图片声明响应式与状态类:
# 章节标题{.text-3xl.font-bold.sm:text-4xl} 了解更多 [点击这里]{.text-blue-500.hover:text-blue-700} 封面{.w-full.h-64.object-cover.rounded-lg}注意事项:
- 提取器只对
.md、.mdc、.markdown文件生效,若你的内容写在.vue、.tsx等文件中,需要其他提取器或默认机制处理; - 正则只匹配点号开头的连续 token,因此
{.text-2xl.font-bold}中每个点号后的片段会被逐个抽出(text-2xl、font-bold),中间的空格不影响结果; - 类名中若包含字符集
[\w:/\-]之外的符号(例如带括号的任意值),可能无法被完整匹配,建议把这类类名写入safelist或使用 safelist 文档 中介绍的方式兜底。
延伸阅读
- 提取器通用配置与自定义方法:docs/config/extractors.md
- 核心提取接口与上下文定义:packages-engine/core/src/types.ts
- 提取器调用主流程:packages-engine/core/src/generator.ts
- 提取器源码与测试:packages-presets/extractor-mdc/src/index.ts、packages-presets/extractor-mdc/test/extractor-mdc.test.ts
【免费下载链接】unocssThe instant on-demand atomic CSS engine.项目地址: https://gitcode.com/GitHub_Trending/un/unocss
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考