98.0k

命名空间

PreviousNext

配置和使用支持命名空间的多资源注册表。

命名空间注册表让你可以在一个项目中配置多个资源来源。这意味着你可以从各种注册表安装组件、库、工具、AI 提示、配置文件和其他资源,无论它们是公开的、第三方的还是你自定义的私有库。

目录


概述

注册表命名空间以 @ 前缀开头,提供了一种组织和引用不同来源资源的方式。资源可以是任何类型的内容:组件、库、工具、hooks、AI 提示、配置文件、主题等等。例如:

  • @shadcn/button - 来自 shadcn 注册表的 UI 组件
  • @v0/dashboard - 来自 v0 注册表的仪表盘组件
  • @ai-elements/input - 来自 AI 元素注册表的 AI 提示输入
  • @acme/auth-utils - 来自你公司私有注册表的认证工具
  • @ai/chatbot-rules - 来自 AI 资源注册表的 AI 规则提示
  • @themes/dark-mode - 来自主题注册表的主题配置

去中心化命名空间系统

我们有意设计了去中心化的命名空间系统。虽然存在一个 开源注册表索引中心 用于开源命名空间,但你可以自由创建和使用任何你想要的命名空间。

这种去中心化的方法给予你完全的灵活性,使你能够根据组织的实际需求来组织资源。

你可以为不同目的创建多个注册表:

components.json
{
  "registries": {
    "@acme-ui": "https://registry.acme.com/ui/{name}.json",
    "@acme-docs": "https://registry.acme.com/docs/{name}.json",
    "@acme-ai": "https://registry.acme.com/ai/{name}.json",
    "@acme-themes": "https://registry.acme.com/themes/{name}.json",
    "@acme-internal": {
      "url": "https://internal.acme.com/registry/{name}.json",
      "headers": {
        "Authorization": "Bearer ${INTERNAL_TOKEN}"
      }
    }
  }
}

这允许你:

  • 按类型组织:分开 UI 组件、文档、AI 资源等
  • 按团队组织:不同团队维护各自的注册表
  • 按可见性组织:公有资源与私有资源分离
  • 按稳定性组织:稳定版与实验版注册表分开
  • 避免命名冲突:由于无中央权威机构,不必担心命名空间冲突

多注册表配置示例

按资源类型

components.json
{
  "@components": "https://cdn.company.com/components/{name}.json",
  "@hooks": "https://cdn.company.com/hooks/{name}.json",
  "@utils": "https://cdn.company.com/utils/{name}.json",
  "@prompts": "https://cdn.company.com/ai-prompts/{name}.json"
}

按团队或部门

components.json
{
  "@design": "https://design.company.com/registry/{name}.json",
  "@engineering": "https://eng.company.com/registry/{name}.json",
  "@marketing": "https://marketing.company.com/registry/{name}.json"
}

按稳定性

components.json
{
  "@stable": "https://registry.company.com/stable/{name}.json",
  "@latest": "https://registry.company.com/beta/{name}.json",
  "@experimental": "https://registry.company.com/experimental/{name}.json"
}

快速开始

安装资源

配置完成后,你可以用命名空间语法安装资源:

pnpm dlx shadcn@latest add @v0/dashboard

或者一次安装多个资源:

pnpm dlx shadcn@latest add @acme/header @lib/auth-utils @ai/chatbot-rules

快速配置

将注册表添加到 components.json

components.json
{
  "registries": {
    "@v0": "https://v0.dev/chat/b/{name}",
    "@acme": "https://registry.acme.com/resources/{name}.json"
  }
}

然后开始安装:

pnpm dlx shadcn@latest add @acme/button

注册表命名规范

注册表名称须符合以下规则:

  • @ 符号开头
  • 仅包含字母数字、连字符和下划线
  • 合法示例:@v0@acme-ui@my_company

引用资源的格式为:@namespace/resource-name


配置

命名空间注册表通过 components.json 文件中 registries 字段进行配置。

基础配置

最简单的配置方式是 URL 模板字符串:

components.json
{
  "registries": {
    "@v0": "https://v0.dev/chat/b/{name}",
    "@acme": "https://registry.acme.com/resources/{name}.json",
    "@lib": "https://lib.company.com/utilities/{name}",
    "@ai": "https://ai-resources.com/r/{name}.json"
  }
}

