一些 npm 包发布经验

2,397 阅读8分钟

本文首发于我的个人博客

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

在 npm 包开发及发布中,或多或少都会遇到一些问题。在此,我将本人一些经验分享给大家。

开发前准备

如何选择开源许可?

开发并发布一个 public npm package ,就代表将相关代码进行开源,那这个时候代码的开源许可就是第一步。

对于一些常用开源许可及其约束,可参考各种开源协议介绍 以及 Open Source Initiative

以我的经验来说,严格一点的限制就是 GPL ,宽松一点的就是 MIT。

GPL 代表代码及代码衍生品必须是开源的。MIT 代表代码的衍生品或代码本身可以被销售、闭源。

我个人采用的都是 MIT 协议。

对开发及发布目录的设定

npm 的开发和发布目录可以是两个分开,也可以是共用一个。

一般两个分开的是使用 ts 开发,使用 tsc 进行编译。或者开发后使用 webpack 之类的编译工具进行混淆编译或压缩。这时候就会存在两个目录,源代码目录(一般是 src )和编译后代码目录(一般是 lib )。

如果共用一个,则代表代码不需要编译,直接发布。

在对目录进行设定时,需要注意 package.json 中的 main 和 types 以及 files 字段。main 代表着 js 环境下的工程入口,types 代表着 ts 环境下 声明文件入口, files 代表需要发布的文件。

在一般不太规范的项目中,这两个字段即使配置错了,也无伤大雅。因为启动时都是直接从工程入口启动。但是如果你的工程是一个 npm 包,需要被他人引用的情况下,这里就需要注意了。

如果你是编译后发布的话,main 和 types 这两个字段代表着是你编译后目录下的工程入口。如果是不编译直接发布,这两个字段代表着你源代码的工程入口。

如果不配置好这三个字段的话,则可能会出现以下问题:

  • 发布了 npm 包,结果安装后发现里面是空的。(files 没配置好)
  • 发布了 npm 包,结果安装后发现里面有文件,但是引用不到。(main 和 typs 没有配置好)
{
    "main": "lib/index.js",
    "types": "lib/index.d.ts",
    "files": [
        "lib/*"
    ]
}

版本管理

npm 的版本管理有以下特点:

在发布版本时不建议通过在版本号后面加 -alpha 这样的方式来标明预发布版本,可以通过使用 preid 的方式来实现指定预发布版本。

在发布版本时,很多小伙伴可能会有一个初始版本的困惑。即,我的第一个版本应该是多少?

我的个人建议是 0.0.0,从 semver 规范 来说,推荐使用 0.1.0,但是我认为 0.1.0 其实代表已经开发出一部分功能了,如果从 0.1.0 开始,则代表从已经拥有部分功能的基础上开发,这样相当于我开发了一个版本,但是已经有两个版本了。但是一开始我们是一穷二白的,0.0.0 可以不视为一个版本号,可以将开发完一部分功能后的第一个版本定为 0.1.0,而不是将初始版本定为 0.1.0

包括从 0.y.z 切换为 1.y.z,可以不一定按照官方说的正式版本必须是 1.y.z ,axios 到目前为止也都是 0.y.z,这一块也是见仁见智,只要在文档中说明你目前的版本状态即可。

当然,以上只是个人建议。

Script

package.json 的 script 是一个非常强大的工具字段。你可以在里面去配置每次 publish、commit 前要做的操作,比如检查代码,格式化代码、运行测试用例等等。通过这样的手段来确保你提交的是一份质量较高的代码。

在发布、编译、更改版本前后的 hook,可以参考 npm 的生命周期。如果是需要在 commit 前进行自动化操作,可以通过安装 pre-commit 来实现。

私有包 和 scope 包

如果你想发布的是一个私有包,在公司或组织内部使用的话,你可以发布私有包。

私有包有几种发布方式:

如果你是一名有钱银,开通了 npm 付费账号,可以通过发布 发布 scope 包,发布为私有包

开发中

完成了上面几个操作,就可以愉快的敲代码了。

开发中基本没什么坑,即使有坑,一般都是对 js 特性了解不全。

开发后

开发后就是需要做一些比较痛苦,比如:

编译

如果使用 ts 开发,使用 tsc 进行编译时,需要注意一个问题,如果你存在不直接引用的代码,需要在 tsconfig.json 中特别标明,如果你涉及到了自定义模版文件的处理,那你需要在编译后通过脚本或其他方式手动将文件 copy 过去。

文档

作为一个对外提供服务的包,你需要有一个比较详尽的文档。关于文档方面,我的做法如下:

  • 每完成一个版本,完善当前版本相应的文档,包括但不限于:

    • 整体包的介绍。
    • 包的方法或类的具体名称、调用方式、作用等。
    • 相关的代码示例。
  • 文档的表现形式一般如下:

    • 对于中大型项目,比如一个框架,一个比较复杂的工具库,采用文档网站搭建的形式提供文档,使用 README 作为文档访问入口,文档网站并不需要去购买专门的服务器或域名,直接使用 github 的静态网站服务就可以。推荐使用 vuepress,可配合 github 使用
    • 对于小型项目,比如一个小的工具库,直接使用 README 来编写即可。
    • 综合来说,就是:能用一个 README 写完的就用 README,需要开多份文档文件写完的就直接使用 vuepress 建立文档网站。
  • 要想写好文档,README是重中之重,因为 README 代表的是一个项目的脸面,不管 github 还是 npm ,首先看到的都是 README。README 不规范,多半也没兴趣再深入了解。对于标准的 README 可以参考 standard-readme

    当然,也不必完全照抄,可以加入一些自己的理解,根据项目实际情况做一些调整。比如我的这几个项目@eliassama/regexnpm-package-clicomsvr-astcomsvr-random

测试

一个好的项目,将近 1/3 的时间都在测试。不过对于个人来说,虽然未必有这么严苛,但是基础的测试还是要的,总不能发布的代码都有问题,那别人还用个罗永浩?

测试建议采用自动测试,推荐使用 jest,并且配置好,每次编译后、commit 前、publish 前都执行下自动化测试,避免提交问题代码。

对于一些不方便测试的,比如 cli 工具,也要在改完后尽可能去测一下。

记住测试的时候,如果你存在编译后文件,一定要去引用编译后的文件去测试,这样你才会发现一些问题,比如部分文件没有编译进去等等。

打 tag

当你测试完没问题,文档也写完的情况下,不要忘记打个 tag,以此来标识你的一个稳定或预发布版本。

发布

在正式发布前,你需要自己去核对以下问题:

  • 当前的代码目录下是最新代码吗?(因为我双分支切换,dev 分支开发,main 分支进行打包发布,所以有时候切到 main 上会忘记pull。)
  • 如果是第一次发包,请确定工程入口、包名、私有/公有属性、git url 地址、编译后目录内文件、版本号是否都是准确无误的。(别问我为啥说这个,你敢信我曾经连续发了三个版本没发对。。。)
  • 如果你是多个账号,请确认发包账号是否是预期的。
  • 检查下 readme 的错别字或者描述,发版后,不可能因为一个 readme 再搞一次的。
  • 部分文件即使你指明了,也无法发布。如果你想将它们作为模版文件或其他原因必须发布的话,建议改名。参考npm publish 会忽略的文件

当你走到这一步,就代表你已经正式的发布了一个版本,后续的维护和发版,只需要再次按照这些步骤操作就可以了。

我使用我自己开发的一个 cli 工具 npm-package-cli 初始化了一个 npm packag 模版仓库 npm-package-template。有兴趣的可以参考,或提出一些建议。