创建并发布 npm 包

npm 是 Node.js 生态的核心,拥有全球最大的开源包仓库。将自己的代码打包成 npm 包,不仅可以复用模块,还能与全世界开发者分享。本章将详细讲解如何从零开始创建、测试、发布和更新一个 npm 包。

1. 准备工作

在开始之前,确保你已经安装了 Node.js 和 npm(通常一起安装)。同时,你需要一个 npm 官网 的账号,用于发布包。

2. 创建项目结构

首先,创建一个新的目录作为你的包项目,并进入该目录:

mkdir my-npm-package
cd my-npm-package

3. 初始化 package.json

使用 npm init 命令生成 package.json 文件。按照提示填写信息,或者添加 -y 使用默认值:

npm init

生成的 package.json 示例:

{
  "name": "my-npm-package",
  "version": "1.0.0",
  "description": "一个简单的示例包",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": ["example", "npm"],
  "author": "Your Name ",
  "license": "MIT"
}

关键字段说明:

  • name:包名,必须是唯一的,不能与 npm 仓库中已有的包重名。可以通过 npm search <name> 或直接在官网搜索检查是否可用。如果需要使用作用域(如 @username/package-name),可以创建组织或个人作用域的包。
  • version:遵循语义版本控制(SemVer),初始通常为 1.0.0
  • main:包的入口文件,当其他模块通过 require('my-npm-package') 引入时,加载的就是这个文件。

4. 编写包代码

创建 index.js 作为入口文件,实现你的功能。例如,一个简单的字符串反转工具:

// index.js
function reverseString(str) {
  return str.split('').reverse().join('');
}

module.exports = reverseString;

也可以导出多个函数或对象:

module.exports = {
  reverseString,
  capitalize: (str) => str.charAt(0).toUpperCase() + str.slice(1)
};

5. 本地测试

在发布之前,强烈建议在本地项目中测试你的包。有两种常用方法:

5.1 使用 npm link

在包目录下运行 npm link,这会在全局 node_modules 中创建一个符号链接。然后在另一个测试项目中运行 npm link my-npm-package,即可引入本地包。

# 在包目录
npm link

# 在测试项目目录
npm link my-npm-package

测试完成后,可以在测试项目中通过 require('my-npm-package') 使用,并验证功能。

5.2 使用相对路径安装

在测试项目的 package.json 中直接添加依赖路径:

"dependencies": {
  "my-npm-package": "file:../my-npm-package"
}

然后运行 npm install,npm 会将该包复制到 node_modules 中。

6. 添加必要文件

6.1 README.md

一个好的包应该包含 README.md 文件,说明包的用途、安装方法、使用示例和 API 文档。npm 官网会展示这个文件的内容。

6.2 .gitignore

如果使用 Git 版本控制,应该忽略 node_modules 等目录。常见的 .gitignore 内容:

node_modules/
.DS_Store
*.log

6.3 指定哪些文件被发布

可以通过 .npmignore 文件或 package.json 中的 files 字段来限制发布到 npm 的文件。推荐使用 files 白名单:

{
  "files": [
    "index.js",
    "lib/",
    "README.md",
    "LICENSE"
  ]
}

这样只有列出的文件会被包含,避免发布测试文件或源码。

7. 注册 npm 账号

如果你还没有 npm 账号,可以在终端中注册:

npm adduser

按照提示输入用户名、密码和邮箱。注册成功后会自动登录。也可以在 npm 官网 注册。

8. 登录 npm

如果已经注册,使用 npm login 登录:

npm login

输入你的用户名、密码和邮箱。登录信息会保存在本地。

9. 发布包

确保所有文件准备就绪,然后运行:

npm publish

如果一切顺利,你会看到类似 + my-npm-package@1.0.0 的输出。现在你的包已经发布到 npm 仓库,全世界都可以通过 npm install my-npm-package 安装使用了。

9.1 发布作用域包

如果包名以 @username/ 开头(例如 @your-username/my-package),默认是私有的,需要付费才能发布私有包。但你可以将其公开:

npm publish --access public

或者在 package.json 中设置 "publishConfig": { "access": "public" }

10. 更新包

当你的代码有变动时,需要更新版本并重新发布。

10.1 修改版本号

使用 npm version 命令自动更新 package.json 中的版本号并创建 Git 标签(如果使用 Git)。

# 补丁版本(修复 bug)
npm version patch   # 1.0.0 -> 1.0.1

# 次要版本(新增功能,向下兼容)
npm version minor   # 1.0.1 -> 1.1.0

# 主要版本(不兼容变更)
npm version major   # 1.1.0 -> 2.0.0

也可以直接手动修改 version 字段。

10.2 重新发布

npm publish

注意:每次发布必须使用不同的版本号,否则会出错。

11. 撤销与弃用

11.1 撤销发布(unpublish)

如果发布错误,可以在 72 小时内撤销发布:

npm unpublish my-npm-package@1.0.0

撤销后,该版本将无法再被安装。请注意,撤销整个包可能导致其他项目依赖损坏,因此谨慎使用。

11.2 弃用包(deprecate)

如果某个版本存在问题,但不希望完全移除,可以弃用它,并给出提示信息:

npm deprecate my-npm-package@1.0.0 "这个版本有严重 bug,请升级到 1.0.1"

用户安装时会看到警告信息。

12. 管理包权限

如果你与他人协作,可以添加维护者:

npm owner add <username> my-npm-package

查看当前维护者:

npm owner ls my-npm-package

13. 最佳实践

  • 编写完善的文档:包括安装、示例、API 说明,放在 README.md 中。
  • 添加测试:使用 Jest、Mocha 等编写测试,并在 scripts 中配置 test 命令。持续集成可以使用 GitHub Actions 等。
  • 遵循语义版本控制:严格按照 SemVer 规范更新版本,避免依赖冲突。
  • 锁定文件范围:通过 .npmignorefiles 字段避免发布不必要的文件。
  • 使用 prepublishOnly 脚本:可以在发布前自动运行测试和构建,例如:
{
  "scripts": {
    "test": "jest",
    "build": "babel src -d lib",
    "prepublishOnly": "npm test && npm run build"
  }
}
  • 包含许可证:明确许可证类型(如 MIT),避免法律风险。
  • 考虑使用 exports 字段:在 Node.js 12+ 中,可以通过 "exports" 定义子路径导出,更加精细地控制包的入口。

14. 常见问题

  • 包名已存在怎么办?:换个名字,或使用作用域包(如 @username/package-name)。
  • 发布时提示 403 Forbidden:可能是包名已被占用,或者你没有权限发布作用域包(需要验证邮箱)。
  • 如何发布私有包?:需要付费 npm 团队版或企业版,或者使用其他私有仓库方案(如 Verdaccio)。
  • 怎样在 CI 中自动发布?:可以使用 npm publish 结合 CI 环境变量中的 token 进行身份验证,具体参考 npm 文档。
提示: 发布前可以在本地使用 npm pack 命令生成一个 tarball 文件,检查包中包含的文件是否正确。

小结

通过本章的学习,你已经掌握了从零开始创建并发布 npm 包的完整流程。从初始化项目、编写代码、本地测试,到注册账号、发布更新和撤销,每一步都至关重要。遵循最佳实践,你的包将更易于维护和使用。现在,去创造属于你自己的 npm 包吧!