记一次项目打包优化

由于项目功能越来复杂,打包发布的速度越来越慢,严重影响了开发速度,所以决定优化下打包发布速度

分析打包流程及耗时

打包流程

  • 代码 clone 到打包服务器上
  • 编译代码,项目采用 nextjs 进行服务端渲染,所以编译编译时分为两个部分,分别为构建服务端 js 和客户端 js,每次编译都要先安装项目依赖,再执行打包构建命令
  • 构建 docker 容器,项目运行在 docker 容器中,每次打包发布都是构建一个新的容器去替换对应环境的容器
  • 部署静态资源,把客户端对应的 js 推送到 CDN 上
  • 替换容器,用之前构建的容器去替换当前环境的容器

耗时分析

  • clone 代码速度由网络和项目大小决定(网络无法控制,源代码不大,优化效果不明显)—— 通常在 10 秒左右
  • 采用 webpack 进行编译,可以通过插件进行构建优化 —— 通常在 2.5 分钟左右
  • 构建 docker 容器时会把 node_modules 下的依赖按照生产模式的方式放入容器中 —— 通常在 4.5 分钟左右
  • 静态资源的上传由上传资源大小及网络决定,上传由基础组控制 —— 2 分钟左右
  • 替换容器由集群控制,业务方无法控制 —— 通常在 1 分左右

优化

通过上面的分析发现,制作 docker 容器和 打包过程最耗费时间,且这两块也在业务方控制之中,所以优化从这两方面着手

docker 容器优化

通过查看打包日志发现制作 docker 容器时发现制作容器时发送的上下文达 1G 多,对比其它项目明显偏大

优化方向分析

  • 发送的上下文是在生产模式下安装的依赖,即只会安装 dependencies 下的依赖 —— 考虑把所有非服务端必须的依赖安装到 devDependencies 中以减小上下文大小
  • 由于需要 SEO 优化,优化不能减少服务端渲染时的页面内容 —— 只能优化对页面内容没有影响但是需要客户端交互及样式操作相关的库

优化操作

  • 通过 webpack 插件提取项目中使用的依赖,结合 package.json 的配置,筛选出项目中无用的依赖
  • 筛选出 dependencies 中的依赖是否可以只在客户端渲染时引入,例如 react-copy-to-clipboard 只会在客户端执行复制操作就可以放入 devDependencies 中以便只在客户端引入

优化效果

构建 docker 容器的时间从优化前的 4.5 分钟左右下降到 2.5 分钟左右,优化了 50%

webpack 打包优化

此项目是基于 webpack 4.x 进行打包的,可以通过插件和 webpack 配置及 loader 的形式进行打包优化

webpack 4 使用 v8 引擎带来的优化

  • for of 替代 forEach
  • Map 和 Set 替代 Object
  • includes 替代 indexOf()
  • 默认使用更快的 md4 hash 算法 替代 md5 算法,md4 较 md5 速度更快
  • webpack AST 可以直接从 loader 传递给 AST,从而减少解析时间
  • 使用字符串方法替代正则表达式

优化方向分析

通过 speed-measure-webpack-plugin 插件进行打包耗时分析

  • 通过配置 exclude / include 和忽略第三方包指定目录及通过 externals 缩小打包文件范围
  • 多进程并行打包和代码压缩
  • 缓存编译结果
  • babel 配置的优化

优化操作

通过研究框架 webpack 配置发现项目已经引入 cache-loaderthread-loaderloader 和插件及配置优化代码打包速度,所以未做 webpack 打包优化

  • 引入 speed-measure-webpack-plugin 查看打包耗时

相关知识点