
本文介绍如何构建一个类似 shadcn 的、源码可直接集成到项目的 npm 组件库,使开发者能自由修改组件实现,而非仅使用编译后的产物。
本文介绍如何构建一个类似 shadcn 的、源码可直接集成到项目的 npm 组件库,使开发者能自由修改组件实现,而非仅使用编译后的产物。
要打造一个“可安装、可定制、源码可见”的组件库(如 shadcn/ui),核心思路并非发布编译后的 dist 文件,而是将原始 TypeScript/JSX 源码以 npm 包形式分发,并通过合理的包结构与导出配置,确保用户安装后能直接 import 并修改组件源码。
✅ 正确做法:发布源码包(Source-first Library)
- 将组件源码(
.tsx、.css、类型定义.d.ts)直接纳入package.json的"files"字段(例如:["src", "types", "package.json", "README.md"]); - 设置
"main"指向入口文件(如src/index.ts),并启用"types": "src/index.d.ts"; -
关键:不运行 tsc 构建,也不生成
dist/目录——让用户项目中的 TypeScript 和 bundler(如 Vite、Next.js)直接处理你的源码,从而支持 HMR、调试和就地编辑。
? 示例 package.json 片段:
{
"name": "@myorg/my-design-system",
"version": "0.1.0",
"files": ["src", "types", "LICENSE", "README.md"],
"main": "src/index.ts",
"types": "src/index.d.ts",
"exports": {
".": {
"types": "./src/index.d.ts",
"import": "./src/index.ts"
},
"./components/button": {
"types": "./src/components/button/index.d.ts",
"import": "./src/components/button/index.tsx"
}
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}? 用户端集成示例(Vite + React):
npm install @myorg/my-design-system
// src/App.tsx
import { Button } from "@myorg/my-design-system";
// ✅ 可直接跳转到 node_modules/@myorg/my-design-system/src/components/button/index.tsx 修改样式或逻辑⚠️ 注意事项:
- 确保
tsconfig.json中"declaration": true且tsc --noEmit或配合tsc -b生成类型声明(推荐使用typescript-project-references或@rushstack/eslint-patch保证类型一致性); - 避免在包中硬编码 CSS-in-JS 运行时逻辑(如 emotion/styled-components 的动态样式),否则会增加用户 bundle 体积;shadcn 风格推荐使用
clsx+tailwindcss的原子类组合,完全零运行时; - 提供清晰的
postinstall脚本或 CLI(如npx my-ds init)帮助用户复制组件模板(类似npx shadcn-ui@latest init),进一步强化“源码即资产”体验。
总结:这不是传统 UI 库(如 Material UI)的黑盒式分发,而是一种设计系统交付范式——把组件当作可复刻、可演进的代码模板。npm 是基石,但真正价值在于源码透明、零构建耦合、与用户工程深度协同。

















