使用 webpack 4 重构 yapi 构建脚本。

背景

我的一部分工作是基于 Yapi 做二次开发,Yapi 官方使用的构建工具是同属 YMFE 出品的 YkitYkit 是基于 `webpack@3.8.1的二次封装,随着我开发强度的增加,Ykit逐渐影响日常开发体验,尤其是hot-reload时间,而官方主要几乎停止维护,在看了Ykit源码之后,决定用webpack@4.x` 重写构建脚本。

tl;dr

webpack@4 构建脚本源码

升级 webpack@4.x

初始化配置

  1. 官方文档:webpack 官方文档有 V3 升级 V4 一些注意事项,其中就包括废弃的一些包
  2. 除了官方废弃的包,这次重构将 Babel 版本也升级到了 7.x,这个版本包都以命名空间的方式发布,所以需要重新安装
  3. webpack 基础配置,先配置 Dev 版
    1. 在进入 webpack 之前需要 initPlugin 生成一份插件列表 plugin-module.js,这部分代码沿用 ykit.config.js
    2. 配置 entry、output
    3. loader
      1. js loader
      2. css|sass|less|stylus loader,先上 style-loader 试试能不能跑通
      3. img|file loader
    4. plugin
      1. HtmlWebpackPlugin 生成入口页面
    5. 优化先跳过
    6. alias 配置沿用 ykit 的配置,common/client/exts
    7. dev server 配置
      1. 热更新
      2. 转发等

到这里升级就算结束了,webpack-dev-server --config ./config/webpack.dev.conf.js 没跑通,顺着报错挨个解决。

问题列表

Q1. babel-loader 无法识别 node_module 中的 React 代码

A: 通过配置 babel.config.js 或者 package.json 中的 babel 配置,不要使用 .babelrc ,参考

Q2: loader exclude 指定包

A: 这一点在 ykit.config.js 中有同样的配置,通过正则解决,示例如下

1
2
3
4
{
test: /\.js$/,
exclude: /node_modules\/(?!(MY-MODULE|ANOTHER-ONE)\/).*/,
},

Q3: tui-editor 的 icon 打包后,background 变成了 url([object Module])

A: 处理图片和字体的 loaderfile-loader 更改为 url-loader

Q4: antd 打包 less 报错 .bezierEasingMixin()

A: less 版本降级到 3 以下解决

上面的问题解决之后,dev-server 可以跑通,接下来开始验证打包后的页面是否正常。

优化列表

  1. 使用 mini-css-extract-plugin 抽离样式:这种方式存在一个问题,在 yapi-plugin-wiki 插件的文档中,样式的引入顺序是先引入 codemirror 再引入 tui-editortui-editor 的样式文件复写了 codemirror 的部分样式,但 mini-css-extract-plugin 打包后的引用顺序不是源码的引入顺序,为了临时解决这个问题,只在 lesssass 这两种文件上使用 mini-css-extract-plugin,再回看 ykit.config.js 的配置,也是通过这种方式绕过。
  2. 分包:将一些低频变更的依赖打包,通过 contenthash 命名,避免每次上线后,用户需要重新下载所有包
  3. 使用 fast refresh 替代 react-hot-loader 实现热替换,具体方案可以参考 react-refresh-webpack-plugin,配置流程相较于 react-hot-loader 更简洁,流程大体为
    1. 依赖安装:npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
    2. webpack 的 plugins 在开发环境增加 new ReactRefreshWebpackPlugin()
    3. babel 的 plugins 在开发环境增加 react-refresh/babel
  4. 优化
    1. antd 按需加载
    2. moment.js 替换语言包

分包前

分包后

代码优化

可以进一步对依赖包进行瘦身,不过需要在代码中操作,下面是一些方向

  1. highlight.js 指定语言,避免引入全部语言包
  2. 使用 day.js 替换 moment.js
  3. 升级 `antd@4.x扔掉沉重的icons/lib`

总结

升级之后,

场景 Ykit webpack@4.x 重构 提升
开发场景 无热更新,每次构建需要下载完整包
构建 10s +
热更新
实时预览
可以做到实时预览
生产构建 120+s 稳定在 60+s 构建时间降低 50%