Acme

命名空间

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

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

目录


概述

注册表命名空间以 @ 为前缀,提供了一种从不同来源组织和引用资源的方式。资源可以是任何类型的内容:组件、库、工具、钩子、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"
}

快速开始

安装资源

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

npx shadcn@latest add @v0/dashboard

或一次性安装多个资源:

npx 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"
  }
}

然后开始安装:

npx 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

{style} 占位符是可选的。当您想为同一资源提供不同版本时可以使用它。例如,您可以为每种样式提供不同版本的组件。


认证与安全

环境变量

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

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 Token(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"
    }
  }
}

安全考虑

当使用命名空间注册表(尤其是第三方或公共注册表)时,安全性至关重要。以下是我们处理安全的方式:

资源验证

所有从注册表获取的资源在安装前都会根据我们的注册表项 schema 进行验证。这确保:

  • 结构验证:资源必须符合预期的 JSON schema
  • 类型安全:资源类型会被验证(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. Schema 验证:必须符合注册表项 schema
  3. 文件路径限制:文件仅能写入配置的路径
  4. 无脚本执行:CLI 不执行注册表资源中的任何代码

注册表信任模型

命名空间系统基于信任模型运行:

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

注册表运营者最佳实践

如果您运行自己的注册表:

  1. 始终使用 HTTPS:切勿通过 HTTP 提供注册表内容
  2. 实现认证:私有注册表需要 API 密钥或令牌
  3. 速率限制:保护您的注册表免受滥用
  4. 内容验证:在提供资源前验证其有效性

安全注册表设置示例:

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

安装前检查资源

CLI 提供了安装前检查资源的功能。您可以使用以下命令查看注册表项的 payload:

npx shadcn@latest view @acme/button

这会将注册表项的 payload 输出到控制台。


依赖解析

基础依赖解析

资源可以跨不同注册表拥有依赖:

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)

这意味着如果您运行以下命令:

npx shadcn@latest add @acme/auth @custom/login-form

来自 @custom/login-formlogin-form.ts 会覆盖来自 @acme/authlogin-form.ts,因为它最后被解析。

覆盖第三方资源

您可以利用依赖解析流程通过在 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. 安装自定义版本

npx shadcn@latest add @my-company/custom-button

这会安装来自 @vendor/button 的原始按钮,然后用您的自定义值覆盖 cssVars

扩展而非替换

保留原始资源并添加扩展:

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 的原始表格,然后将您的扩展添加到 components/ui/table-extended.tsx

部分覆盖(多文件资源)

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

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/card - 安装到 components/ui/card.tsx
  2. @vendor/chart - 安装到 components/ui/chart.tsx
  3. @custom/card - 覆盖 components/ui/card.tsx(如果目标路径相同)

关键解析特性

  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
  • 按环境覆盖(开发、 staging、生产)

语义化版本

实现支持范围的语义化版本:

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

搜索结果包括:

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

错误处理

注册表未配置

如果您引用了未配置的注册表:

npx shadcn@latest add @non-existent/component

错误:

Unknown registry "@non-existent". Make sure it is defined in components.json as follows:
{
  "registries": {
    "@non-existent": "[URL_TO_REGISTRY]"
  }
}

缺少环境变量

如果所需环境变量未设置:

Registry "@private" requires the following environment variables:

  • REGISTRY_TOKEN

Set the required environment variables to your .env or .env.local file.

资源未找到

404 Not Found:

The item at https://registry.company.com/button.json was not found. It may not exist at the registry.

这通常意味着:

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

认证失败

401 Unauthorized:

You are not authorized to access the item at https://api.company.com/button.json
Check your authentication credentials and environment variables.

403 Forbidden:

Access forbidden for https://api.company.com/button.json
Verify your API key has the necessary permissions.

创建自己的注册表

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

  1. 实现注册表项 schema:您的注册表必须返回符合注册表项 schema的 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. 验证:确保响应符合注册表项 schema
  7. 解析依赖:递归解析来自各自注册表的依赖

跨注册表依赖

当组件具有来自不同注册表的依赖时,解析器:

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

最佳实践

  1. 使用环境变量存储敏感数据如 API 密钥和令牌
  2. 为注册表命名空间使用唯一、描述性的名称
  3. 清晰文档认证要求为用户
  4. 实现适当的错误响应带有帮助信息
  5. 缓存注册表响应以提高性能
  6. 支持样式变体如果您的组件有多个主题

故障排查

资源未找到

  • 验证注册表 URL 正确且可访问
  • 检查 URL 中是否包含 {name} 占位符
  • 确保资源存在于注册表中
  • 确认资源类型与注册表提供的一致

认证问题

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

依赖冲突

  • 检查来自不同注册表的同名资源
  • 使用完全限定名称(@namespace/resource)避免歧义
  • 检查注册表之间的循环依赖
  • 混合注册表时确保资源类型兼容