注意: URL 中的 {name} 会在执行 npx shadcn@latest add @namespace/resource-name 时自动解析替换成资源名。例如,@acme/button 会变成 https://registry.acme.com/resources/button.json。详见 URL 模式系统

高级配置

需要认证或额外参数的注册表,使用对象格式:

components.json
{
  "registries": {
    "@private": {
      "url": "https://api.company.com/registry/{name}.json",
      "headers": {
        "Authorization": "Bearer ${REGISTRY_TOKEN}",
        "X-API-Key": "${API_KEY}"
      },
      "params": {
        "version": "latest",
        "format": "json"
      }
    }
  }
}

注意: ${VAR_NAME} 格式的环境变量会自动从环境变量(process.env)展开,支持 URL、请求头及参数。例如,${REGISTRY_TOKEN} 会被替换为 process.env.REGISTRY_TOKEN 的值。更多环境变量相关信息见 认证与安全


URL 模式系统

注册表 URL 支持以下占位符:

{name} 占位符(必需)

{name} 会被替换为资源名称:

components.json
{
  "@acme": "https://registry.acme.com/{name}.json"
}

安装 @acme/button 时,URL 为:https://registry.acme.com/button.json
安装 @acme/auth-utils 时,URL 为:https://registry.acme.com/auth-utils.json

{style} 占位符(可选)

{style} 会被替换为当前样式配置:

{
  "@themes": "https://registry.example.com/{style}/{name}.json"
}

样式设置为 new-york,安装 @themes/card 解析为:https://registry.example.com/new-york/card.json

该占位符用于按样式提供同一资源的不同版本,例如为每个样式提供不同版本的组件。


认证与安全

环境变量

使用环境变量安全存储凭据:

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

然后在环境文件设置:

.env.local
REGISTRY_TOKEN=your_secret_token_here

认证方式

Bearer 令牌(OAuth 2.0)

{
  "@github": {
    "url": "https://api.github.com/repos/org/registry/contents/{name}.json",
    "headers": {
      "Authorization": "Bearer ${GITHUB_TOKEN}"
    }
  }
}

请求头中的 API Key

components.json
{
  "@private": {
    "url": "https://api.company.com/registry/{name}",
    "headers": {
      "X-API-Key": "${API_KEY}"
    }
  }
}

基本认证

components.json
{
  "@internal": {
    "url": "https://registry.company.com/{name}.json",
    "headers": {
      "Authorization": "Basic ${BASE64_CREDENTIALS}"
    }
  }
}

查询参数认证

components.json
{
  "@secure": {
    "url": "https://registry.example.com/{name}.json",
    "params": {
      "api_key": "${API_KEY}",
      "client_id": "${CLIENT_ID}",
      "signature": "${REQUEST_SIGNATURE}"
    }
  }
}

多重认证方式

部分注册表同时需要多种认证方式:

components.json
{
  "@enterprise": {
    "url": "https://api.enterprise.com/v2/registry/{name}",
    "headers": {
      "Authorization": "Bearer ${ACCESS_TOKEN}",
      "X-API-Key": "${API_KEY}",
      "X-Workspace-Id": "${WORKSPACE_ID}"
    },
    "params": {
      "version": "latest"
    }
  }
}

安全注意事项

使用命名空间注册表,尤其是第三方或公共注册表时,安全尤为重要。我们通过以下方式确保安全:

资源验证

所有从注册表拉取的资源都会根据注册表项模式进行验证,包括:

  • 结构校验:资源必须符合预期的 JSON 结构
  • 类型安全:验证资源类型(如 registry:uiregistry:lib 等)
  • 避免执行任意代码:资源为数据文件,非可执行脚本

环境变量安全

认证所用环境变量:

  • 绝不打印日志:CLI 不会记录或显示环境变量值
  • 运行时展开:只在需要时展开,不存储在其他地方
  • 隔离认证上下文:每个注册表拥有独立的认证配置

安全配置示例:

components.json
{
  "registries": {
    "@private": {
      "url": "https://api.company.com/registry/{name}.json",
      "headers": {
        "Authorization": "Bearer ${PRIVATE_REGISTRY_TOKEN}"
      }
    }
  }
}

