前端代码打包优化
前端资源打包在每个项⽬中都会有涉及,每位开发者都希望打包是⽤最少的时间构建出最⼩的代码,这不仅能提⾼团队中的效率,也能提⾼页⾯的访问性能,以下会从如何优化构建速度和优化构建输出代码来说明⼀些⽅法。 图⽚来⾃webpack
1. 速度优化
二维液相谱
⽇常开发打包配置⼤家都是习惯⽤脚⼿架等的默认配置,没问题,没⽑病,跑的好好的,就没这么在意。对于⼀些强迫症的患者,还是会有点不爽的,⽐如速度,⽐如最终打包出来的资源⼤⼩等等。
1.1 本地构建或者服务端构建
1.1.1 本地构建
开发完后本地构建,然后通过push到cnd同步资源。可能是传统⼤家喜欢做的思路,没⽑病,也挺好⽤的。
不⾜点:加重了仓库的体积,对于仓库中的语义化的npm包,本地构建不能实时享受到包的更新。
优点:适合于多⼈项⽬合作初期,或者依赖的⼀个三⽅包也处于⼀个不断迭代的过程,每个⼈开发的过程中仅仅打包⾃⼰的页⾯,互相不⼲扰
1.1.2 服务端构建
服务端构建,⼤致就是当资源push的时候,会在⼀台构建机器上⾯跑类似ci的服务,同时也会有打包的服务
优缺点基本就是本地的相反,但是还是⽐较推荐这样的⽅案
1.2 如何来优化
1.2.1 配置差异化
粗暴点其实⼤家可能希望这个配置可以⾃动化⽣成,⽽且可以仅有⼀份来做,思路是没错,但是其实应该做⼀些区分
功能本地开发线上发布
babel-polyfill⼀般不需要看业务需求
分离样式需要
删除console.log需要
css Prefix需要
OccurrenceOrderPlugin需要
DedupePlugin需要
Babel present转码需要
其实⽐较合理的⽅式应该是⽤环境变量来区分进⾏不同环境下不同的配置,ps:设置环境变量为了在window兼容,可以使⽤cross-env 来设置
以上的对⽐没有进⾏测试,感兴趣的同学可以试试看,在⽼的基础上修改会有多少的优化。
总结起来就是本地开发只求速度快,能少处理⼀点是⼀点
1.2.2 常见⽅式
可以在社区中看到很多相关类似的⽂章来做webpack的优化,各种各样的提速,可能都知道,但是懒得做,但其实⼀旦完成后,带来的受益是巨⼤的。
t型槽螺母externals
这可能是最暴⼒最提速的⽅法之⼀,把其中的⼀些库从中忽略掉,如果extern react了,需要注意的是最好把相关的⼀些react-addons-transition-group也给extern掉,否则有可能会出现依然打⼊多份react的问题,因为react-addons-transition-group这样的包⾥⾯代码是类似如下⽅式,externals并不能排除
Dll
将⼀些可预见性的库从中抽离,预打包,可以极⼤的提速,当时还是有蛮多需要注意的,⽐如同样的包最好全局只有⼀份,预打包后不能享受到语义化版本的资源跟新,需要结合实际问题来看是否需要。 HappyPack
常⽤套路加速
const os = require('os');
HappyPack.ThreadPool({size: os.cpus().length })
⼀些配置
设置⼀些alias,同时可以适当设置⼀些loaders中的exclude等
设置css-loader版本号
提速特别明显
"css-loader": "^0.14.5",
替换scss-loader 为fast-sass-loader
相⽐起来⽐scss-loader速度更快
不⽤webpack⾃带的uglfiyJS
⽤⾃带的uglfiyJS来做压缩速度⽐较慢,这边有俩思路,但原理应该是⼀样的
2. 造个新轮⼦多核并⾏去压缩js和css
这个⽅案优化⼀般来说可以提速⼀半左右
js和scss的分离
这个可以优化本地开发过程中的rebuild速度,尽量让scss⽂件和js⽂件分离,如果使⽤了⼀些ui库,可以引⽤UI库的css⽂件,⽽不是scss⽂件,省去每次的scss build过程
1.3 其他
1. 对于打包webpack可能是⼀个功能⼤⽽全的⼯具,除此之外还有很多类似于rollup或者是browserify,要看具体场景来使⽤,杀鸡可能选个更合适的⼑会更好,不要盲⽬选
择都是⽤⼀把⼑。后续待尝试后详细再补相关的⼀些其他打包⽅案。
2. 优化永⽆⽌境
一下一下的顶开2. 代码优化
2.1 精简node_modules
现在开发基本都是使⽤npm或者yarns进⾏依赖管理,随便引⼊⼏个依赖就会使得最终打包的结构臃肿,再加上开发者可能对依赖的包并没有特别统⼀管理,需要什么就引⼊什么,不会去关⼼互相之间的关系。
上图仅仅是说明node_modules管理的时候出现的包的量⼀个图,可以说是⾮常的形象。,⽂章推荐
⼀看
注:npm包开发者应该保证包⾥⾯仅只有需要的代码,⽐如测试等等的资源最好都忽略掉,这样也可以省去不少开⽀,细节后续会整理⼀篇新的⽂章。
2.1.1 ⽅法1:同样功能使⽤同样的包
多⼈开发常会遇到使⽤三⽅库,部分⼈使⽤deep-extend,但是后⾯可能⼜有⼈⽤lodash,这样⼀来⼀回,会出现同样功能的包会引⽤多个的问题。对于这个情况不会导致bug,但是会造成node_modules增多且package.json依赖混乱,当然代码⼤⼩也会有相应的损失。
解决⽅式
查看仓库的package.json,⽐如
{
"deep-extend": "^0.4.1",
多点干油泵
"lodash.clonedeep": "^4.5.0",
}
如上俩个库都是想做深拷贝,可以选择只使⽤其⼀即可,推荐
2.1.2 ⽅法2:同⼀个包尽量不存在多个版本
⼤部分情况这样仅只会加重代码的体积等,但是在少数的场景下,⽐如使⽤了前端组件库;
举个例⼦,项⽬中依赖了俩组件A和B,A依赖了某UI库C的1.0.0的input,⽽B依赖了C中的2.0.0的input,最终页⾯上会同时存在俩版本的input,这⾥存在⼀个隐患(如果俩组件有Dom节点结构调整发⽣样式变化,这个时候⽆论是使⽤1.0.0或者是2.0.0的样式其实都不合适),所以这个问题也需要多关注的,特别是前端的UI库,最好习惯性的排查下较为好。必须最好做下
解决⽅式
打开chrome调试⼯具,查看node_modules,对于UI的库,仔细翻翻,不能有多版本的库,对于其他库则可以佛系排查;如果发现某个库A出现了多次,可以使⽤npm ls A来查看是在什么地⽅多次引⽤到了,然后再定位到具体细节的包查看
使⽤webpack的使⽤BundleAnalyzerPlugin或者是⽤⾃带的功能输出json,进⾏分析,排查为什么最后输出的资源这么⼤的原因
2.2 抽离公⽤资源
⽐较适合那些整站的开发,将各个页⾯公⽤的资源抽离出来,这样在页⾯的访问过程中浏览器可以很好的将这些通⽤资源缓存,类似使⽤dll存在本地⼯程中,还可以使得打包加速,下⾯以dll为例
做法
1. 配置好项⽬所要打的dll资源,⼀般选择的是⼀些三⽅的库,具体看项⽬的需求
2. 预先打好dll的资源放到项⽬的某个⾃定⽬录中(甚⾄可以直接打成⽣产环境的版本省去后续的压缩)
3. 本地构建或者服务端构建任务结束后,将打好的dll资源拷贝到build⽬录下⾯
注意点
1. 如果使⽤服务端构建请务必保持本地的npm版本和服务端构建上⾯的版本⼀致,不同的npm的版本可能会导致manifest.json的⾥⾯内容不⼀致,因为dll存的是路径
2. 最好解决下同⼀个库多版本的问题,否则dll中就会打进去多版本的库,因为dll存路径不同的版本的版本号是不⼀致的
2.3 其他
2.3.1 使⽤babel-preset-env
官⽅也是推荐使⽤它来代替babel-preset-2015,根据业务所需要适配的浏览器去选择合适的,否则使⽤多余的转码会是的代码转码后更⼤,同时对于browsers的设置,也可以跟postCss进⾏统⼀
放线菌培养基2.3.2 区分好⼤包⼩包的问题
⼀些组件库或者是lodash
import { isEmpty } from 'lodash';
import isEmpty from 'lodash/isEmpty';
微机消谐装置umg92
所产⽣的结果是不⼀样的。除⾮使⽤⼀个转码的⼯具来⽀持;vscode⽤户建议装⼀个
2.3.3 升级打包⼯具webpack
升级到webpack3,有tree shaking、Scope Hoisting都对代码有着不错的优化
2.3.4 优化样式
1. prefix这类的⼯作交给postCss来完成,同样是根据业务的需求去做相关的prefix的处理,不多不少
2. 精简样式,去除没必要的样式