发布第一个 NPM 包
我们可以通过 npm install 从 NPM 安装其他开发者发布的第三方包,实际上,我们也可以尝试自己发布我们的包,这非常简单!
数据单位转换库
假设我们想要发布一个数据单位转换库,将 byte 单位的数据转换为其他单位,新建 src/index.js,写好我们的函数
export default function transformDataSize(size, unit) {
switch(unit) {
case 'B':
return size + 'B';
case 'KB':
return (size / 1024).toFixed(2) + 'KB';
case 'MB':
return (size / Math.pow(1024, 2)).toFixed(2) + 'MB';
case 'GB':
return (size / Math.pow(1024, 3)).toFixed(2) + 'GB';
case 'TB':
return (size / Math.pow(1024, 4)).toFixed(2) + 'TB';
}
}我们希望用户的通过如下的方式使用:
// 用法示例:
let fileSize = 1024 * 1024 * 1024 * 1.5; // 1.5GB
let kb = transformDataSize(fileSize, 'KB');
// 返回 '1572864KB'
let mb = transformDataSize(fileSize, 'MB');
// 返回 '1536MB'
let gb = transformDataSize(fileSize, 'GB');
// 返回 '1.50GB'发布前的准备
同时支持 ESM/CJS
为了能让用户同时通过 ESM 和 CJS 使用我们的包:
import transformDataSize from 'transform-data-size'
// or
const transformDataSize = require('transform-data-size')所以我们需要提供两种对应风格的导出,这一步手虽然可以复制一份代码,但是容易出错且无必要,一般我们会通过打包工具来打包,输出 ESM/CJS 两种风格的代码,这里使用 tsup
首先全局安装工具:
npm i -g tsup # install然后执行打包:
tsup src/index.js --transform=esm,cjs会生成两个文件 dist/index.js 和 dist/index.cjs,分别是 ESM/CJS 风格的代码
dist
- index.js
- index.cjs
修改 package.json
需要在 package.json 配置出口,即便 module 和 main 已经定义了入口,exports 还是有必要的,目的是最大程度地兼容不同的导入方式和工具
{
"name": "transform-data-size", // NPM 包名,不能含有大写,必须
"version": "1.0.0", // 当前包版本,必须
"module": "./dist/index.js", // ESM 的出口
"main": "./dist/index.cjs", // CJS 的出口
"exports": {
".": {
"require": "./dist/index.cjs", // CJS 的出口
"import": "./dist/index.js" // ESM 的出口
}
}
}定义上传到 NPM 的文件
可以通过 .npmignore 决定不上传哪些文件,或者 package.json 中的 files 字段决定上传那些文件,由于我们现在文件比较少,可以通过定义 .npmignore,目前我们忽略 src,让源码不暴露在分发产物中
src/注册/登陆
确保在 npm 上已经注册了账号,然后执行下面的命令,然后输入在 NPM 上的用户名、密码和邮箱
npm login示例成功日志:
npm notice Log in on https://registry.npmjs.org/
Username: peterroe
Password:
Email: (this IS public) hi@peterroe.me
npm notice Please check your email for a one-time password (OTP)
Enter one-time password: xxxxx
Logged in as peterroe on https://registry.npmjs.org/.准备发布!
现在我们已经有了如下文件了
dist
- index.js
- index.cjs
src
- index.js
- .npmignore
- package.json
确保你的包名在 npm 上还未存在过,然后执行
npm publish --access=publish成功发布后将会看到如下日志,否则,检查是否包名已被用了或者和存在的包名相似,这两种请求都是不允许发布的。
npm notice
npm notice 📦 transform-size-data@1.0.0
npm notice === Tarball Contents ===
npm notice 222B app.ts
npm notice 1.3kB dist/index.js
npm notice 440B dist/index.mjs
npm notice 215B package.json
npm notice === Tarball Details ===
npm notice name: transform-size-data
npm notice version: 1.0.0
npm notice filename: transform-size-data-1.0.0.tgz
npm notice package size: 1.1 kB
npm notice unpacked size: 3.0 kB
npm notice shasum: e63a69ba5b5f23dee8cdf9ebb08591eed8e5e048
npm notice integrity: sha512-f3Ll8iUGhW/0K[...]0L6IqqcGFEaow==
npm notice total files: 6
npm notice
npm notice Publishing to https://registry.npmjs.org/
+ transform-size-data@1.0.0TIP
NPM 经过十余年的发展,已经有 200w+ 的包了,大部分简短的包名都已经被抢占,而且很多好的包名被占用却无实质内容,这算是去中心化的一个弊端
使用
其他人就能通过如下方式安装和使用你的包了
npm i transform-size-data在文件中使用:
import transformSizeData from 'transform-size-data'支持 TS
为了让用户在使用我们的库的时候,能够有类型提示,我们需要提供 d.ts 库,这一步也可以由打包工具生成,我们只需要将源码重构为 TS
type DataSizeUnit = 'B' | 'KB' | 'MB' | 'GB' | 'TB';
export default function transformDataSize(size, unit) {
export default function formatDataSize(size: number, unit: DataSizeUnit): string {
switch(unit) {
case 'B':
return size + 'B';
case 'KB':
return (size / 1024).toFixed(2) + 'KB';
case 'MB':
return (size / Math.pow(1024, 2)).toFixed(2) + 'MB';
case 'GB':
return (size / Math.pow(1024, 3)).toFixed(2) + 'GB';
case 'TB':
return (size / Math.pow(1024, 4)).toFixed(2) + 'TB';
}
}然后安装 typescript,由于上面我们使用 tsup 的时候是全局安装的,所以安装的 typescript 也要是全局的。如果是在项目内安装二者也要统一
npm i -g typescript然后执行打包,加上 --dts 参数
tsup src/index.ts --format=esm,cjs --dts我们将会得到额外的 dist/index.d.ts 文件:
type DataSizeUnit = 'B' | 'KB' | 'MB' | 'GB' | 'TB';
declare function formatDataSize(size: number, unit: DataSizeUnit): string;
export { formatDataSize as default };然后在 packge.json 中添加类型导出的字段 types,顺便让版本号自增
{
"name": "transform-size-data",
"version": "1.0.0",
"version": "1.0.1",
"type": "module",
"types": "./dist/index.d.ts",
"author": "peterroe",
"module": "./dist/index.mjs",
"main": "./dist/index.cjs",
"exports": {
".": {
"require": "./dist/index.cjs",
"import": "./dist/index.mjs"
"types": "./dist/index.d.ts"
}
}
}重新执行发布新版本即可
npm publish --access=publish