在日常开发中,我们经常会写一些定制化组件。但如果想要在多个项目中复用,并且像使用 Shadcn/ui 官方组件一样通过 CLI shadcn add 快速引入,该如何实现呢?本文将带你从零搭建属于自己的 Shadcn/ui Registry


为什么要做自定义 Registry?

  • 复用:一次开发,多次复用,不用再手动复制组件文件。
  • 一致性:团队共享组件,保持风格统一。
  • CLI 集成:通过 npx shadcn add 一键安装,享受官方组件一样的体验。
  • 可扩展:支持依赖声明、CSS 追加、多文件修改,甚至私有化部署。

一、搭建组件 Registry 仓库

新建一个仓库,例如 acme-ui-registry,结构如下:

acme-ui-registry/
├─ components/
│  └─ ui/
│     └─ smart-button.tsx
├─ lib/
│  └─ utils.ts
├─ styles/
│  └─ tokens.css
├─ smart-button.json          ← 组件清单
└─ registry.json              ← Registry 索引

1. Registry 索引文件

在根目录创建 registry.json

{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "@acme",
  "items": ["smart-button"]
}

2. 单个组件定义文件

创建 smart-button.json

{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "smart-button",
  "type": "registry:component",
  "dependencies": ["react", "clsx"],
  "registryDependencies": ["@shadcn/button"],
  "files": [
    { "path": "components/ui/smart-button.tsx", "target": "components/ui/smart-button.tsx" },
    { "path": "lib/utils.ts", "target": "lib/utils.ts" },
    { "path": "styles/tokens.css", "target": "app/globals.css", "append": true }
  ]
}

二、发布 Registry

公共部署

把仓库托管在 GitHub Pages、Vercel 或 S3。CLI 会根据 URL 获取:

  • 索引地址:https://your-domain.com/registry.json
  • 组件地址:https://your-domain.com/smart-button.json

私有部署

需要鉴权时,可在消费项目的 components.json 中配置 headers:

{
  "registries": {
    "@acme": {
      "url": "https://registry.company.com/{name}.json",
      "headers": { "Authorization": "Bearer ${REGISTRY_TOKEN}" }
    }
  }
}

三、在项目中使用

初始化

在目标项目中先初始化一次:

npx shadcn@latest init

配置自定义 Registry

components.json 里添加:

{
  "aliases": { "components": "@/components", "utils": "@/lib/utils" },
  "registries": {
    "@acme": "https://your-domain.com/{name}.json"
  }
}

安装自定义组件

npx shadcn@latest add @acme/smart-button

也可以直接指定 URL:

npx shadcn add https://your-domain.com/smart-button.json

四、示例组件

components/ui/smart-button.tsx

import * as React from "react";
import { cn } from "@/lib/utils";

type SmartButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
  loading?: boolean;
};

export function SmartButton({ className, loading, children, ...props }: SmartButtonProps) {
  return (
    <button
      className={cn(
        "inline-flex items-center justify-center h-9 rounded-md px-4 text-sm font-medium",
        "bg-primary text-primary-foreground hover:opacity-90 disabled:opacity-50",
        className
      )}
      disabled={loading || props.disabled}
      {...props}
    >
      {loading ? "Loading..." : children}
    </button>
  );
}

现在,你就可以在任意项目中直接通过 CLI 引入它了。


五、注意事项

  • pathtarget 要和 components.json.aliases 对应,否则路径解析会失败。
  • 可以通过 append: true 在用户的 CSS 或配置文件中自动追加内容。
  • dependencies 管理 npm 包依赖,registryDependencies 管理其他 Registry 组件依赖。
  • 支持多注册表命名空间,适合团队拆分使用。

总结

通过搭建自己的 Shadcn/ui Registry,我们就能让自定义组件享受与官方组件同样的 CLI 体验:

  • shadcn add @acme/xxx 即可一键引入。
  • 团队共享组件,避免重复造轮子。
  • 支持公共和私有场景,灵活可扩展。

赶快把你常用的组件整理成一个私有 Registry,提升开发效率吧 🚀

参考资料


A Student on the way to full stack of Web3.