109k

命名空间

配置并使用支持命名空间的多个资源仓库。

带命名空间的注册表允许你在一个项目中配置多个资源来源。这意味着你可以从各种注册表安装组件、库、工具、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://create.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 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"
    }
  }
}

安全考虑

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

资源验证

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

  • 结构验证:资源必须符合预期的 JSON 模式。
  • 类型安全:验证资源类型(registry:ui, registry: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", // ✅ Good
    "@insecure": "http://registry.example.com/{name}.json" // ❌ Avoid
  }
}

内容安全

来自注册表的资源被视为数据,而非代码。

  1. 仅 JSON 解析:资源必须是有效的 JSON。
  2. 模式验证:必须符合注册表项模式。
  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 提供安装内容的透明度。你可以使用以下命令查看注册表项的有效负载:

pnpm dlx shadcn@latest view @acme/button

这会将注册表项的有效负载输出到控制台。


依赖解析

基本依赖解析

资源可以拥有跨越不同注册表的依赖关系。

registry-item.json
{
  "name": "dashboard",
  "type": "registry:block",
  "registryDependencies": [
    "@shadcn/card", // From default registry
    "@v0/chart", // From v0 registry
    "@acme/data-table", // From acme registry
    "@lib/data-fetcher", // Utility library
    "@ai/analytics-prompt" // AI prompt resource
  ]
}

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/authlogin-form.ts,因为它是最后被解析的。

覆盖第三方资源

你可以利用依赖解析过程覆盖任何第三方资源,方法是将它们添加到你的自定义资源下的 registryDependencies 中,并使用你自己的自定义值进行覆盖。

示例:自定义第三方按钮

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

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

button.json
{
  "name": "button",
  "type": "registry:ui",
  "files": [
    {
      "path": "components/ui/button.tsx",
      "type": "registry:ui",
      "content": "// Vendor's button implementation\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" // Import original first
  ],
  "cssVars": {
    "light": {
      "--button-bg": "purple" // Override the color
    }
  }
}

3. 安装你的自定义版本:

pnpm dlx 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// Add your extensions\nexport function ExtendedTable() { ... }"
    }
  ]
}

这将安装来自 @vendor/table 的原始表格,然后将你的扩展添加到 components/ui/table-extended.tsx

部分覆盖(多文件资源)

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

custom-auth.json
{
  "name": "custom-auth",
  "registryDependencies": [
    "@vendor/auth" // Has multiple files
  ],
  "files": [
    {
      "path": "lib/auth-server.ts",
      "type": "registry:lib",
      "content": "// Your custom auth server"
    }
  ]
}

解析顺序示例

当你安装依赖于多个资源的 @custom/dashboard 时:

dashboard.json
{
  "name": "dashboard",
  "registryDependencies": [
    "@shadcn/card", // 1. Resolved first
    "@vendor/chart", // 2. Resolved second
    "@custom/card" // 3. Resolved last (overrides @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
  • 针对每个环境(开发、预发、生产)进行覆盖

语义化版本控制

实现支持范围的语义化版本控制。

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 提供了几个用于处理命名空间注册表的命令。

添加资源

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

# Install from a specific registry
npx shadcn@latest add @v0/dashboard
 
# Install multiple resources
npx shadcn@latest add @acme/button @lib/utils @ai/prompt
 
# Install from URL directly
npx shadcn@latest add https://registry.example.com/button.json
 
# Install from local file
npx shadcn@latest add ./local-registry/button.json

查看资源

安装前检查注册表项。

# View a resource from a registry
npx shadcn@latest view @acme/button
 
# View multiple resources
npx shadcn@latest view @v0/dashboard @shadcn/card
 
# View from URL
npx shadcn@latest view https://registry.example.com/button.json

view 命令显示:

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

搜索注册表

搜索注册表中可用的资源。

# Search a specific registry
npx shadcn@latest search @v0
 
# Search with query
npx shadcn@latest search @acme --query "auth"
 
# Search multiple registries
npx shadcn@latest search @v0 @acme @lib
 
# Limit results
npx shadcn@latest search @v0 --limit 10 --offset 20
 
# List all items (alias for search)
npx shadcn@latest list @acme

搜索结果包括:

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

错误处理

注册表未配置

如果你引用了未配置的注册表。

pnpm dlx 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 未找到

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

这通常意味着:

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

认证失败

401 未授权

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

403 禁止访问

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

创建你自己的注册表

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

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

  2. 支持 URL 模式:在你的 URL 模板中包含 {name},以便插入资源名称。

  3. 定义资源类型:使用适当的 type 字段来标识你的资源(例如 registry:ui, registry:lib 等)。

  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 密钥和令牌等敏感数据使用环境变量
  2. 用唯一、描述性的名称命名你的注册表
  3. 为用户明确记录认证要求
  4. 实施带有有用消息的正确错误响应
  5. 尽可能缓存注册表响应以提高性能。
  6. 如果你的组件有多个主题,请支持样式变体

故障排除

资源未找到

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

认证问题

  • 确认环境变量设置正确。
  • 验证 API 密钥/令牌是否有效且未过期。
  • 检查标头是否以正确的格式发送。

依赖冲突

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