分为开发环境、生产环境的性能优化:

一、开发环境:

1.优化打包构建速度,这样运行webpack就更快,就能更快看见构建效果。调试开发更加友好
2.优化代码调试功能

1.HMR:只会针对非入口文件进行使用

一旦修改了入口 文件,那么所有的都会变,所以这个不对入口文件使用
hot module replacement热模块替换/模块热替换
作用:一个模块发生变化,只会重新打包这一个模块,而不是打包所有,这样可以极大的提升代码构建速度
在devServer里配置: hot:true
并且样式文件:可以使用HMR功能,因为style-loader内部实现了
IMG_1073.JPG
js文件:默认不可以使用HMR功能,所以需要修改js代码添加支持HMR功能的代码才可以使用
module会到全局找
IMG_1076.JPG
这么添加之后,当print.js变化之后,只有print.js重新更新了,其他不变

html:默认不能使用HMR功能(因为html文件只有一个,一旦发生变化,没有其他的需要因此发生变化,不像js有很多个模块),同时会导致问题:html文件不能热更新了,怎么解决?:entry:改成一个数组,将html文件放进去,就可以热更新了
IMG_1075.JPG

2.source-map

提供源代码到构建后代码的映射 技术,(因为构建后代码是很多个源代码的结合体,所以一旦构建后代码出错了,要找源头就很麻烦)(如果构建后代码出错了,通过映射关系可以追踪源代码错误,非常利于调试找错)
devtool:’source-map’ (inline-source-map/hidden-source-map/eval-source-map/nosources-source-map/cheap-source-map/moudle-source-map)
这些还可以俩俩组合
会生产一个sourcemap文件
IMG_1079.JPG
IMG_1082.JPG
上面是构建后的代码,下面是开发源代码,source-map可以提供详细准确的错误代码 提示信息和错误位置
IMG_1084.JPG
IMG_1085.JPG
IMG_1086.JPG

不同环境采用哪个更好:

开发环境:要求速度快,调试更友好

速度快(eval>inline>cheap……)
还可以俩俩组合eval-cheap-source-map
调试友好:cheap-module-source-map
IMG_1087.JPG
生产环境:源代码要不要隐藏?调试要不要更友好
IMG_1088.JPG

二、生产环境:

1.优化打包构建速度
2.优化代码运行性能

1.oneof优化生产环境打包速度

之前每个文件都会被所有loader过一遍,比较费时,这样就不会反复被多个loader处理
如果有需要必须执行的loader,那可以将这个loader提取到外面
enforce:pre 会优先执行
IMG_1092.JPG

2.优化缓存

1)babel+整体缓存资源(让第二次打包速度更快)

babel要对代码进行编译处理,编译成浏览器能识别的js,我们想如果只有一个js变,那就直接使用babel缓存(第一次编译将所有都缓存下来),不需要再重新构建多次
cacheDirectory:true
IMG_1093.JPG

2)文件资源缓存(让代码上线运行缓存更好使用)

在缓存之后的build文件夹写一个服务器代码:server.js
IMG_1106.JPG
IMG_1105.JPG

IMG_1097.JPG
IMG_1096.JPG
在强制缓存期间不会访问服务器,直接读取本地缓存,如果强缓存期间出现严重bug,需要紧急修复,但又处在强制缓存,所以没法修复。这时候就可以给资源名称做手脚,加上个版本号,如果资源名称变了就重新缓存,没变就走强缓存的,一般加上哈希值。
每次webpack构建时会生成一个唯一的hash值,小问题:因为css和js打包都共享一个hash值,所以一旦重新打包,这俩是一起变的,所有缓存失效,而我只改动一个文件就导致所有一起变,这样不太好。
IMG_1098.JPG
IMG_1100.JPG
所以引入chunkhash值,根据chunk生成的hash值,打包来自同一个chuank,hash值就一样。
但当我换成chunkhash之后,js和css的hash值还是一样的,因为css是在js中被引入的,所以同属于一个chunk。所以这种方法耶不好用
IMG_1101.JPG
所以第三种方法:contenthash:根据文件的内容生成hash值,不同文件hash值一定不一样,当文件内容不变hash值是恒不变的,
IMG_1103.JPG

三、tree-shaking去除无用代码

