
本文介绍如何构建一个像 shadcn 一样「将源码直接注入项目」的可安装组件库,使开发者能自由修改组件逻辑与样式,而非仅调用编译后的黑盒包。核心方案是基于 npm 包管理 + 源码分发 + 本地化集成。
本文介绍如何构建一个像 shadcn 一样「将源码直接注入项目」的可安装组件库,使开发者能自由修改组件逻辑与样式,而非仅调用编译后的黑盒包。核心方案是基于 npm 包管理 + 源码分发 + 本地化集成。
shadcn/ui 并非传统意义上的“运行时 npm 包”,而是一种源码分发型设计系统——它不发布编译后的 dist 文件,而是通过 CLI 工具(如 npx shadcn-ui@latest add button)将组件源码(含 TypeScript、JSX、CSS、配置)直接复制到你的项目中。这种方式赋予你完全控制权:可修改 props、调整样式、适配主题、甚至重构内部逻辑。
要实现类似能力,关键在于跳过传统打包流程,采用“可复用源码模板 + 脚手架工具”组合:
✅ 1. 组件以源码形式组织(非构建产物)
将每个组件存为独立、自包含的文件夹(如 components/button/),包含:
-
Button.tsx(带默认导出的 React 组件) -
Button.stories.tsx(可选 Storybook 示例) -
Button.css或Button.module.css(作用域样式) -
index.ts(统一导出)
确保所有依赖(如 clsx、react-icons)列为 peerDependencies,避免版本冲突。
✅ 2. 创建轻量 CLI 工具(推荐使用 create-cli 或 zx)
例如使用 zx 编写 bin/install-component.mjs:
#!/usr/bin/env zx
import { $ } from 'zx'
const component = argv._[0]
if (!component) throw new Error('Usage: npm run install-component button')
await $`cp -r ./components/${component} ./src/components/${component}`
await $`npm install --save-dev clsx`
console.log(`✅ ${component} installed to src/components/`)
再在 package.json 中配置:
"scripts": {
"add:component": "zx bin/install-component.mjs"
}
运行 npm run add:component dialog 即可一键复制源码。
✅ 3. 发布为 npm 包(可选但推荐)
即使不提供运行时导入,仍建议发布为私有或公开 npm 包(如 @yourorg/ui),用于:
- 统一维护组件源码版本(Git tag +
npm version patch && npm publish) - 提供 CLI 全局安装:
npm install -g @yourorg/ui-cli - 支持
npx @yourorg/ui@latest add alert命令
⚠️ 注意事项:
- ❌ 不要
tsc --build或vite build输出dist/—— 这会失去可编辑性; - ✅ 所有组件必须使用相对路径导入(如
import { cn } from "@/lib/utils"),并确保项目已配置tsconfig.json的baseUrl和paths; - ✅ 推荐搭配
eslint+prettier+tsc --noEmit做类型与格式校验,保障源码质量; - ✅ 若需支持多框架(如 Vue / Solid),可按框架划分子目录(
/react/,/vue/),但 shadcn 模式默认聚焦单一技术栈。
最终效果:你的设计系统既是“可安装的包”,又是“可编辑的源码集合”。团队成员不再受限于黑盒 API,而是像维护自有代码一样持续迭代 UI 基础设施——这才是真正可持续的设计系统实践。










