前言
npm(node package manager)作为 Node.js 的包管理工具,让世界各地的 JavaScript 开发者方便复用、分享代码以及造轮子;本文将介绍如何发布一个 npm 包,以及使用工具来自动化管理发布 npm 包;本文总览如下:
- 准备 npm 账号 & 示例包代码;
- 初始化 & 配置 package.json 文件;
- 确定发布的包版本;
- 发布 npm 包;
- 使用 cli 工具 release-it 来自动管理版本、发布包等;
- 学习 npm init release-it 原理。
准备
本地需要安装 Node.js 及 npm CLI,npm 将随 Node.js 一起安装,建议使用 Node 版本管理工具来安装 Node,例如 nvm 、n。
注册 npm 账号
第一步先到 npm 注册个账号 www.npmjs.com/signup,跟着注册步骤操作就行。
示例包代码
为了整个流程相对完整,创建个 github 仓库存放代码(本文代码仓库);将仓库克隆到本地后,新建 index.js 文件,这里我们随便搞点工具函数来作为示例。
// index.js copy from @vue/shared
export const isArray = Array.isArray;
export const isMap = (val) => toTypeString(val) === "[object Map]";
export const isSet = (val) => toTypeString(val) === "[object Set]";
export const isDate = (val) => toTypeString(val) === "[object Date]";
export const isRegExp = (val) => toTypeString(val) === "[object RegExp]";
export const isFunction = (val) => typeof val === "function";
export const isString = (val) => typeof val === "string";
export const isSymbol = (val) => typeof val === "symbol";
export const isObject = (val) => val !== null && typeof val === "object";
export const toTypeString = (val) => Object.prototype.toString.call(val)
复制代码
创建 & 配置 package.json
要发布一个 npm 包,需要创建一个 package.json 文件,用来描述包信息及依赖包。使用 npm init -y
命令创建一个默认的 package.json 文件,默认生成内容如下:
{
"name": "utils", // 包名,必填且唯一
"version": "1.0.0", // 版本号,必填,需遵循语义化版本规范
"description": "", // 包描述信息,利于包检索
"main": "index.js", // 入口文件,不设置默认为根文件夹下的 index.js
"scripts": { // 脚本命令
"test": "echo "Error: no test specified" && exit 1"
},
"repository": { // 项目代码仓库
"type": "git",
"url": "git+https://github.com/jizai1125/joker1125-utils.git"
},
"keywords": [], // 关键字,利于包检索
"author": "", // 作者信息
"license": "ISC", // 许可证协议
"bugs": { // 问题反馈地址
"url": "https://github.com/jizai1125/joker1125-utils/issues"
},
// 项目主页
"homepage": "https://github.com/jizai1125/joker1125-utils#readme"
}
复制代码
修改为如下,这里只填写了一些字段,根据项目需要配置。
{
"name": "@joker1125/utils", // 这里为了避免包名冲突,加上命名空间 joker1125
"version": "1.0.0",
"description": "js utility functions",
"keywords": ["utils", "js-utils"],
"main": "index.js",
"author": "joker1125",
"repository": {
"type": "git",
"url": "git+https://github.com/jizai1125/joker1125-utils.git"
},
"author": "joker1125",
"license": "ISC",
"bugs": {
"url": "https://github.com/jizai1125/joker1125-utils/issues"
},
"homepage": "https://github.com/jizai1125/joker1125-utils#readme"
}
复制代码
要发布一个npm 包,name 和 version 字段是必填的;
包名(name 字段)命名规则:
- 包名长度不能超过 214 个字符(命名空间也算在里面);
- 包名所有字符必须小写;
- 包名可以由连字符
-
组成; - 包名不能包含空格,不能以
.
或者_
开头,不能包含~)('!*
中的任意一个字符; - 包名不能包含任何非 url 安全字符(因为包名将作为 url 的一部分);
- 包名不能与 Node.js / io.js 的核心模块、保留字或黑名单相同,例如
http
。
可以使用 validate-npm-package-name 包来检查包名是否合法
版本号(version 字段)则需要遵循 semver 规范。
可以使用 node-semver 来检查
扩展阅读:
- npm Docs - package.json
- New Package Moniker rules 译文 新的包名规则
- semver 规范
确定版本号
填写好 package.json 字段后,接下来就是确定我们要发布的版本号,每次对包的更改都应该对应一个版本。
版本号格式
格式:MAJOR.MINOR.PATCH
,值非负整数,且禁止在数字前面补 0
MAJOR
:主版本号MINOR
:次版本号PATCH
::修订号
版本号递增逻辑
- 当有破坏性不兼容的 API 变更时,升级主版本号
- 当新增一些功能特性时,升级次版本号
- 当做一些 bug 修复时,升级修订号
当某个版本还不稳定的时候,还可能要先发布一个先行版本,具体可看 semver 规范。
可以使用 npm version
命令来修改版本号
npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]
复制代码
栗子 🌰
# 0.0.0 => 0.0.1
npm version patch
# 0.0.0 => 0.1.0
npm version minor
# 0.0.0 => 1.0.0
npm version major
# 0.0.0 => 0.0.1-0
# === 先行版本 ===
npm version prepatch
# 0.0.0 => 0.0.1-alpha.0
npm version prepatch --preid=alpha
# 0.0.1-alpha.0 => 0.0.1-alpha.1
npm version prerelease
复制代码
命令行选项:
--preid
指定先行版本的标识符,例如1.2.3-rc.4
中的rc
-m 或 --message
可以指定 commit 信息,例如npm version patch -m "Upgrade to %s for reasons”
;-no-git-tag-version
取消创建 git tag 和 commit 信息- ...
其他说明:
- 执行
npm version
命令时,会修改package.json
、package-lock.json
的version
字段为对应版本;若当前使用 git 来管理文件,还会创建一条 commit 信息和创建一个 tag,可通过指定-no-git-tag-version
取消生成 commit 和 tag。 - 执行
npm version
前,git 工作区和暂存区确保没有文件,否则会执行失败。
相关地址:
- npm CLI - npm version
- npm semver 版本号在线测试工具
发布 npm 包
npm 登录 & 确定源地址
使用 npm login
命令登录,如下图
因为我们要发布到官方源上面,所以要确保源地址为官方地址 http://registry.npmjs.org
或 https://registry.npmjs.com
,可以通过 npm config get registry
命令查看当前 registry 源。
如需修改 registry 可通过以下四种方式:
-
在全局配置
.npmrc
,可通过命令npm config set registry= http://registry.npmjs.org/
; -
在当前项目配置,在当前项目中添加配置文件
.npmrc
;// .npmrc registry = http://registry.npmjs.org/ 复制代码
-
发布包时指定
--registry
选项,npm publish —registry=http://registry.npmjs.org/
; -
在当前项目的
package.json
中通过publishConfig
字段指定。// package.json { ”publicConfig“: { "registry": "http://registry.npmjs.org/" } } 复制代码
发布版本
通过命令 npm publish
发布包
npm publish --access public
复制代码
本文示例使用的命名空间为 joker1125
,在发布时需要指定声明为公有包,因为发布带有命名空间的包 npm 会默认为是要发布私有包,发布私有包需要另外付费的哦!
这里我们通过命令行选项 --access public
声明为公有包,也可通过 package.json 中的 publicConfig
字段配置声明。
以上就是手动发布一个最简单的 npm 包的大致步骤,下面我们借助 cli 工具 release-it 来自动发布。
扩展阅读:
- npm Docs - Publishing scoped packages
使用 cli 工具 release-it
release-it 工具可以用来升级包版本、生成 changgelog、Git commit \ tag \ push、发布包等。
在项目中运行命令 npm init release-it
, 如下:
选择完之后将会自动安装 release-it 包、在 package.json 中加入脚本命令 "release": "release-it”
、及生成一个 .release-it.json
初始配置文件。
在 .release-it
添加以下配置(查看更多配置见 release-it - Configuration),并安装生成 changelog 的插件npm i @release-it/conventional-changelog -D
{
"github": {
"release": true
},
"git": {
"commitMessage": "Release: v${version}"
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": "angular",
"infile": "CHANGELOG.md"
}
}
}
复制代码
因我们发布的包带有命令空间,所以还需要在 package.json 中添加如下配置,声明一下为公有包
{
"publishConfig": {
"access": "public"
}
}
复制代码
然后运行命令 npm run release
,跟着步骤操作选择,之后就会自动生成 changelog、修改包版本、git commit 信息、打 tag、创建 github release、发布包;如下图,至此就完成了 npm 包的自动发布。
npm init release-it 原理
我们前面使用npm init
创建了一个 pakage.json 文件,其实 init 后面还可以接一个参数 <initializer>
,该命令格式为:
# npm v6 版本给该命令添加了别名 npm create
npm init <initializer>
复制代码
initializer 是名为 create-<initializer>
的 npm 包 ( 例如 create-react-app
, create-vite
),如果缺省该参数的话(也就是只运行 npm init),就会回退到 init 的默认行为,即询问一系列问题,然后创建 package.json 文件,当然我们加上 -y
/ --yes
参数,就会跳过这些问题。
执行 npm init <initializer>
将会被转换为对应的 npm exec
操作,即会使用 npm exec
来运行 create-<initializer>
包。例子:
# 使用 create-react-app 包创建一个名为 my-react-project 的项目
$ npm init react-app ./my-react-project
# 等同于
$ npm exec create-react-app ./my-react-project
# 等同于
$ npx create-react-app ./my-react-project
复制代码
init 命令在 npm 版本中的区别:
- v6.x: 会使用
npx
安装该包,并执行该包的 bin。 - v7+: 使用
npm exec
命令安装该包,并执行该包 bin。
npx 命令介绍:
用于运行 npm 包的命令(本地未安装要运行的包则从远程拉取),例如执行
npx create-vite my-vite-app
,如果本地没有安装过create-vite
,则会先从远程拉取安装create-vite
,然后执行create-vite my-vite-app
。
啰嗦这么一大推,回到我们执行的 npm init release-it
,具体发生了什么呢?
-
使用
npx
/npm exec
执行create-release-it
包的 bin,本地未安装则先拉取该包; -
create-release-it
的 bin 字段指向 index.js 文件,index.js 脚本做的事情:
- 首先先询问一些问题,然后将配置写入
.release-it.json
文件或 package.json 中; - 接着在 package.json 中加入脚本命令
"release": "release-it”
; - 最后执行安装
release-it
包。
- 首先先询问一些问题,然后将配置写入
总结
通过本文的学习,了解如何发布一个 npm 包,以及利用 release-it 工具自动化管理版本号、发布、生成 changelog、git tag 等;最后学习了 npm init release-it
原理。