开发一个前端库需要什么

738 阅读6分钟

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

今天来结合阅读开源库源码的经验来聊聊开发一个前端 npm 库,可能需要哪些东西。

运行环境

首先你需要一台电脑,系统甭管是 windows 还是 linux 还是 mac,你需要保证电脑装了 nodejs 和 git (如果没记错的话,nodejs 安装第三方库依赖于 git),且都添加到了环境变量,即保证命令行输入以下命令不会提示找不到命令

node -v
git --version

包管理器

通过 nodejs 的包管理器,我们可以方便地安装、移除第三方库。

nodejs 默认自带的包管理器是 npm, 你也可以使用 npm 安装其他的包管理器如 yarn、pnpm。

npm i -g yarn
npm i -g pnpm

yarn官网:yarnpkg.com/getting-sta…

yarn 使用文档:yarn.bootcss.com/docs/cli/li…

pnpm官网:pnpm.io/motivation

本人用 yarn 多一点,感觉上用 yarn 安装依赖比 npm 速度快一点,输出内容也简洁一点,pnpm 没用过,其特点是可以充分利用磁盘空间,所有项目安装的依赖放在一个单一的文件夹,对一个项目本地安装依赖时会在当前的node_modules/.pnpm创建硬链接指向实际的安装位置,保证你磁盘中同一个依赖库不会有冗余的副本。 对于一个包的更新,只下载发生改变的部分文件,不会重新克隆整个仓库。

对于 yarn 和 npm 在某些功能上的语法区别梳理如下:

功能npmyarn
全局安装依赖npm i -g 包名yarn global add 包名
安装/移除依赖npm i 包名/npm uni 包名yarn add 包名/yarn remove 包名
运行scriptnpm run 脚本名yarn 脚本名

怎么发布一个npm库

详细发布步骤仓库npm的使用文档

npm login
  • 创建好 README.md
  • 执行发布
npm publish

模块打包器

rollup 官网:www.rollupjs.com/guide/plugi…

rollup 是一个流行的模块打包的开源库,可以将多个JavaScript文件按某种规范(esm或commonjs或umd等)打包成一个或多个文件,通过编写rollup.config.js和搭配 rollup 插件能实现灵活复杂的构建和热重载操作。它还支持 tree-shaking,在 import 具名导出的模块时会做静态分析,可以把实际没有使用的代码比如未被使用的函数在构建过程中移除掉,优化打包后的体积。

在项目构建中,你很容易需要用到一些插件如 @rollup/plugin-babel来扩展 rollup 的功能,这可以在npm仓库上搜索,通常rollup插件的包名以@rollup/plugin-rollup-plugin-为前缀。有时你会更希望自己编写一些插件,建议读一遍 rollup 官网上的 plugin-development

typescript 支持

官网文档:www.typescriptlang.org/docs/handbo…

编写现代前端库当然是建议使用 typescript 来编写,通过静态的类型检查来提高代码的质量。对于类型声明,我们通常关注两个问题:一是社区有没有人提供声明文件,而是怎么维护自己的声明文件。

对于第一个问题,我们可以在 npm仓库上搜索,通常约定以@types/前缀的包都是 ts 声明文件,确定了正确的包名之后,执行安装:yarn add -D @types/xxx。一般类型声明包都是属于开发依赖,它应该存在于package.json中的devDependencies

第二个问题,声明文件写法可以参考官网的declaration-files部分,对于项目内自己的ts类型声明,类型声明文件通常后缀是.d.ts, 为了方便管理一般将不同模块的类型声明写到多个文件中,然后在一个文件如index.d.ts统一 import,并在package.json中指定index.d.ts的相对路径即可。

可以说,如果你要发布一个@types库,需要做的仅是维护一个index.d.ts文件以及在 package.json完善相关信息,如包名、版本号、仓库地址,并指定types字段为声明文件的路径即index.d.ts

规范代码风格

eslint 可以校验你项目代码是否符合规范。规范是可以自己定制的,一般是在配置文件继承现有的规范,并根据实际需要添加新的规则。 prettier 是一个专注于代码格式化的库。

规范 git提交

  • husky
  • commitlint husky 帮助生成一些 git hooks, commitlint 可以校验 git 提交信息

测试

  • jest jest 是一个轻巧流行的测试框架,我们需要掌握如何测试一个断言是否为真、如何借助模拟函数测试某函数的调用次数以及如何测试异步代码。

jest 还提供了快照测试功能。对于expect(xxx).toMatchSnapshot(); 在第一次运行这个测试代码时会生成一个 xxx 的快照,下次进行测试就会拿新的 xxx 的值和快照的值做 diff,发生改变就测试不通过,并提示diff的内容。

调整控制台打印内容外观

  • chalk 正常情况下,我们在终端打印的字符都是统一默认的颜色,很难突出重点,我们可以通过 chalk控制目标字符的显示样式,以区分开打印的重要内容和次要内容。

编写命令行交互工具

  • enquirer
  • commander enquirer 主要做交互式 cli工具,可以实现这样的场景:在命令行询问配置偏好,不断地选择选项后生成整个配置文件。

commander 专注于编写命令行工具,提供了制作符合 posix 规范的 cli工具的便捷方法,支持指令和短指令、输入参数的解析。

工具函数库

  • lodash
  • ramda 为了提高开发效率,我们使用一些现成的工具函数。

lodash是一个增强JavaScript的工具函数库,包含了函数柯里化、流式操作、节流防抖、访问对象嵌套路径、打乱数组等功能,为了支持 tree-shaking,我们一般使用的是 lodash-es 而不是 lodash,后者不能进行命名导出。

ramda 是一个专注于函数式编程的工具库。

基准测试

  • benchmark benchmark用于比较几个不同方法执行的快慢和运行性能,一个简单的基准测试步骤如下:
  1. 创建 Suite
  2. 给 Suite 添加待比较的代码块函数和名字
  3. 监听cycle事件,获取信息
  4. 调用 run 方法跑测试
const Benchmark = require('benchmark')
const suite = new Benchmark.Suite()
let arr = [...'a'.repeat(10000)]
suite
  .add('for-in', function () {
    for (let i = 0; i < 10000; ++i) {}
  })
  .add('forEach', function () {
    arr.forEach(() => {})
  })
  .on('cycle', function (event) {
    console.log(String(event.target))
  })
  .run()

终端输出结果如下:

for-in x 286,908 ops/sec ±1.11% (88 runs sampled)
forEach x 18,340 ops/sec ±23.78% (89 runs sampled)