首页
/ ui(shadcn/ui)贡献者开发指南:Monorepo 结构、本地 CLI 调试与 Registry 构建流水线

ui(shadcn/ui)贡献者开发指南:Monorepo 结构、本地 CLI 调试与 Registry 构建流水线

2026-09-03 15:24:16作者:俞予舒Fleming

本文基于仓库根目录的 CONTRIBUTING.md 展开,系统讲解 shadcn/ui 这个 pnpm + Turborepo monorepo 的目录结构、本地开发启动流程、shadcn CLI 的本地调试方法、组件注册表(registry)的构建规则与提交规范。读完后,你能够独立完成:克隆仓库并跑起官网 dev server、在本地对 CLI 进行端到端调试、修改组件后正确地执行 registry 定向构建,并按仓库约定提交代码。

一、Monorepo 架构与工具链

CONTRIBUTING.md 开宗明义:这是一个 monorepo,开发依赖三套核心工具:

  • pnpm workspaces:管理多包依赖与跨包脚本过滤(--filter);
  • Turborepo:作为构建系统,负责任务编排、缓存与依赖感知执行;
  • changesets:管理 packages/ 下可发布包的版本与发布。

这三点在仓库配置中都有直接对应:

  1. pnpm-workspace.yaml 声明了工作区范围,apps/*packages/* 下的包均纳入工作区,同时通过排除规则把测试夹具目录排除在外:

    packages:
      - "apps/*"
      - "packages/*"
      - "!**/test/**"
      - "!**/fixtures/**"
      - "!**/temp/**"
      - "!packages/tests/temp/**"
    
  2. package.jsonscripts 字段展示了 Turborepo 的用法:buildlinttypecheckcheck 等脚本都走 turbo run <task>,而针对特定工作区的操作则直接用 pnpm 过滤,例如 v4:devpnpm --filter=v4 dev(见 package.json)。同时 release 脚本为 changeset versionpackage.json),印证了 changesets 在发布流程中的角色。根目录还安装了 @commitlint/cli@commitlint/config-conventionalpackage.json),并在仓库中配有 .commitlintrc.json.changeset/ 目录,分别支撑下文第五、七节的提交规范与发布流程。

  3. turbo.json 定义了各任务的缓存与依赖关系,其中与贡献者日常最相关的有:dev 任务标记为 persistent: true(长期驻留,不缓存);test 任务 dependsOn: ["^build"]cache: false(测试前会先构建被依赖的包);build 任务的 outputs 中明确包含了 public/r/styles/**styles/**——这正是 registry 构建产物的缓存声明。

二、仓库目录结构

CONTRIBUTING.md 给出的结构图与职责表如下:

apps
└── v4
    ├── app
    ├── components
    ├── content
    └── registry
        └── new-york-v4
            ├── example
            └── ui
packages
└── shadcn
Path Description
apps/v4/app The Next.js application for the website.
apps/v4/components The React components for the website.
apps/v4/content The content for the website.
apps/v4/registry The registry for the components.
packages/shadcn The shadcn package.

结合当前仓库的实际目录可以补充几点文档没有展开的事实:

  • apps/v4 是名为 v4 的 Next.js 应用(见 apps/v4/package.json),content/docs 目录下按主题划分为 installationcomponentsdark-modeformschangelog 等子目录;
  • apps/v4/registry 下除文档提到的 new-york-v4 外,还有 bases/styles/__components__/ 等目录,它们共同构成 registry 流水线(详见第四节);
  • 仓库根目录还有 templates/(CLI 安装组件时的项目模板源)与 packages/tests/(跨包的 CLI 集成测试)等目录,是理解 CLI 行为时值得关注的部分。

三、首次本地启动:从 Fork 到 Dev Server

CONTRIBUTING.md 给出的标准开发步骤为:

1. Fork 并克隆仓库

在仓库页面右上角点击 Fork 按钮,然后克隆到你的本机:

git clone <你 fork 后的仓库地址>

(原文档中使用 git clone https://github.com/your-username/ui.git,请替换为你自己的 fork 地址。)

2. 进入目录并创建分支

cd ui
git checkout -b my-new-branch

3. 安装依赖

pnpm install

package.json 通过 packageManager 字段锁定 pnpm@10.33.4,建议保持版本一致以避免依赖解析差异。此外 pnpm-workspace.yaml 配置了 minimumReleaseAge: 2880(48 小时),即默认拒绝安装发布不足 48 小时的依赖,这是对依赖供应链的一种加固策略。

4. 运行工作区

文档说明可以使用 pnpm --filter=[WORKSPACE] 来启动任意工作区,给出了两个例子:

  1. 运行 ui.shadcn.com 官网:

    pnpm --filter=v4 dev
    

    Fresh clone 提示(原文档强调):生成的样式文件并未提交到 git。第一次启动 dev server 前,需先执行一次 pnpm --filter=v4 registry:build --style all。如果忘了执行,dev server 会快速失败并明确提示这一点。

    apps/v4/package.json 看,dev 脚本的实际实现是 pnpm icons:dev & next dev --turbopack --port 4000——它会并行启动图标构建的 watch 模式(scripts/build-icons.ts --watch)与 Next.js dev server(Turbopack,端口 4000)。这个端口信息对下一节本地调试 CLI 很关键。

  2. 运行 shadcn 包:

    pnpm --filter=shadcn dev
    

    对应 packages/shadcn/package.json 中的 dev: "tsup --watch",即以 tsup 的 watch 模式持续构建 CLI 包,适合在修改 CLI 源码时热更新。

四、本地调试 shadcn CLI

CONTRIBUTING.md 的 "Running the CLI Locally" 一节给出的工作流是两终端并行:

  1. 一个终端启动 dev server(即上一节的 pnpm --filter=v4 dev,根目录等价命令为):

    pnpm dev
    

    package.jsondevturbo run dev,会拉起 v4 工作区的官网服务。

  2. 另一个终端测试 CLI:

    pnpm shadcn
    

    要在指定项目中测试,可加上 -c 指向目标应用:

    pnpm shadcn <init | add | ...> -c ~/Desktop/my-app
    

    这个命令之所以能测到"本地最新版",原因在于根 package.jsonshadcn 脚本的定义:pnpm --filter=shadcn start:dev,而 packages/shadcn/package.jsonstart:dev 的完整内容是:

    cross-env REGISTRY_URL=http://localhost:4000/r SHADCN_TEMPLATE_DIR=../../templates node dist/index.js
    

    也就是说:

    • REGISTRY_URL 被指到本地 dev server 的 /r 路由(官网 4000 端口),CLI 拉取的组件 JSON 全部来自你本地刚构建的 registry,而不是线上版本;
    • SHADCN_TEMPLATE_DIR 指向仓库内的 templates/ 目录,init 命令使用的就是仓库里的模板源。

    这正是文档总结的:"This workflow ensures that you are running the most recent version of the registry and testing the CLI properly in your local environment."(该工作流确保你运行的是最新版本的 registry,并在本地环境正确地测试 CLI。)

    作为对照,start:prod 会把 REGISTRY_URL 指向线上 https://ui.shadcn.com/rpackages/shadcn/package.json),用于验证线上行为;包还声明了 engines.node >= 20.18.1packages/shadcn/package.json),运行 CLI 需满足该 Node 版本要求。

五、文档(MDX)开发

CONTRIBUTING.md 指出:本项目文档位于 v4 工作区内,本地运行方式同样是 pnpm --filter=v4 dev;文档使用 MDX 编写,源文件位于 apps/v4/content/docs 目录。

仓库中可以进一步印证:

  • apps/v4/content/docs 下按 installationcomponentsregistrychangelog 等模块组织,每个模块目录内含 meta.json 控制导航排序;
  • apps/v4/package.jsonpostinstall 脚本是 fumadocs-mdx,说明文档栈基于 Fuma Docs 的 MDX 方案,安装依赖时会自动完成 MDX 预处理。

六、组件(Registry)开发:改动、文档与构建

CONTRIBUTING.md 的 "Components" 一节说明:组件开发采用 registry 系统,组件源码位于 apps/v4/registry,按 style 组织,结构示意如下:

apps
└── v4
    └── registry
        └── new-york-v4
            ├── example
            └── ui

新增或修改组件时,文档要求满足三点:

  1. 为每一种 style 都做相应修改
  2. 更新文档
  3. 执行 pnpm registry:build 更新 registry

registry 流水线的源码级细节

文档要求参阅 apps/v4/registry/README.md 了解流水线结构与更快的定向构建模式。该 README 补充了大量 CONTRIBUTING.md 未覆盖的关键事实:

  • 手写源(source of truth)bases/base/bases/radix/ 是两套手写的 base registry(Base UI 与 Radix),styles/style-*.css 是风格 token 文件(novaseravega 等),new-york-v4/ 是遗留的手写源 registry;
  • 生成产物(不可手改)__index__.tsx__blocks__.jsonbases/__index__.tsxstyles/<style>/ui/*(以及 base-novaradix-novaui-rtl)与可安装的 public/r/* JSON,均由 scripts/build-registry.mts 生成;
  • 风格模型(style model):所有 base(baseradix)与所有风格 token(novasera…)的交叉组合(如 base-novaradix-sera)是生成的,registry/<组合>/ 目录内容不入库;而 new-york-v4 是遗留源 registry,直接手写并提交,--style new-york-v4 会被拒绝,应改用 --registry new-york-v4

定向构建模式(快速本地迭代)

文档中提到的快速构建模式在 apps/v4/registry/README.md 中有完整定义:

pnpm registry:build --examples            # examples/__index__.tsx
pnpm registry:build --indexes             # runtime registry indexes
pnpm registry:build --style base-nova     # styles/base-nova/ui (+ ui-rtl)
pnpm registry:build --style all           # every generated combination
pnpm registry:build --registry base-nova  # public/r/styles/base-nova
pnpm registry:build --registry all        # every style, incl. new-york-v4
Flag Rebuilds Run after
--examples ../examples/__index__.tsx adding, removing, or renaming a demo
--indexes bases/__index__.tsx, __index__.tsx, __blocks__.json, public/r/index.json changing registry or block metadata
--style <style|all> ../styles/<style>/ui and ui-rtl editing authored base UI/components
--registry <style|all> ../public/r/styles/<style> changing what the CLI installs

注意事项(来自该 README 与 CONTRIBUTING 的共同约定):

  • 定向模式可组合使用,如 --style base-nova --registry base-nova
  • 定向模式为了速度跳过格式化,可能留下未格式化的生成文件与较大的 git diff
  • 因此提交前必须跑一次完整的 pnpm registry:build 来重新规范化所有产物。根目录的 registry:build 脚本实际是 pnpm --filter=v4 registry:build && pnpm lint:fix && pnpm format:write -- --loglevel silentpackage.json),在 v4 工作区内则会先构建 @shadcn/react@shadcn/helpersshadcn 三个包,再执行 scripts/build-registry.mtsapps/v4/package.json)。

生成产物与 git 工作树

CONTRIBUTING.md 特别强调:大部分生成产物不受 git 跟踪——apps/v4/public/r/styles 下的可安装 JSON 与 apps/v4/styles 下的编译样式均被 gitignore,并在每次部署时重建。因此执行 registry:build 不会用生成文件弄脏你的工作树——最终提交的只有手写源(如 registry/bases)的变化和被跟踪的索引文件。这一设计与 turbo.jsonbuild 任务将 public/r/styles/**styles/** 列为输出的做法一致:它们受 Turborepo 缓存管理,而非 git。

七、提交规范(Commit Convention)

CONTRIBUTING.md 要求提交前检查提交信息是否符合 category(scope or module): message 约定,可用的 category 如下:

  • feat / feature:引入全新代码或新功能的所有改动
  • fix:修复 bug 的改动(若存在对应 issue 建议引用)
  • refactor:非 fix、非 feature 的代码相关改动
  • docs:修改或新建文档(README、库或 CLI 使用文档等)
  • build:与软件构建相关的所有改动、依赖变更或新增依赖
  • test:与测试相关的所有改动(新增或修改测试)
  • ci:与持续集成配置相关的所有改动
  • chore:不属于以上任何类别的仓库改动

示例:feat(components): add new prop to the avatar component

这一约定有工具链支撑:根 package.json 依赖了 @commitlint/cli@commitlint/config-conventional,仓库根目录存在 .commitlintrc.json 配置文件。约定本身源自 Conventional Commits 规范与 Angular 提交信息指南(文档中给出了参考说明)。一个实际用例:模板同步脚本 scripts/sync-templates.sh 在提交模板变更时使用的就是 chore: update template 这类消息(scripts/sync-templates.sh)。

八、测试

CONTRIBUTING.md 说明测试使用 Vitest 编写,可以从仓库根目录运行全部测试:

pnpm test

提交 PR 前请确保测试通过;新增功能请附带测试。

源码层面可以进一步看清这条命令的完整语义——根 package.json 中:

"test:dev": "turbo run test --force",
"test": "pnpm --filter=v4 registry:build && start-server-and-test v4:dev http://localhost:4000 test:dev"

即根目录的 pnpm test 并不只是跑单元用例:它会先构建 registry,再启动 v4 dev server 并等待 http://localhost:4000 就绪后,通过 Turborepo 以 --force 方式在各工作区执行 test 任务(--force 绕过缓存)。这与 turbo.jsontest 任务 dependsOn: ["^build"]cache: false 的配置互相印证:测试依赖已构建的产物(shadcn CLI 的测试会通过 REGISTRY_URL=http://localhost:4000/r 打向本地 registry,见 packages/shadcn/package.jsontest:dev)。

工作区维度的测试编排见 vitest.workspace.ts:Vitest 以 workspace 模式聚合根 vitest.config.tspackages/tests/vitest.config.ts(后者承载针对 CLI 的集成测试,测试夹具位于 packages/tests/fixtures/)。针对单个包也可以直接跑,例如 pnpm --filter=shadcn test(对应根脚本 shadcn:test)。

九、其他贡献路径

CONTRIBUTING.md 还约定了两条补充路径:

  • 新组件请求:如有新组件需求,应通过 GitHub Discussions 发起讨论,而非直接提 PR;
  • CLI 改动:所有 shadcn CLI 的改动都在 packages/shadcn 目录中进行,并强烈建议为改动补充测试。CLI 的公开子命令与参数实现位于 packages/shadcn/src/commands,其对外能力(registry 拉取、schema、MCP 等子入口)在 packages/shadcn/package.jsonexports 字段中有明确声明。

关于版本发布,虽然 CONTRIBUTING.md 未展开,但从仓库配置可以确认:发布基于 changesets,根脚本 releasechangeset versionpackage.json),shadcn 包的发布通过 pub:beta / pub:rc / pub:release 脚本带 tag 执行(packages/shadcn/package.json);RELEASING.md 提供了更完整的发布流程说明。

十、贡献流程速查

综合 CONTRIBUTING.md 与上述源码佐证,一次完整的组件贡献流程可归纳为:

  1. Fork → 克隆 → 建分支 → pnpm install
  2. 首次启动前执行 pnpm --filter=v4 registry:build --style all
  3. pnpm --filter=v4 dev 启动官网(端口 4000),开发时用 pnpm registry:build --style/--registry/--examples/--indexes 定向快速重建;
  4. 若改动涉及 CLI,另开终端用 pnpm dev + pnpm shadcn <cmd> -c <目标项目> 做本地端到端验证;
  5. 按"所有 style 同步修改 + 更新文档"的要求检查 apps/v4/registryapps/v4/content/docs
  6. 提交前运行完整 pnpm registry:build(勿只留定向模式的未格式化产物)与 pnpm test
  7. category(scope): message 规范写提交信息,发起 PR。

掌握以上流程与 pnpm-workspace.yamlturbo.jsonapps/v4/registry/README.md 三份配置之间的关系,就能在只读浏览本仓库的基础上,顺畅地进入自己的 fork 进行开发。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
981
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384