切勿将真实令牌提交到版本控制,使用 .env.local

.env.local
PRIVATE_REGISTRY_TOKEN=actual_token_here

强制 HTTPS

强烈建议所有注册表 URL 使用 HTTPS:

  • 数据传输加密:防止中间人攻击
  • 证书校验:确保连接到合法注册表
  • 凭证保护:请求头和令牌加密传输
components.json
{
  "registries": {
    "@secure": "https://registry.example.com/{name}.json", // ✅ 推荐
    "@insecure": "http://registry.example.com/{name}.json" // ❌ 避免
  }
}

内容安全

注册表资源作为数据处理:

  1. 仅允许 JSON 解析:资源必须是合法 JSON
  2. 模式验证:必须匹配注册表项模式
  3. 文件路径限制:只能写入配置的路径
  4. 无脚本执行:CLI 不执行任何注册表资源中的代码

注册表信任模型

命名空间系统基于信任原则:

  • 你信任你安装的内容:仅添加你信任的注册表
  • 显式配置:必须在 components.json 中明确配置注册表
  • 无自动注册发现:CLI 不会自动添加任何注册表
  • 依赖透明:所有依赖在注册表项中清晰列出

注册表运营最佳实践

如果你维护自己的注册表:

  1. 始终使用 HTTPS,避免 HTTP
  2. 实现认证机制,为私有注册表要求 API Key 或令牌
  3. 限制访问频率,防止滥用
  4. 校验内容,发布前验证资源有效性

安全注册表示例:

components.json
{
  "@company": {
    "url": "https://registry.company.com/v1/{name}.json",
    "headers": {
      "Authorization": "Bearer ${COMPANY_TOKEN}",
      "X-Registry-Version": "1.0"
    }
  }
}

安装前查看资源

CLI 提供查看安装内容的透明度。使用命令查看注册表项内容:

pnpm dlx shadcn@latest view @acme/button

该命令在控制台输出注册表项的完整内容。


依赖解析

基础依赖解析

资源可能存在跨注册表依赖:

registry-item.json
{
  "name": "dashboard",
  "type": "registry:block",
  "registryDependencies": [
    "@shadcn/card",        // 默认注册表
    "@v0/chart",           // v0 注册表
    "@acme/data-table",    // acme 注册表
    "@lib/data-fetcher",   // 工具库
    "@ai/analytics-prompt" // AI 提示资源
  ]
}

CLI 会自动从对应的注册表解析并安装所有依赖。

高级依赖解析

了解依赖如何内部解析在开发注册表或自定义第三方资源时十分重要。

解析流程

执行 npx shadcn@latest add @namespace/resource 时,CLI 会:

  1. 清理注册表上下文,确保状态恢复初始
  2. 请求主资源,从指定注册表拉取
  3. 递归解析依赖,对每个依赖从其相应注册表获取
  4. 拓扑排序,保证安装顺序正确
  5. 路径去重,同路径文件以最后拉取的为准
  6. 深度合并配置(tailwind、cssVars、css、envVars)

因此:

pnpm dlx shadcn@latest add @acme/auth @custom/login-form

中,@custom/login-formlogin-form.ts 会覆盖先安装的 @acme/auth 中的同名文件。

覆盖第三方资源

你可以通过依赖解析技巧覆盖任何第三方资源,在自定义资源中声明registryDependencies 并提供自定义内容。

示例:自定义第三方按钮

假设要自定义来自供应商注册表的按钮:

1. 供应商按钮(@vendor/button):

button.json
{
  "name": "button",
  "type": "registry:ui",
  "files": [
    {
      "path": "components/ui/button.tsx",
      "type": "registry:ui",
      "content": "// 供应商的按钮实现\nexport function Button() { ... }"
    }
  ],
  "cssVars": {
    "light": {
      "--button-bg": "blue"
    }
  }
}

2. 创建自定义覆盖版本(@my-company/custom-button):

custom-button.json
{
  "name": "custom-button",
  "type": "registry:ui",
  "registryDependencies": [
    "@vendor/button" // 先引入原始内容
  ],
  "cssVars": {
    "light": {
      "--button-bg": "purple" // 覆盖背景颜色
    }
  }
}