将应用程序想做是一棵树,在应用程序中引入的源代码/第三方库,都可以想象成树上的绿叶,而没有引用的代码就想象成灰色枯萎的树叶。
为了去掉灰色的树叶,就可以摇动树叶,让它掉落。为了去除应用程序中没有使用的代码。减少代码体积

前提条件:

1.必须使用es6模块化
2.必须开启production环境
满足前提条件webpack自动会进行treeshaking
不同版本的tree-shaking会有点差异,有些可能会将css文件当作没用代码干掉,怎么解决?需要中package.json补上:
sideEffect:[“*.css”]
IMG_1111.JPG

四、code split代码分割

将打包输出的一个chunk分割成多个文件,这样就可以并行加载/按需加载 ,从而速度更快

1.entry多入口

输出多个bundle文件,这样不太灵活,每次如果改了入口文件都需要自己再改
IMG_1117.JPG

2.optimization:splitChunk

可以将node_modules中代码单独打包成一个chunk最终输出
并且会自动分析多入口chunk中,有没有公共的文件,如果有会打包成单独一个chunk
IMG_1118.JPG

3.import动态导入语法:能将某个文件单独打包

通过js代码,让某个文件被单独打包成一个chunk
IMG_1120.JPG
这样test文件就被单独打包了。
IMG_1121.JPG
给打包出来的文件固定命名
IMG_1122.JPG

五、懒加载、预加载

懒加载:放到异步回调函数中触发了再加载

js文件的懒加载,不是图片的
懒加载可以理解为:延迟加载,当触发了某些条件的时候再加载,而不是一上来就加载
将import语法加入到异步回调函数中,(这里也会进行代码分割的,先分成单独的文件,再进行加载)并且这样做,第二次操作的时候会使用缓存,而不会重新再加载
IMG_1124.JPG

预加载:prefetch

会在使用之前,提前加载js文件
IMG_1125.JPG
看上面截图打包出来的结果,还是两个文件,但多了个关键字(prefect)
看下面截图,第二次点击的时候,其实用的是上面加载过的缓存
IMG_1126.JPG
预加载和懒加载正常加载有啥不一样呢?
正常加载可以认为是并行加载(同时加载多个文件,文件越多加载速度越慢,比如说因为http请求同一时间只能最多同时加载六个文件,换个域名又可以多再加载六个文件等)文件资源越多,后面的就得靠后加载,没有所谓的先后顺序,写在前面的就先加载,有可能这个先加载的暂时还没用,这样就浪费了大量时间。
而预加载是等其他资源加载完毕,浏览器空闲了,再偷偷加载资源。这样不会阻塞其他资源的加载。这个兼容性比较差,在移动端和IE有较大的兼容性问题,PC端就还好,所以慎用。
懒加载如果要加载的文件比较大,就会给用户体验不太好,延迟加载。

PWA

serviseWorker+cache 构成,作用:让我们的网页像app一样,离线也可以访问,性能也更好。
渐进式网络开发程序,有兼容性问题,淘宝就在使用,
访问掘金网站,看右边控制台,网络状态换成offline离线的时候
IMG_1129.JPG
淘宝:大部分可以访问,少部分无法使用
IMG_1130.JPG
PWA通过workbox库,借助插件:workbox-webpack-plugin
先npm插件,然后配置
IMG_1133.JPG
这个插件可以帮助我们生成一个serviceWorker的配置文件,用这个配置文件去注册,注册一般在入口js文件中做配置,这时候要处理一下serviceWorker的兼容性问题:
IMG_1141.JPG
编译之后会出现一个问题:eslint不认识navigator、window全局变量,怎么办?
在eslintConfig中添加配置,支持浏览器的全局变量
IMG_1136.JPG
然后重新编译后还有个问题,serviceWorker的代码必须运行在服务器上,所以需要npm i serve -g这个会帮我们快速创建一个静态资源服务器
serve -s build 这个命令启动服务器,然后帮助我们把build里的资源作为(部署为)静态资源暴露出去。
重新编译之后,可以在控制台Application里找到注册的Service Workers资源:IMG_1142.JPG
同时在下面的cache API找到缓存的数据
IMG_1143.JPG
切换离线状态,发现这些资源是从ServiceWork缓存的
IMG_1144.JPG