从 0 到 1 构建基于自身业务的前端工具库
作者:京东零售 吴迪
前言
在实际项目开发中无论 M 端、PC 端,或多或少都有一个 utils 文件目录去管理项目中用到的一些常用的工具方法,比如:时间处理、价格处理、解析 url 参数、加载脚本等,其中很多是重复、基础、或基于某种业务场景的工具,存在项目间冗余的痛点以及工具方法规范不统一的问题。
在实际开发过程中,经常使用一些开源工具库,如 lodash,以方便、快捷的进行项目开发。但是当 npm 上没有自己中意或符合自身业务的工具时,我们不得不自己动手,此时拥有自己的、基于业务的工具库就显得尤为重要。
我们所熟知的 Vue、React 等诸多知名前端框架,或公司提供的一些类库,它们是如何开发、构建、打包出来的,本文将带领你了解到如何从 0 到 1 构建基于自身业务的前端工具库。
构建工具库主流方案
1. WEBPACK
webpack 提供了构建和打包不同模块化规则的库,只是需要自己去搭建开发底层架构。
vue-cli,基于 webpack , vue-cli 脚手架工具可以快速初始化一个 vue 应用,它也可以初始化一个构建库。
2. ROLLUP
rollup 是一个专门针对 JavaScript 模块打包器,可以将应用或库的小块代码编译成更复杂的功能代码。
Vue、React 等许多流行前端框架的构建和打包都能看到 rollup 的身影。
为什么采用 ROLLUP 而不是 WEBPACK
webpack 主要职能是开发应用,而 rollup 主要针对的就是 js 库的开发,如果你要开发 js 库,那 webpack 的繁琐配置和打包后的文件体积就不太适用了,通过 webpack 打包构建出来的源代码增加了很多工具函数以外的模块依赖代码。
rollup 只是把业务代码转码成目标 js ,小巧且轻便。rollup 对于代码的 Tree-shaking 和 ES6 模块有着算法优势上的支持,如果只想构建一个简单的库,并且是基于 ES6 开发的,加上其简洁的 API,rollup 得到更多开发者的青睐。
工具库底层架构设计
构建工具库底层架构大概需要哪些功能的支持:
架构依赖需知
在对底层架构设计的基础上,首先需要把用到的依赖库简单熟悉一下:
rollup 全家桶
• rollup(工具库打包构建核心包)
• rollup-plugin-livereload(rollup 插件,热更新,方便本地 debugger 开发)
• rollup-plugin-serve(rollup 插件,本地服务代理,方便在本地 html 中调试工具)
• rollup-plugin-terser(rollup 插件,代码压缩混淆)
• rollup-plugin-visualizer(rollup 插件,可视化并分析 Rollup bundle,以查看模块占用)
• @rollup/plugin-babel(rollup 插件,rollup 的 babel 插件,ES6 转 ES5)
• @rollup/plugin-commonjs(rollup 插件,用来将 CommonJS 模块转换为 ES6,这样它们就可以包含在 Rollup 包中)
• @rollup/plugin-json(rollup 插件,它将.json 文件转换为 ES6 模块)
• @rollup/plugin-node-resolve(rollup 插件,它使用节点解析算法定位模块,用于在节点模块中使用第三方 node_modules 包)
• @rollup/plugin-typescript(rollup 插件,对 typescript 的支持,将 typescript 进行 tsc 转为 js)
typescript 相关
• typescript(使用 ts 开发工具库)
• tslib(TypeScript 的运行库,它包含了 TypeScript 所有的帮助函数)
• @typescript-eslint/eslint-plugin(TypeScript 的 eslint 插件,约束 ts 书写规范)
• @typescript-eslint/parser(ESLint 解析器,它利用 TypeScript ESTree 来允许 ESLint 检测 TypeScript 源代码)
文档相关
• typedoc(TypeScript 项目的文档生成器)
• gulp(使用 gulp 构建文档系统)
• gulp-typedoc(Gulp 插件来执行 TypeDoc 工具)
• browser-sync(文档系统热更新)
单元测试相关
• jest(一款优雅、简洁的 JavaScript 测试框架)
• @types/jest(Jest 的类型定义)
• ts-jest(一个支持源映射的 Jest 转换器,允许您使用 Jest 来测试用 TypeScript 编写的项目)
• @babel/preset-typescript(TypeScript 的 Babel 预设)
其他依赖
• eslint(代码规范约束)
• @babel/core(@rollup/plugin-babel 依赖的 babel 解析插件)
• @babel/plugin-transform-runtime(babel 转译依赖)
• @babel/preset-env(babel 转译依赖)
• chalk(控制台字符样式)
• rimraf(UNIX 命令 rm -rf 用于 node)
• cross-env(跨平台设置 node 环境变量)
底层架构搭建
1. 初始化项目
新建一个文件夹 utils-demo,执行 npm init,过程会询问构建项目的基本信息,按需填写即可:
2. 组织工具库业务开发 SRC 目录结构
创建工具库业务开发 src 文件目录,明确怎样规划工具库包,里面放置的是工具库开发需要的业务代码:
3. 安装项目依赖
要对 typescript 代码进行解析支持需要安装对 ts 支持的依赖,以及对开发的工具的一些依赖包:
这里遇到一个坑,关于最新 chalk5.0.0 不支持在 nodejs 中 require()导入,所以锁定包版本 chalk@^4.1.2
要对 typescript 进行解析和编译还需要配置 tsconfig.json,该文件中指定了用来编译这个项目的根文件和编译选项,在项目根目录,使用 tsc --init 命令快速生成 tsconfig.json 文件(前提全局安装 typescript)
初始化 tsconfig 完成之后,根目录自动生成 tsconfig.json 文件,需要对其进行简单的配置,以适用于 ts 项目,其中具体含义可以参考tsconfig.json官网
4. 组织项目打包构建 SCRIPTS 目录结构
根目录创建项目打包构建 scripts 脚本文件目录,里面放置的是有关于项目打包构建需要的文件:
生成 rollup 配置项函数核心代码:
rollup 在打包构建的过程中需要进行 babel 的转译,需要在根目录添加.babelrc 文件告知 babel:
此时距离打包构建工具库只差一步之遥,配置打包脚本命令,在 package.json 中配置命令:
执行 yarn build,根目录会构建出一个 lib 文件夹,里面有打包构建的文件,还多了一个 stats.html,这个是可视化并分析 Rollup bundle,用来查看工具模块占用空间:
架构搭建优化
项目搭建到这里,不知机智的你能否发现问题:
只要添加了一个工具,就要在入口文件导出需要打包构建的工具,在多人开发提交代码的时候将引来冲突的产生:
使用工具库的时候,按需引用的颗粒度太细了,不能满足一些要求颗粒度粗的朋友,比如:
• 我想使用该包里面 date 相关工具,要这样吗?
能不能这样?
• 在一些使用 script 脚本引入的场景下,就仅仅需要 date 相关的工具,要这样吗?
能不能这样?
这样仅仅使用 date 里面的工具,就没有必要将所有的工具都引入了
解决方案:
针对第一个代码冲突的问题,可以根据 src > modules 下目录结构自动生成入口文件 index.ts
自动构建入口文件核心代码:
针对颗粒度的问题,可以将 modules 下各种类型工具文件夹下面也自动生成入口文件,除了全部导出,再追加 import * as 模块类名称 类型的导出
至此,基本上解决了工具库打包的问题,但是架构中还缺少本地开发调试的环境,下面为大家介绍如何架构中添加本地开发调试的系统。
本地开发调试系统
首先要明确要加入本地开发调试系统的支持,需要做到以下:
• 跨平台(window 不支持 NODE_ENV=xxx)设置环境变量,根据环境配置不同的 rollup 配置项
• 引入本地开发需要的 html 静态服务器环境,并能做到热更新
跨平台设置环境变量很简单,使用 cross-env 指定 node 的环境
配置 package.json 命令
根据最开始架构设计的模块,在项目根目录新建 debugger 文件夹,里面存放的是工具调试的 html 静态页面
接下来就是配置 scripts > rollup.config.js ,将 NODE_ENV=development 环境加入 rollup 配置,修改生成 rollup 配置项函数核心代码:
执行 yarn dev 之后浏览器会新打开窗口,输入刚添加的工具链接,并且它是热更新的:
工具库文档系统
一个完备的工具库需要有一个文档来展示开发的工具函数,它可能需要具备以下几点支持:
• 支持工具库中方法的可视化预览
• 支持修改工具的时候,具备热更新机制
typedoc(TypeScript 项目的文档生成器)能完美支持 typescript 开发工具库的文档生成器的支持,它的核心原理就是读取源代码,根据工具的注释、ts 的类型规范等,自动生成文档页面
关于热更新机制的支持,第一个自然想到 browser-sync(文档系统热更新)
由于文档系统的预览功能有很多插件组合来实现的,可以借助 gulp (基于流的自动化构建工具),typedoc 正好有对应的 gulp-typedocGulp 插件来执行 TypeDoc 工具插件
构建完成后打开文档系统,并且它是热更新的,修改工具方法后自动更新文档:
单元测试
为确保用户使用的工具代码的安全性、正确性以及可靠性,工具库的单元测试必不可少。单元测试选用的是 Facebook 出品的 Jest 测试框架,它对于 TypeScript 有很好的支持。
1. 环境搭建
首先全局安装 jest 使用 init 来初始化 jest 配置项
执行完之后根目录会自动生成 jest.config.ts 文件,里面设置了单元测试的配置规则,package.json 里面也多了一个 script 指令 test。
关于 jest.config.js 文件配置项具体含义可以查看官网,要想完成 jest 对于 TypeScript 的测试,还需要安装一些依赖:
jest 还需要借助 .babelrc 去解析 TypeScript 文件,再进行测试,编辑 .babelrc 文件,添加依赖包 @babel/preset-typescript:
2. 单元测试文件的编写
通过以上环节,jest 单元测试环境基本搭建完毕,接下来在__tests__下编写测试用例
执行 yarn test
可以看到关于 debounce 防抖工具函数的测试情况显示在了控制台:
• stmts 是语句覆盖率(statement coverage):是不是每个语句都执行了?
• Branch 分支覆盖率(branch coverage):是不是每个 if 代码块都执行了?
• Funcs 函数覆盖率(function coverage):是不是每个函数都调用了?
• Lines 行覆盖率(line coverage):是不是每一行都执行了?
同时还会发现项目根目录多了一个 coverage 文件夹,里面就是 jest 生成的测试报告:
3. 单元测试文件的编写引发的思考
每次修改单元测试都要执行 yarn test 去查看测试结果,怎么解决?
jest 提供了 watch 指令,只需要配置 scripts 脚本就可以做到,单元测试的热更新。
以后会写很多工具的测试用例,每次 test 都将所有工具都进行了测试,能否只测试自己写的工具?
jest 也提供了测试单个文件的方法,这样 jest 只会对防抖函数进行测试(前提全局安装了 jest)。
工具库包的发布
至此工具库距离开发者使用仅一步之遥,就是发布到 npm 上,发包前需要在 package.json 中声明库的一些入口,关键词等信息。
登陆npm,你会看到自己的 packages 里面有了刚刚发布的工具库包:
写在最后
以上就是作者整理的从 0 到 1 构建基于自身业务的前端工具库的全过程,希望能给阅读本文的开发人员带来一些新的想法与尝试。
在此基础上已经成功在京东 npm 源发布了应用于京东汽车前端的工具库@jdcar/car-utils,并在各个业务线及系统得到落地。
当然,架构优化之路也还远未结束,比如:打包构建的速度、本地开发按需构建、工具库脚手架化等,后续我们也会基于自身业务以及一些新技术,持续深入优化,在性能上进一步提升,在功能上进一步丰富。本文或存在一些浅显不足之处,也欢迎大家评论指点。
参考资料
[1] rollup 英文文档(https://rollupjs.org/guide/en/#quick-start)
[2] rollup 中文文档(https://rollupjs.org/guide/zh/#introduction)
[3] Rollup.js 实战学习笔记(https://chenshenhai.github.io/rollupjs-note/)
[4] Rollup 打包工具的使用(https://juejin.cn/post/6844904058394771470)
[5] TypeScript、Rollup 搭建工具库(https://juejin.cn/post/6844904035309322254)
[6] 使用 rollup.js 封装各项目共用的工具包(https://juejin.cn/post/6993720790046736420)
[7] 如何开发一个基于 TypeScript 的工具库并自动生成文档(https://juejin.cn/post/6844903881030238221)
[8] 一款优雅、简洁的 JavaScript 测试框架(https://jestjs.io/zh-Hans/)
版权声明: 本文为 InfoQ 作者【京东科技开发者】的原创文章。
原文链接:【http://xie.infoq.cn/article/3dbc1c463ae6880f4cf6d494d】。文章转载请联系作者。
评论