如何发布一个自己的NPM包

TMaize 于 2020-06-03 发布

最近在写代码时几个从网上搜的一些工具方法拷过来拷过去非常麻烦,由于不行引入一些大而全的工具库增加体积,于是就想自己是否可以发布一个 npm 包供自己在多个项目间引用

项目地址

代码编写

初始化项目,根据提示填写信息,建议先在 github 上建好项目再执行,因为一些信息会自动替你补上

npm init

为了代码的通用性,当不使用 webpack 等工具发布 dist 包的话,那么在代码内引用库的话最好使用 Nodejs 支持的 CommonJS (require)规范来导入,从而避免别人使用你的库还需要再安装 Babel。在导出模块时可以做兼容同时支持 ES Module 和 CommonJS。

const utf8 = require('../utf8/index.js')
// ...
module.exports = {
  encode: btoa,
  decode: atob
}

兼容多种导出的写法

!(function (t, r) {
  'object' == typeof exports && 'object' == typeof module
    ? (module.exports = r())
    : 'function' == typeof define && define.amd
    ? define('kit', [], r)
    : 'object' == typeof exports
    ? (exports.kit = r())
    : (t.kit = r())
})(this, function () {
  return {
    // base64: base64
  }
})

代码编写到这里就完成了,发布上去可以被其他库引用了,而且还是按需加载的,用到那个就去引入那个。但是有时候,除了在 Node 项目中引用,还需要在浏览器中进入 js 文件,这时候就要用到 webpack 了

npm install webpack -D
npm install webpack-cli -D

可以新建一个index.js文件,然后引入所有的 js 挂到 window 上,再使用 webpack 打包这个文件,就生成了可以在浏览器中使用的版本了

const base64 = require('./lib/base64/index')
const utf8 = require('./lib/utf8/index')
const md5 = require('./lib/md5/index')

window.kit = {
  base64: base64,
  utf8: utf8,
  md5: md5
}

webpack 配置如下,然后在 package.json 中添加 build 脚本webpack --config ./webpack.conf.js然后执行npm run build就可以了,如果你希望代码可以在低版本设备上运行可以使用 bable 插件进行 polyfill

module.exports = {
  mode: 'production',
  entry: './index.js',
  output: {
    filename: './kit.min.js'
  }
}

cli

一些 cli 程序全局安装后是可以直接通过命令行去执行的,比如npm install -g hexo-cli。其实只要在package.json配置好下就好了

{
  "bin": {
    "hexo": "./bin/hexo"
  }
}

另外文件的第一行一定要写上解释器,不然的话会直接执行 js 文件就报错了。这也说明 npm 也是可以托管二进制可执行文件的

#!/usr/bin/env node

打包规范

上面的打包还是有问题的,全局变量是直接绑定在 window 上的,难免会有变量名的冲突,且不符合模块化的规范,其实 webpack 在打包的时候是可以设置输出为各种规范下的文件的

调整 index.js 文件,设置为标准导出

const base64 = require('./lib/base64/index')
const utf8 = require('./lib/utf8/index')
const md5 = require('./lib/md5/index')

module.exports = {
  base64: base64,
  utf8: utf8,
  md5: md5
}

调整 webpack 配置,这样打包后会把 kit 变量绑定到 this 上,通过<script>引用后就直接绑定到 window 上了。如果你使用了 requireJS 等引用,还可以重命名导出的变量名称

module.exports = {
  mode: 'production',
  entry: './index.js',
  output: {
    filename: './kit.min.js',
    library: 'kit',
    libraryTarget: 'umd',
    globalObject: 'this',
    umdNamedDefine: true
  }
}

测试

一个好的项目必须要有足够的测试,由于这是一个自己用的库,就用下 nodejs 自带的 assert,没有去使用第三方的测试库

调整 package.json 脚本,新增"test": "node test.js",然后执行npm test既可以了,如果测试不通过会终止测试并报错

test.js 文件

const kit = require('./index')
const assert = require('assert')

let rawStr = '你好 kit'
let base64Str = '5L2g5aW9IGtpdA=='

assert(base64Str === kit.base64.encode(rawStr), 'base64.encode')
assert(rawStr === kit.base64.decode(base64Str), 'base64.decode')

当测试文件过多时,可以以考虑把测试项目单独形成一个项目,这就涉及到如何在本地调试 npm 包了

一种方式是使用 npm link 命令将项目临时放到全局 node_modules 目录里面,还有一种方式是 npm 是支持安装本地包的 😁

npm install -S F:/npm-hello
npm install -S ../npm-hello
{
  "dependencies": {
    "@tmaize/hello": "file:F:/npm-hello",
    "@tmaize/hello": "file:../npm-hello"
  }
}

发布那些文件

默认情况下,除了 node_modules 和 .gitignore 中配置的不会发布,其余的都会发布上去,这显然不是我们想要的,因为有一些配置文件是要提交的仓库的,但是不需要发布的。可以通过设置黑白名单来解决这个问题

黑名单:.npmignore文件,规则同.gitignore

白名单:配置那些发布,优先级最高,推荐使用这个,因为他是写在 package.json 文件中的

{
  "files": ["dist", "lib", "LICENSE", "README.md", "package.json"]
}

发布

npmjs上注册一个账号,留意下自己的邮箱点下验证链接,不然后面的发布会报错

取一个名字,然后搜索下有没有被占用,然后没有被占用,就可以使用了(有种像抢注域名的感觉)

另外如果实在是不想改名字,可以发布 scoped 包,这种绝对不会被占用的,因为包名规则是@user/pkg,和你的用户名绑定的

注意:若登陆失败可以执行npm config get registry检查是否为官方源https://registry.npmjs.org/,如果不是可以到C:\Users\name\.npmrc下临时注释配置的 registry

npm adduser # 登陆
npm logout  # 退出
npm whoami  # 显示当前登陆用户
npm publish # 发布 ,提示版本存在需要手动更新package.json中的版本
npm deprecate pkgname@x.x.x # 标识某个版本过时
npm unpublish pkgname@x.x.x # 删除,删除的版本24小时后方可重发,只有发布72小时之内的包可以删除
npm view pkgname versions # 查看所有版本

当发布到 npm 仓库后,可以使用unpkg来访问里面的静态文件,还可以享受到 CDN 加速服务

关于版本的一些说明

01

参考

npm 发布包教程(二):发布包

[package.json npm Docs](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#workspaces)