Skip to content
0

发布第一个 NPM 包

我们可以通过 npm installNPM 安装其他开发者发布的第三方包,实际上,我们也可以尝试自己发布我们的包,这非常简单!

数据单位转换库

假设我们想要发布一个数据单位转换库,将 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

为了能让用户同时通过 ESMCJS 使用我们的包:

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.jsdist/index.cjs,分别是 ESM/CJS 风格的代码

  • dist
    • index.js
    • index.cjs

修改 package.json

需要在 package.json 配置出口,即便 modulemain 已经定义了入口,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.0

TIP

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

Released under the MIT License.