Milkdown 贡献者开发指南:基于 pnpm 工作区的构建、测试与提交流程实战
【免费下载链接】milkdown🍼 Plugin driven WYSIWYG markdown editor framework.项目地址: https://gitcode.com/GitHub_Trending/mi/milkdown
本文以仓库根目录 CONTRIBUTING.md 为核心骨架,面向想要参与 Milkdown 开源开发的贡献者,完整讲解从环境准备、依赖安装、Storybook 本地调试,到单元测试 / E2E 测试 / 代码规范 / 类型检查 / 构建与规范化提交的全流程。读完本文,你将掌握 Milkdown 这套多包 monorepo 仓库的标准开发工作流,知道每个常用命令背后的实际脚本与工具链,并能在提交 Pull Request 前独立完成自检。
Milkdown 是一个插件驱动的所见即所得(WYSIWYG)Markdown 编辑器框架,基于 ProseMirror 与 remark 构建,整个仓库采用 pnpm workspace 组织的 monorepo 结构。本文所有命令与结论均以当前仓库真实配置为依据,你可以一边阅读一边在本地仓库中执行验证。
一、项目结构与开发工作流概览
在动手之前,先理解仓库的顶层布局。通过 pnpm-workspace.yaml 可以看到,Milkdown 的 workspace 由以下几类成员组成:
packages/*:核心包,例如packages/core(编辑器内核)、packages/ctx(上下文容器)、packages/prose(ProseMirror 封装)、packages/transformer(Markdown 与文档树转换)等;packages/plugins/*:全部插件与预设,如preset-commonmark、preset-gfm、plugin-history、plugin-listener、theme-nord等;packages/integrations/*:框架集成层,如integrations/react、integrations/vue;e2e:基于 Playwright 的端到端测试工程;storybook:Storybook 组件调试站点;dev与docs:内部开发工具包与自动生成的 API 文档工程。
顶层 tsconfig.json 通过 TypeScript Project References 把上述所有包串联起来,每个包都有独立的tsconfig.json,因此构建时按依赖图顺序编译。理解这一结构后,再来走 CONTRIBUTING.md 定义的完整开发流程:安装依赖 → 构建 → 启动 Storybook → 修改代码 → 跑测试与检查 → 提交 PR。
二、开发环境准备:Node.js、npm 与 corepack 启用 pnpm
Milkdown 官方开发流程明确要求:使用 corepack 配合 pnpm 进行开发,且本机必须已安装 node.js 与 npm,并确保 corepack 已启用(原文引用自 CONTRIBUTING.md 开头的注释说明)。
这是整个开发工作流的起点。corepack 是 Node.js 自带的包管理器版本管理工具,启用后它会读取仓库内声明的packageManager字段,自动下载并使用对应版本的 pnpm,避免团队成员各自安装不同版本导致的锁文件漂移问题。当前仓库在 package.json 中声明:
"packageManager": "pnpm@11.20.0":固定 pnpm 版本;"engines": { "node": ">=22" }:要求 Node.js 版本不低于 22。
因此,一个标准的环境检查顺序是:
- 确认
node -v满足>=22; - 确认
npm -v可用; - 执行
corepack enable启用 corepack; - 在仓库根目录执行
pnpm install,corepack 会按packageManager字段自动切换并锁定 pnpm@11.20.0。
提示:从 package.json 的
prepare: "husky"脚本可以看出,pnpm install完成后 husky 会自动初始化 git hooks(见下文“Pre Check”部分),所以首次安装依赖时请确保 git 仓库上下文完整。
三、安装依赖并启动本地开发服务器
根据 CONTRIBUTING.md 的 Development Workflow 章节,克隆仓库后需要依次执行三条命令:
pnpm install # 安装全部 workspace 依赖 pnpm build # 构建所有包 pnpm start # 在另一个终端中启动 Storybook 调试站点其中:
pnpm install:一次性安装packages/*、packages/plugins/*、packages/integrations/*、e2e、storybook、dev、docs各子工程的依赖。注意 pnpm-workspace.yaml 中还配置了peerDependencyRules(如忽略 prosemirror-* 与 vue 等 peer 依赖缺失告警)以及overrides(将一批 polyfill 包重定向到@nolyfill/*以统一版本),这些配置保证了跨包依赖解析的一致性。pnpm build:先做 TypeScript 类型检查与编译,再逐个构建发布产物,详见下文“构建系统解析”。pnpm start:启动 Storybook。对应 storybook/package.json 中的"start": "storybook dev -p 6006",即开发服务器默认监听6006端口。Milkdown 的全部核心能力(Crepe 编辑器、各组件、主题)都在storybook/stories下以 stories 的形式提供实时调试入口,例如crepe/crepe.stories.ts、components/code-block.stories.ts、components/table-block.stories.ts等。
四、命令参考:构建、测试、清理与提交
CONTRIBUTING.md 的 Commands 章节列举了贡献者最常使用的八条命令,下表将其与当前仓库 package.json 中的真实脚本一一对应,方便你在执行前了解其底层行为:
| 文档中的命令 | 底层脚本(package.json) | 作用 |
|---|---|---|
pnpm clear | rimraf 'packages/*/{lib,tsconfig.tsbuildinfo,node_modules,.rollup.cache}' && rimraf node_modules | 删除所有包与根目录的构建产物(lib)、TypeScript 增量构建缓存(tsconfig.tsbuildinfo)、.rollup.cache与node_modules,用于彻底清理环境 |
pnpm test:unit | vitest run | 运行所有包的单元测试,配置见根目录 vitest.config.mts,它会以packages/**/*/vitest.config.ts为项目入口聚合各包测试 |
pnpm test:e2e | pnpm --filter=@milkdown/e2e test | 运行 Playwright 端到端测试(见 e2e/package.json) |
pnpm test:e2e:debug | pnpm --filter=@milkdown/e2e run test:debug | 以 Playwright 的 UI 模式运行 E2E 测试,便于逐步排查失败用例 |
pnpm test:lint | oxlint -c .oxlintrc.json --deny-warnings | 基于 oxlint 检查代码风格,--deny-warnings表示把警告升级为错误,任何告警都会导致检查失败 |
pnpm test:tsc | 当前仓库未直接提供该脚本名,最接近的是build:tsc(tsc -b tsconfig.json --verbose) | 运行 TypeScript 类型检查。注意 CONTRIBUTING.md 中记载的脚本名与实际仓库略有出入,实际类型检查/编译统一走pnpm build:tsc |
pnpm build | pnpm build:tsc && pnpm build:post(后者为pnpm -r run build) | 先对整个仓库做 TypeScript 编译,再递归构建每个子包 |
pnpm commit | git-cz | 启动 commitizen 风格的交互式提交向导,结合 git hooks 生成规范化的提交信息 |
除上述文档提及的命令外,package.json 还提供几个值得了解的相关脚本:pnpm test(等价于pnpm test:lint && pnpm test:unit,即 PR 自检的完整命令,见下文)、pnpm test:unit:watch(vitest 监听模式)、pnpm changeset(配合 changesets 生成版本变更集)、pnpm codegen(用 tsx 执行 scripts/gen-ts-config.mts 生成各包 tsconfig)。
五、构建系统解析:从类型检查到产物打包
pnpm build是提交流程中必须通过的一步,理解它的两个阶段有助于定位构建失败:
- 阶段一
pnpm build:tsc:执行tsc -b tsconfig.json --verbose。-b(build mode)会按照 tsconfig.json 中声明的references顺序增量构建全部子项目——从dev、docs、e2e到 20 多个 packages 工程。由于启用了--verbose,你可以清晰看到每个项目的编译过程;tsconfig.tsbuildinfo缓存文件的存在也使得二次构建更快。 - 阶段二
pnpm build:post:执行pnpm -r run build,递归进入每个 workspace 包运行其各自的 build 脚本。以 packages/core/package.json 为例,各包一般通过 Vite 或 Rollup(如 packages/components/rollup.config.js、packages/prose/rollup.config.js)产出lib目录下的分发文件。
因此,当你新增或修改了一个包时,需要先让整个依赖链重新构建,本地 Storybook 才能引用到最新代码——这正是 CONTRIBUTING.md 把pnpm build放在pnpm start之前的直接原因。
六、测试体系:单元测试与端到端测试
Milkdown 的测试分为两层,贡献者在改动涉及对应模块时必须确保两者通过:
6.1 单元测试(pnpm test:unit)
根目录 vitest.config.mts 只做了一件事——把每个包下的vitest.config.ts作为独立 project 聚合进 vitest,因此各包可以声明自己的测试环境与插件。仓库内的单测用例分布广泛,例如:
- packages/ctx/src/context/container.spec.ts 与 packages/ctx/src/timer/timer.spec.ts:验证核心容器与计时器机制;
- packages/crepe/src/default-config/default-config.spec.ts:验证 Crepe 默认配置;
- packages/crepe/src/llm-providers/providers.spec.ts:验证 LLM Provider 抽象。
单元测试适合验证编辑器内核、上下文容器、序列化器等与 DOM 无关或可 mock 的逻辑。
6.2 端到端测试(pnpm test:e2e)
E2E 部分在独立的e2eworkspace 中运行,其 package.json 声明了 Playwright 相关脚本:
pnpm test:e2e # playwright test pnpm test:e2e:debug # playwright test --ui(带 UI 的调试模式) pnpm test:install # playwright install --with-deps(首次运行前安装浏览器)测试工程通过 e2e/playwright.config.ts 配置,用例按场景分目录组织:e2e/tests/input(输入行为,如heading.spec.ts、bold.spec.ts)、e2e/tests/transform(文档转换)、e2e/tests/crepe(Crepe 完整功能,如block-handle.spec.ts、table.spec.ts)、e2e/tests/command、e2e/tests/shortcut等。每个场景目录下都有配套的 HTML/TS 入口(如 e2e/src/preset-gfm/),供 Vite 构建出测试页面后再由 Playwright 驱动真实浏览器验证。
当你修改了某个插件或预设时,通常需要在e2e/tests下补充或更新对应用例,然后本地跑pnpm test:e2e:debug在 UI 模式下逐条观察执行结果。
七、提交 PR 前的自检清单(Pre Check)
CONTRIBUTING.md 明确要求:创建 Pull Request 之前,必须完成以下自检:
- Pre commit hooks 通过,请不要忽略它。仓库通过 husky(
prepare: "husky"脚本)在pnpm install时安装 git hooks,配合 commitlint.config.js(继承@commitlint/config-conventional)与 .lintstagedrc.json 对暂存文件做提交信息规范校验与格式化检查。提交时若 hook 失败,应修复而非--no-verify跳过。 pnpm test通过。根据 package.json,pnpm test等价于先跑pnpm test:lint(oxlint 严格模式)再跑pnpm test:unit(vitest 全量单测)。加上 PR 评审前的pnpm build,就构成了“lint → unit → build”的完整本地门禁。
作为补充建议,涉及 E2E 场景的改动还应额外运行pnpm test:e2e,并在提交信息上使用pnpm commit(git-cz 交互式向导)以生成符合 Conventional Commits 规范的 message,这也是后续 changesets 自动生成 CHANGELOG 的基础(参见 scripts/changelog.mts)。
八、许可证与贡献约定
CONTRIBUTING.md 最后声明:向 Milkdown 贡献代码即表示你同意你的贡献以 MIT 许可证授权(与仓库根目录 LICENSE 一致)。这意味着你的补丁会与其他贡献者的代码一同以 MIT 协议对外分发,提交前请确认你拥有所贡献代码的合法权利,并接受这一授权条款。
总结
参与 Milkdown 开发的核心链路可以浓缩为五步:corepack enable→pnpm install→pnpm build→pnpm start(Storybook 调试)→ 修改代码后依次通过pnpm test、pnpm test:e2e、pnpm build与 git hooks,最后用pnpm commit提交并创建 PR。本文中的所有命令、脚本与测试路径都可以在当前仓库中直接核对,遇到环境问题时可优先检查 Node 版本(>=22)与 pnpm 版本(11.20.0)是否与 package.json 声明一致。
【免费下载链接】milkdown🍼 Plugin driven WYSIWYG markdown editor framework.项目地址: https://gitcode.com/GitHub_Trending/mi/milkdown
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考