news 2026/9/13 22:10:56

UnoCSS MDC Extractor 指南:为 Markdown 组件语法提取原子类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UnoCSS MDC Extractor 指南:为 Markdown 组件语法提取原子类

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-mdc
yarn add -D @unocss/extractor-mdc
npm install -D @unocss/extractor-mdc
bun 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)) }) }, } }

可以拆成三个要点理解:

  1. 文件类型过滤:通过ctx.id匹配\.(?:md|mdc|markdown)$(不区分大小写),只有 Markdown 系列文件才进入提取逻辑;其他文件直接return跳过,不影响默认提取器对普通代码的抽取。
  2. 候选词正则/\.[\w:/\-]+/g匹配所有"点号开头、后跟单词字符/冒号/斜杠/连字符"的连续片段。这个字符集设计很关键:
    • \w覆盖字母、数字、下划线,匹配text-2xlfont-boldw-32等常规类名;
    • :支持 UnoCSS 变体写法,如hover:border-red/10
    • /支持任意值中的斜杠,如bg-red:10border-red/10这类带透明度的颜色工具类;
    • -覆盖连字符类名。
  3. 去掉点号入池c.slice(1)去掉前导.,把text-2xlfont-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-redfootext-greenbg-red:10hover: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-2xlfont-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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 22:10:47

MySQL批量更新不同值的几种实现方案:从CASE WHEN到临时表JOIN

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 22:06:59

如何用 dectl backup 和 restore 备份并恢复 DataEase 数据?

如何用 dectl backup 和 restore 备份并恢复 DataEase 数据&#xff1f; 【免费下载链接】dataease &#x1f525; 人人可用的开源 BI 工具&#xff0c;数据可视化神器。An open-source BI tool alternative to Tableau. 项目地址: https://gitcode.com/GitHub_Trending/da/d…

作者头像 李华
网站建设 2026/9/13 22:06:32

MySQL 统计字符串出现次数的几种实用方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 22:05:06

夸克网盘资源平台选择与使用指南:从找资源到高效整理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 22:00:56

工业紧凑型线缆组件设计与选型实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华