3. 安装自定义版本:

pnpm dlx shadcn@latest add @my-company/custom-button

这会先安装 @vendor/button,然后用你自定义的 CSS 变量覆盖。

高级覆盖模式

扩展而非替换

保留原始功能,新增扩展:

extended-table.json
{
  "name": "extended-table",
  "registryDependencies": ["@vendor/table"],
  "files": [
    {
      "path": "components/ui/table-extended.tsx",
      "content": "import { Table } from '@vendor/table'\n// 添加扩展\nexport function ExtendedTable() { ... }"
    }
  ]
}

这会安装 @vendor/table 的原始表格,并新增你的扩展代码。

部分覆盖(多文件资源)

仅覆盖复杂组件中特定文件:

custom-auth.json
{
  "name": "custom-auth",
  "registryDependencies": [
    "@vendor/auth" // 多文件组件
  ],
  "files": [
    {
      "path": "lib/auth-server.ts",
      "type": "registry:lib",
      "content": "// 你的自定义认证服务"
    }
  ]
}

解析顺序示例

安装依赖多个资源的 @custom/dashboard

dashboard.json
{
  "name": "dashboard",
  "registryDependencies": [
    "@shadcn/card",    // 1. 先解析
    "@vendor/chart",   // 2. 再解析
    "@custom/card"     // 3. 最后解析,覆盖@shadcn/card
  ]
}

