实战干货-老项目升级/优化全过程

date:2020/04/21 20:20:51
updated:2020/04/21 20:20:51
categories:
•Webpack
•工程化

背景:迫于公司项目技术债严重,做了一些更新升级与修复.

本文取自当时的内部分享 PPT.

今天乘着有空,把部分内容整理出来,放在博客里,希望能帮到你.

文章内容信息已脱敏.
**

0.背景(发布时间 45-60min)

之前手头接手了一个项目,技术债极其严重.

Build 编译时间在本地需要接近 45 分钟,Publish 到公司 npm 的时间在 5 分钟左右.

经测算,平均发布时间在 40-65 分钟之间,已经严重影响到了开发与 bug 修复效率.

因为这个项目发布过慢,前端组被点名批评,领导重点关照希望解决掉这个问题,

同事们之前尝试解决,但因为过多的遗留问题,并没有成功.

打包后的项目总 package 大小 122.64mb(压缩前) 48.62mb(压缩后).

无 Cache 下加载时间 15209ms.
image.png

1.存在的问题.

  1. node 版本过老,多数插件存在问题,经常出现莫名错误.
  2. 发布流程老旧复杂,大多数环节重度依赖手工.
  3. 包过大导致的发布上传需要很长时间,有一定几率失败.
  4. 内存会在使用时间较长的时候出现爆栈.
  5. UglifyJS 报错,部分配置出现原因不明的失效,导致抛出大量错误使项目编译极慢.
  6. 必须在特定 npm 与 node 环境下才可以启动项目.

等等.

2.优化了有什么好处?

往小了说:

  • 极大提升开发部署体验,极大提高前后台联调效率,减少大量上手成本,抹平代码腐化导致的问题.

往大了说:

  • 减少线上 bug 快速响应时间,提高迭代效率,增加团队规范与约束.

3.优化 1:规范化 commit

问题 1:版本号不规范,commit 不规范,手动修改版本号,导致极易出现线上 bug.
问题 2:分支极多导致 changelog 难以阅读,存在大量”fix”,”update”等 commt 导致回滚变得困难

解决:引入 git-cz.
优势 1:交互式 commit,方便快捷直观.
优势 2:方便回滚与查找.
image.png

4.优化 2:使用标准的 npm version

问题 1:版本号不规范,版本-xxx-α 等版本号导致版本极度混乱,出现过很多次因为代码版本导致的线上 bug.
问题 2:手动同时修改几个文件与库的版本号,极易出现错误.

*解决:引入 npm version *
优势 1:方便回滚与查找.
优势 2:版本号可读性高,易于理解于发布.
优势 3:标准的 npm 版本号有着更加简单的 version 操作方式(手动修改=>自动修改)

例:
npm version [ | major | minor | patch ]
如版本号为 0.0.0.
npm version major 后为 1.0.0
npm version minor 后为 0.1.0
npm version patch 后为 0.0.1

图片由于包含部分公司项目信息,不方便展示,抱歉.
**

5.优化 3:发布优化

发布慢的一大部分原因不是项目问题,而是流程问题. 1.大量流程需要手动操作,完全没有文档,几乎无法接手. 2.发布流程不科学,很多琐碎的修复与命令需要统一.
3.xx(公司名)基础包的修改与 npm 源污染会带来连锁反应.

问题解决:

5-1:将原来需要手动修复的发布问题写成 fix 脚本,可以通过 npm run fix 或直接 start 就可以修复.

5-2:将 deploy 脚本抽象为区分环境的 deploy 命令,结合 gitlab 的 CI 做自动化.

5-3:使用脚本将大量重复的修改工作自动化.

6.webpack 优化

6-1UglifyJS

时间:45-60min->15-20min

UglifyJS 出了什么问题? 1.老版本 Webpack 中,官方的 UglifyJS 只支持单核编译.
2.UglifyJS 存在一定程度上的配置错误,虽然不影响最终输出,但是会影响效率.

image.png
解决方案: 1.升级 Webpack,使用新的版本的 UglifyJS,开启多线程.(高成本) 2.尝试使用其他插件.

6-1-1 尝试:Fast-Uglify-Plugin

Fast-Uglify-Plugin 是有赞开源的,基于多核的 UglifyJs 的插件.它能解决我的问题吗?
image.png

怎么打包速度提高了这么多?看起来是解决了?
并没有.

它带来的问题:

  1. 打包体积从 49mb->53mb,在默认配置下必须关闭 SourceMap,否则会因为包体积太大触发 npm 包发布体积上限,导致发布失败.
  2. Compress 配置项下的功能全部失效.
  3. 输出大量无效 console,且无法被 drop.

并且,由于这个插件是用来适配老项目的,已经有 2 年没有维护过的.看来,这条路走不通.
但是,这个方法给我们提供了一个思路,并且确切的减少了 Webpack 打包时间.

6-1-2 尝试 Parallel-Uglify-Plugin

Parallel-Uglify-Plugin 也是一个多线程打包工具.经过尝试后,我发现:

