NPM
如何将你的组件发布到 NPM。
NPM 包代表了分发组件库的传统方法。虽然 注册表 因其灵活性而越来越受欢迎,但 npm 发布仍然是一种在某些用例下具有显著优势的强大选项。
npm 包与注册表之间的根本区别在于它们如何分发代码并管理所有权。
包模型
当你将组件作为 npm 包发布时,你是在分发预构建、版本化的代码,用户将其作为依赖安装:
npm install @acme/ui-componentsimport { Button } from '@acme/ui-components'
// Component is imported from node_modules
// Source code is not directly editable这提供了若干显著优势,使其成为许多组件库的合适选择。
版本管理
作为包的作者,你控制版本和更新。用户可以锁定特定版本,以确保稳定性:
{
"dependencies": {
"@acme/ui-components": "^2.1.0"
}
}这种集中式的版本控制意味着你可以推送更新、安全补丁和新功能,用户通过标准的依赖更新即可获得这些更改。
简化安装
NPM 包提供了无摩擦的安装体验。一个命令就可以添加整个组件库:
npm install @acme/ui-components无需手动复制文件、管理依赖或配置构建工具。一切开箱即用。
依赖解析
NPM 会自动处理传递依赖。如果你的组件需要特定版本的 React、Framer Motion 或其他库,npm 会自动解析这些依赖,防止版本冲突。
TypeScript 支持
已发布的包可以包含预构建的类型定义,从而在无需额外配置的情况下立即提供 TypeScript 支持:
{
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
}
}NPM 包的局限性
尽管 npm 包在分发方面表现出色,但它们也有权衡,注册表正是为了解决这些问题而提出的。
源代码所有权
最显著的限制是缺乏源代码访问。用户无法:
- 直接修改组件行为
- 在不等待更新的情况下修复错误
- 自定义实现细节
- 删除未使用的代码
这会创建一种依赖关系,用户必须依赖包维护者来进行所有更改。
自定义限制
对组件进行微调需要在公开的 API 范围内进行。虽然你可以通过 props 提供定制:
<Button
variant="primary"
size="large"
className="custom-styles"
/>但用户无法在不派生整个包(fork)的情况下从根本上改变组件的工作方式。
包体积
NPM 包包含所有组件,即使用户只需要其中的一部分。虽然 tree-shaking 有所帮助,但并不总是完美,可能会给应用程序增加不必要的体重。
CSS 和 Tailwind 配置
通过 npm 发布基于 Tailwind 的组件时,一个关键考虑点是确保样式在消费应用中正确生效。
默认情况下,Tailwind 只为它在你的项目文件中发现的类生成样式。它不会检查 node_modules,这意味着你的组件样式不会被包含。
为了解决这个问题,用户需要在他们的 Tailwind 配置中添加一个 @source 指令,告诉它扫描你的包以查找类名:
@import "tailwindcss";
/* Tell Tailwind to look for classes in your package */
@source "../node_modules/@acme/ui-components";务必在你的包的 README 中显著记录此要求。
发布你的组件库
要将你的组件发布到 npm,你需要一个配置正确的 package.json,可能如下所示:
{
"name": "@acme/ui-components",
"version": "1.0.0",
"description": "A collection of accessible React components",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./styles.css": "./dist/styles.css"
},
"files": [
"dist"
],
"scripts": {
"build": "tsup",
"prepublishOnly": "npm run build"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"dependencies": {
"clsx": "^2.0.0",
"tailwind-merge": "^2.0.0"
},
"devDependencies": {
"tsup": "^8.0.0",
"typescript": "^5.0.0"
}
}NPM 包仍然是组件生态系统的重要组成部分。尽管注册表在源代码所有权和定制性方面提供了令人信服的好处,npm 包则提供了许多团队所需的稳定性、版本管理和易用性。
关键在于了解你的用户的需求并选择最能满足他们的分发方式。有时,这意味着同时提供两种选项,让开发者根据项目选择最合适的方法。