解析顺序:

  1. 安装 @shadcn/cardcomponents/ui/card.tsx
  2. 安装 @vendor/chartcomponents/ui/chart.tsx
  3. 覆盖 components/ui/card.tsx(由 @custom/card

关键解析特性

  1. 来源追踪:每个资源记录来源注册表,避免命名冲突
  2. 循环依赖预防:自动检测阻止循环依赖
  3. 智能安装顺序:先安装依赖,再安装主资源

版本控制

你可以通过查询参数为注册表资源实现版本管理,允许用户固定特定版本或使用不同发布渠道。

基础版本参数

components.json
{
  "@versioned": {
    "url": "https://registry.example.com/{name}",
    "params": {
      "version": "v2"
    }
  }
}

解析 @versioned/button 为:https://registry.example.com/button?version=v2

动态版本选择

使用环境变量全局控制版本:

components.json
{
  "@stable": {
    "url": "https://registry.company.com/{name}",
    "params": {
      "version": "${REGISTRY_VERSION}"
    }
  }
}

这样可以:

  • 生产环境设置 REGISTRY_VERSION=v1.2.3
  • 在不同环境(开发、预发布、生产)覆盖版本号

语义版本管理

支持语义版本范围和预发布选项:

components.json
{
  "@npm-style": {
    "url": "https://registry.example.com/{name}",
    "params": {
      "semver": "^2.0.0",
      "prerelease": "${ALLOW_PRERELEASE}"
    }
  }
}

版本解析最佳实践

  1. 使用环境变量统一管理各环境版本
  2. 提供合理默认值(如 ${VAR:-default}
  3. 明确文档说明版本规则
  4. 支持版本锁定,实现可复现构建
  5. 提供版本发现接口(如 /versions/{name}
  6. 合理缓存版本资源,设置缓存头

CLI 命令

shadcn CLI 提供多条命令支持命名空间注册表操作:

安装资源

从任何已配置注册表安装资源:

# 从指定注册表安装
npx shadcn@latest add @v0/dashboard
 
# 安装多个资源
npx shadcn@latest add @acme/button @lib/utils @ai/prompt
 
# 直接从 URL 安装
npx shadcn@latest add https://registry.example.com/button.json
 
# 从本地文件安装
npx shadcn@latest add ./local-registry/button.json

查看资源

安装前查看注册表项详情:

# 查看单个资源
npx shadcn@latest view @acme/button
 
# 查看多个资源
npx shadcn@latest view @v0/dashboard @shadcn/card
 
# 从 URL 查看
npx shadcn@latest view https://registry.example.com/button.json

view 命令显示:

  • 资源元数据(名称、类型、描述)
  • 依赖和注册表依赖
  • 将被安装的文件内容
  • CSS 变量及 Tailwind 配置
  • 所需环境变量

搜索注册表

在注册表中搜索可用资源:

# 搜索特定注册表
npx shadcn@latest search @v0
 
# 带查询关键词搜索
npx shadcn@latest search @acme --query "auth"
 
# 多个注册表搜索
npx shadcn@latest search @v0 @acme @lib
 
# 限制结果数量和偏移
npx shadcn@latest search @v0 --limit 10 --offset 20
 
# 列出所有项(search 别名)
npx shadcn@latest list @acme

搜索结果包含:

  • 资源名称和类型
  • 描述
  • 所属注册表

错误处理

注册表未配置

引用未配置的注册表时:

pnpm dlx shadcn@latest add @non-existent/component

报错:

未知注册表 "@non-existent"。请确保在 components.json 中定义如下:
{
  "registries": {
    "@non-existent": "[注册表地址]"
  }
}

缺失环境变量

未设置所需环境变量时:

注册表 "@private" 需要以下环境变量:
 
  • REGISTRY_TOKEN
 
请将所需环境变量添加至你的 .env 或 .env.local 文件。

资源未找到

404 未找到:

https://registry.company.com/button.json 上的项目未找到,可能不存在于注册表中。

通常表示:

  • 资源名称拼写错误
  • 资源不存在于该注册表
  • 注册表 URL 模式错误

认证失败

401 未授权:

你无权访问 https://api.company.com/button.json
请检查认证凭证和环境变量设置。

403 禁止访问:

禁止访问 https://api.company.com/button.json
请确认 API Key 拥有相应权限。

创建你自己的注册表

要使你的注册表兼容命名空间系统,可以提供任意类型资源——组件、库、工具、AI 提示、主题、配置或其他共享内容:

  1. 实现注册表项模式:你的注册表必须返回符合 注册表项模式 的 JSON。

  2. 支持 URL 模式:你的 URL 模板中应包含 {name} 作为资源名占位。

  3. 定义资源类型:使用合适的 type 字段标识资源(如 registry:uiregistry:libregistry:airegistry:theme 等)。

  4. 支持认证(如需要):通过请求头或查询参数接受认证信息。

  5. 文档说明你的命名空间,示例如下:

components.json
{
  "registries": {
    "@your-registry": "https://your-domain.com/r/{name}.json"
  }
}

技术细节

解析器正则表达式

命名空间解析器使用以下正则:

namespace-parser.js
/^(@[a-zA-Z0-9](?:[a-zA-Z0-9-_]*[a-zA-Z0-9])?)\/(.+)$/

保证命名空间格式合法且正确提取组件名。

解析流程

  1. 解析:从 @namespace/component 提取命名空间和组件名
  2. 查找:获取 @namespace 的注册表配置
  3. 构建 URL:替换占位符为实际值
  4. 设置请求头:如果配置了认证,设置请求头
  5. 请求资源:从解析后的 URL 拉取组件资源
  6. 验证:确保响应符合注册表项模式
  7. 递归解析依赖:继续拉取所有注册表依赖

跨注册表依赖

当组件依赖多个注册表的资源时,解析器:

  1. 为每个注册表维护独立认证上下文
  2. 从各自注册表拉取依赖
  3. 基于目标路径对文件去重
  4. 合并所有来源的配置(tailwind、cssVars 等)

最佳实践

  1. 使用环境变量存储 API Key 和令牌等敏感数据
  2. 为注册表使用唯一且具描述性的命名空间
  3. 清晰文档认证需求
  4. 实现错误响应,提供友好错误提示
  5. 尽可能缓存注册表请求,提升性能
  6. 如果组件支持多主题,考虑支持样式变体

故障排除

资源找不到

  • 确认注册表 URL 正确且可访问
  • 检查 URL 中是否包含 {name} 占位符
  • 确定资源在注册表中存在
  • 资源类型应与注册表提供的内容匹配

认证相关问题

  • 检查环境变量是否正确设置
  • 验证 API Key/令牌是否有效且未过期
  • 确认请求头格式符合要求

依赖冲突

  • 审查不同注册表中同名资源
  • 使用完整命名空间资源名 (@namespace/resource) 避免歧义
  • 检查注册表间是否存在循环依赖
  • 混合不同注册表资源时确认类型兼容性