无脑发布 npm
npm init新建一个包,改把改把,然后来个npm publish
,so easy ✌️!
请容我讲述一些发布过程中踩过的坑。
npm的配置文档。
通用性👷
指定发布文件
利用package.json
中files
字段精简发布体积。
{
"files": ["dist", "lib", "module"]
}
若不指定files
,每次发布会把所有不以.
开头的文件都发布出去,导致发布体积过大(node_modules
默认也不会被发布)。
README.md作为主文档,加不加都会发布,package.json
也是。
指定源代码
{
"source": "src/index.ts",
"repository": {
"type": "git",
"url": "https://github.com/yourname/yourproject.git"
}
}
通常来说我是不在npm
发布中包括源代码的,因此都没有加过source
字段,只是用repository
来告知一下git
仓库地址即可。
source字段就有用了,将源代码发布后可让人帮忙debug
找问题。
source,则files
也要加上souce
对应的文件或文件夹。
发布sourcemap
sourcemap文件,例如发布了一个dist/index.js
则也需要一个dist/index.js.map
文件与之配套。
指定安装源
利用.npmrc
指定安装源,用于当前项目与你的全局配置区分开。
npm源,导致外部用户无法利用lock
文件安装。
registry=https://registry.npmjs.org/
精确指定dependencies
、devDependencies
、peerDependencies
dependencies
要尽量少,只有在运行时确实用到才放进去。"react": "16.x || 17.x"
"react": "17.0.0",则在使用了
react
16的项目中,会引入两份react
,造成一些莫名其妙的问题。react应放到
peerDependencies
中。指定发布目标
在
package.json
中指定发布地址,在当前包与全局配置不一致时非常必要。{ "publishConfig": { "registry": "https://registry.npmjs.org" } }
sideEffects
对应配置:
{ "sideEffects": false }
作用:在打包时进行
treeshake
可根据是否使用而优化相关的代码。sideEffects为
true
,则一旦引入,不管是否调用都不能被treeshake
掉。专用性🥷
类型配套
记得生成类型的
.d.ts
文件,并在package.json
中指定。{ "types": "type/index.d.ts", "typings": "type/index.d.ts" }
我一般会用一个专用的
tsconfig.declaration.json
来专门生成类型:{ "extends": "./tsconfig.json", "compilerOptions": { "noEmit": false, "emitDeclarationOnly": true, "declaration": true, "outDir": "types" } }
作为后端库
package.json
中指定main
字段。nodejs环境中运行,输出
commonjs
格式模块。esmodule格式模块。
{ "main": "lib/index.js", "module": "module/index.js", "jsnext:main": "module/index.js" }
module
与jsnext:main
都是指esmodule
格式,只是为了兼容某些特殊环境的别名。可能还有其他别名单我暂时就见过这俩。module中的文件推荐使用特定的后缀名,例如
.esm.js
或.mjs
,但在一些工程相关工具中是否会有未知为题,不好说。module指定的文件,单如果没有指定
module
,也会为了兼容去加载main
。作为前端库
因为现代前端开发环境要求支持所有后端环境,并延伸出前端环境的额外支持。也就是说后端库要求一般是前端库要求的子集。
amd已经被淘汰可以不用考虑,现在基本都被
umd
格式统一。{ "main": "lib/index.js", "module": "module/index.js", "unpkg": "dist/index.js", "umd:main": "dist/index.js", "jsdelivr": "dist/index.umd.production.min.js" }
其中
unpkg
,umd:main
,jsdelivr
都是为了更广泛兼容的指向浏览器环境运行的同一个目标别名。commonjs,
esmodule
,umd
都不会将其依赖的其他包包括进去,只是在运行时才加载。independent(取名叫
standalong
也比较合适)格式,将这个包的所有依赖都封装进去,可以不依赖外部环境独立使用。mobx-value的独立运行文件。
注意浏览器环境输出的都是优化后的
.production.min
格式,也必须同时输出.development
后缀的开发模式,为了方便使用者调试方便。作为命令行工具
多配置兼容
命令行工具一般需要很多参数,例如
tsc
,当参数过多时没人愿意每次都输入长长的参数,因此需要配置文件的支持。此时cosmiconfig隆重登场!以一句名言形容,小孩子才做选择,成年人全都要!
api。
json配置,不要用原生的
JSON.parse
,很多json
是带注释的或者编写不规范,用json5
读取兼容好。配置文件类型校验
刚入门
typescript
时,我尝试用typescript
作为配置文件,然后在运行时利用类型机制达到校验配置的目的。typescript环境与应用所在的
typescript
环境不一致,也导致了很多工程问题(对我说的就是ts-gear
)。js文件中也同样可以校验类型,而且
js
文件对运行时更友好。webpack.config.js这样配置
/** * @type {import('webpack').Configuration} * */ const config = {...} export default config
配置文件运行时校验
我们的程序要读配置,但配置是使用者提供的,谁知道用户会写些什么,即使有上面那步提到的类型校验把关,也会有很多边界问题类型根本管不了。
不光是校验不通过时终止运行,还必须给出一个合理且精准的错误提示。
协议是
json schema
,校验工具为joi
或ajv
,提示输出工具为chalk
。指定可运行文件
package.json中指定
bin
:{ "bin": "bin/run.js" }
对于大部分js脚本,都要在运行文件头部指定运行环境。
#! /usr/bin/env node
然后别忘了在发布前添加可执行属性,务必整合在自动化发布脚本中。
chmod +x bin/run.js
可调用api
例如
babel
,我们不光能使用@babel/cli
在命令行使用,也可以在自己的程序里import babel from 'babel'
来调用其api
。其他特定环境
例如针对
react-native
,这个我就见过,没实际用过。{ "react-native": "dist/index.esm.js" }
最后不论什么格式,都记得输出配套
sourcemap
的.map
文件。健壮性🏋
指定运行环境:engine与os
{ "engine": "node>=14", "os": ["linux", "darwin"] }
有否配套测试用例
- 有可运行的配套测试用例。
- 在
README.md
上有可见的测试覆盖率统计,让人可以放心使用。
测试用例放在哪?
最初我习惯按照jest
推荐的模式,将所有测试用例放在__tests__
文件夹内。
比如以下这种目录结构
src/setter.ts
src/setter.test.ts
测试运行时机
npm prepublishOnly
的钩子一定要加上运行测试用例。github上有好多免费的配套流水线,自己折腾折腾。
代码校验配套
eslint,然后配上
airbnb
与prettier
的校验规则。如果有面试者给我看自己的开源作品,如果代码风格都不行,立即就判定不行,也不用再看什么逻辑能力了,招进来也是挖坑。
推广性🤹
文档
使用
.markdownlint
配置规范自己的markdown
文档,否则很容易写飞了。配套展示用例
- 一个方法是在项目中自带一个可运行的样例,让人
- 更好一些,部署一个可以在线查看的例子,并在主文档上附上直达链接。
- 更进一步,项目增大之后,需要说明的地方越来越多,一个
README
已经太长。使用docusaurus
等类似的工具部署一个独立的文档站点。
clone
之后运行指定命令即可查看样例。
有否自动化版本管理
Why?因为版本号与兼容性是强相关的,具体参考semver
规范。
- 使用
- 使用
standard-version
等自动生成CHANGELOG
并根据规则自动提升版本号。
husky
/yorkie
等规范提交日志。
最后留个作业
- 你有什么
- 当我们再一次运行
npm publish
,脑编译一下,想想这期间都发生了些什么,还少些什么?
npm
发布时的关键经验这里没提到的,帮我补充下🤝
内容来源:京东云开发者社区