94.2k

命名空间

上一页下一页

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

命名空间注册表允许您在一个项目中配置多个资源源。这意味着您可以从各种注册表安装组件、库、实用程序、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"
}

入门

安装资源

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

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

身份验证方法

持有者令牌 (OAuth 2.0)

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

标头中的 API 密钥

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", // ✅ 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: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, etc.)

最佳实践

  1. 使用环境变量 用于敏感数据,如 API 密钥和令牌
  2. 为您的注册表命名空间,使用独特且具有描述性的名称
  3. 清晰地记录身份验证要求,以便用户参考
  4. 实施适当的错误响应,并提供有用的消息
  5. 尽可能缓存注册表响应 以提高性能
  6. 如果您的组件有多个主题,请支持样式变体

故障排除

未找到资源

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

身份验证问题

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

依赖项冲突

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