- 手风琴
- 提示
- 警告对话框
- 宽高比
- 头像
- 徽章
- 面包屑导航
- 按钮
- 按钮组
- 日历 Calendar
- 卡片
- 轮播图
- 图表 Chart
- 复选框
- 折叠面板
- 组合框
- 命令
- 上下文菜单
- 数据表格 Data Table
- 日期选择器 Date Picker
- 对话框 Dialog
- 方向
- 抽屉
- 下拉菜单
- 空状态
- 字段
- 悬停卡片
- 输入
- 输入组
- Input OTP
- 项目
- Kbd
- 标签
- 菜单栏
- 原生选择框
- 导航菜单 Navigation Menu
- 分页
- 弹出框
- 进度 Progress
- 单选框组
- 可调整大小
- 滚动区域 Scroll Area
- 选择框
- 分隔符 Separator
- 侧边栏 Sheet
- 侧边栏 Sidebar
- 骨架屏
- 滑块
- Sonner
- 加载指示器 Spinner
- 开关
- 表格
- 标签页 Tabs
- 文本域
- 吐司
- 切换按钮 Toggle
- 切换组
- 提示 Tooltip
- 排版
shadcn CLI 支持 包导入,用于安装组件、重写导入以及解析第三方注册表。
包导入让你可以使用 package.json 中私有的 #... 导入别名,而不是在 tsconfig.json 中使用 compilerOptions.paths。
示例#
你可以在 package.json 中配置 imports:
{
"imports": {
"#components/*": "./src/components/*.tsx",
"#lib/*": "./src/lib/*.ts",
"#hooks/*": "./src/hooks/*.ts"
}
}然后使用 #... 标识符导入生成的组件:
import { Button } from "#components/ui/button"
import { cn } from "#lib/utils"包导入标识符必须以 # 开头。请使用 TypeScript 5 或更高版本,并将
moduleResolution 设为 "bundler",同时启用 resolvePackageJsonImports: true。
应用#
适用于 Next.js、Vite 和 TanStack Start 应用,这些应用会将组件安装到同一个工作区中。
配置 package.json#
为 shadcn/ui 的安装目标添加 imports。
{
"imports": {
"#components/*": "./src/components/*.tsx",
"#lib/*": "./src/lib/*.ts",
"#hooks/*": "./src/hooks/*.ts"
}
}如果你的应用不使用 src 目录,请从目标路径中移除 src/。例如:
{
"imports": {
"#components/*": "./components/*.tsx",
"#lib/*": "./lib/*.ts",
"#hooks/*": "./hooks/*.ts"
}
}配置 TypeScript#
启用包导入解析。
{
"compilerOptions": {
"moduleResolution": "bundler",
"resolvePackageJsonImports": true
}
}对于这些别名,你不需要 compilerOptions.paths。
配置 components.json#
在 components.json 中使用相同的 #... 根路径。
{
"aliases": {
"components": "#components",
"ui": "#components/ui",
"lib": "#lib",
"hooks": "#hooks",
"utils": "#lib/utils"
}
}ui 别名使用 #components/ui。它仍然会被 package.json 中的
#components/* 导入所覆盖。
utils 别名使用 #lib/utils。它会被 #lib/* 覆盖,因此你不需要单独的
#utils 导入。
单仓库#
在单仓库中,对每个包内部的文件使用包导入,对在各工作区之间共享的文件使用包导出。
对于应用工作区:
{
"name": "web",
"private": true,
"imports": {
"#components/*": "./src/components/*.tsx",
"#lib/*": "./src/lib/*.ts",
"#hooks/*": "./src/hooks/*.ts"
},
"dependencies": {
"@workspace/ui": "workspace:*"
}
}{
"aliases": {
"components": "#components",
"ui": "@workspace/ui/components",
"lib": "#lib",
"hooks": "#hooks",
"utils": "@workspace/ui/lib/utils"
}
}对于共享 UI 包:
{
"name": "@workspace/ui",
"private": true,
"imports": {
"#components/*": "./src/components/*.tsx",
"#lib/*": "./src/lib/*.ts",
"#hooks/*": "./src/hooks/*.ts"
},
"exports": {
"./globals.css": "./src/styles/globals.css",
"./components/*": "./src/components/*.tsx",
"./lib/*": "./src/lib/*.ts",
"./hooks/*": "./src/hooks/*.ts"
}
}{
"aliases": {
"components": "#components",
"ui": "#components",
"lib": "#lib",
"hooks": "#hooks",
"utils": "#lib/utils"
}
}当你从 apps/web 执行 add 时,应用本地文件使用 #... 导入,
共享的 UI 文件则从 @workspace/ui 导入。
import { Button } from "@workspace/ui/components/button"
import { LoginForm } from "#components/login-form"文件扩展名#
package.json#imports 中的目标模式会控制生成的导入是否包含文件扩展名。
{
"imports": {
"#components/*": "./src/components/*.tsx"
}
}这会生成不带扩展名的导入:
import { Button } from "#components/ui/button"如果你使用不带扩展名的目标:
{
"imports": {
"#components/*": "./src/components/*"
}
}生成的导入会保留源文件扩展名:
import { Button } from "#components/ui/button.tsx"对于大多数应用,建议在目标模式中使用扩展名。
故障排查#
如果 TypeScript 无法解析 #... 导入,请检查以下内容:
- 标识符是否以
#开头 imports条目是否位于最近的package.json中moduleResolution是否设置为bundler- 是否已启用
resolvePackageJsonImports - 添加组件后是否存在匹配的目标路径
如果组件已安装,但导入仍然指向 @/...,请检查 components.json 是否使用了与你的包导入相同的 #... 别名。