1.在舍弃了所有线上调试功能与 IE8 兼容后,我才能拿到一个比较小的包 Size.但是这个项目并不能舍弃这些. 2.如果带上这些功能,它打出来的包比 Fast-Uglify 更大.

鉴于它失败的表现,我放弃了这个解决方案.
但是,它依旧在减少打包时间并减小包大小上做出了一定的效果.

时间:15-20min->10min
Parsed:122.56mb->85.22mb
Bundle(gziped)48.62mb->29.31mb

6-2 尝试分析 Chunk(5-6min)

6-2-1 使用 BundleAnalyzerPlugin

image.png

可以看到,node_modules 被重复打包了很多次.
但是,还是很难找出具体哪些包被重复打包了,问题又出在哪里?

6-2-2 尝试自己写一个简单的插件去做依赖的 Parser

迫于找了一大圈,没有插件去做依赖分析,我自己实现了一个简单的模块依赖分析插件.

写的比较烂,就不献丑了.

最后定位到问题,解析出了被重复打包的包.

6-2-3 解决分包问题(重新修改分包配置)

image.png
image.png

重新分包后,打包时间从 7-10min 减少到 5-6min.
Parsed:85.22mb->10.45mb
Bundle(gziped):48.62mb->3.22mb

6-2-4 对部分分包参数进行调整,解除版本限制,升级新的 npm.(玄学,很多细节微调)

调整后,打包时间降低至 4min
Parsed:10.45mb->7.08mb
Bundle(gziped):3.22mb->2.75mb

7.结束了?不,并没有

到这里,问题已经解决了.但是,升级到 Webpack4 并在这基础上进行更进一步的优化,才真正解决的了这个问题,并保证项目不腐化.

由于篇幅关系,这里不细发升级 Webpack4 中出现的所有问题,需要参考可以参照附录.

在升级 Webpack4 并做了一些一些细节上的优化,如:

  1. DropConsole
  2. 移除报告
  3. 调整编译细节参数
  4. Webpack 静默运行
  5. 调大运行时内存
    等等.

之后,最后我们得到的结果是:
image.png
image.png

8.总结

对比未经优化之前的项目:
时间:30-45min->1.8-2.5min
Parsed:122.64mb->5.62mb.
Bundle(gziped)->1.39mb

看起来好像还不错,体验提高了吗?

image.png

系统首屏时间:
PC 端 15209ms=>4955ms 减少 68.5%
移动端 7473ms=>3282ms 减少 57%

性能无小事,追求无止境.感谢你看到这里.

9.附录:升级 Webpack4 出现的问题与解决办法

9-1 不需要插件后,webpack 打包配置出错

解决办法:修改配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
},

9-2 报错 Webpack has been initialise useing a configuration object that does not match the API schema

image.png
解决办法:
修改 Ruls 为符合 Webpack4 的规则.

9-3 报错 configuration.resolve.extensions[0] should not be empty

见 Issue:https://github.com/webpack/webpack/issues/3043

9-4 Tapable.plugin 报错.

image.png
见字面意思.更换插件配置即可.

9-5 compilation.mainTemplate.applyPluginsWaterfall is not a function.

image.png
升级 HTML-plugin 即可.

9-6 babel 转译出现问题.

image.png

解决:
https://stackoverflow.com/questions/50754773/typeerror-cannot-read-property-babel-of-undefined
升级:
https://babeljs.io/docs/en/env/#upgrading-to-babel-preset-env

9-7 alias 出现问题

image.png

解决:因为 webpack 的 alias 规则变更,所以需要重新配置 alias.

9-8file-lodaer 出现问题

image.png
解决:将 file-loader 直接升级即可.

9-9 运行项目出现直接爆栈的情况

image.png
解决:webpack4 中 code split 规则不同,请重新配置.

9-10Uglify 报错

image.png
更换 Uglify 为适合 webpack 的版本,并开启多核编译.

9-11 大文件警告

image.png

解决:移除自带热加载,添加 Dev Cache,升级 webpack-hot-middleware 至 2.25.0 以上版本.

9-12.properties undefined

image.png

解决:升级 webpack-cli 至 3.1.1 以上版本.

9-13 webpack/lib/removeAndDo 报错.

image.png
尝试移除 ExtartTextPlugin

可能是最简单易懂的ReactFiber打开方式

date:2020/06/21 19:53:24
updated:2020/06/21 19:53:24
categories:
•React
•Fiber/DOMdiff
•算法

说实话,在网上看过很多讲 fiber 相关的文章.有很多很棒的文章,也有不少糟糕的文章.

但是,我觉得它们都不太好懂.换句话来说,对新手不友好.看完以后还是很懵逼的,过两天就会忘个精光.

所以,我想尝试一下,把自己的理解写成一篇简单易懂的 ReactFiber 解析文章.如果对你有帮助,那就再好不过了.

本文拒绝公众号转载与洗稿,原创不易,谢谢.

(施工中)