webpack打包慢的话,应该怎么做

单独打包runtime

在webpack.config加上三行代码

  1. optimization:{
  2. runtimeChunk:'single',
  3. }
  4. 字面意思:
  5. 优化:{
  6. 运行时文件:单独打包
  7. }

image.png
build一下看看有什么作用:
当前dist文件夹状态:
image.png
打包完后,多了一个runtime.js
image.png

为什么runtime要单独打包,有什么效果

runtime:如果我为了让一个东西运行而提供的代码,那这个代码就是runtime的代码

为了让main,js可以在ie里运行,webpack需要写额外的代码,那一部分的代码就是刚刚打包出来的runtime.js

不单独打包

当我们修改了配置,或者升级了配置之后,去yarn build打包,可能这个runtime就会变。
因为不单独打包,runtime就会包含在main.js里面,runtime变了,main.js自然也会变了,main.js的hash也会变了。之前可能是main.xxx.js,build完之后就变成了main.zzz.js。这样就会导致:用户可能会多下载多一个文件main.zzz.js,因为之前的main.xxx.js是缓存了的(用户只要之前浏览过这个js),现在文件名变了,用户就得再下载一遍,这个下载是完全没必要的,你只修改了配置,mian.js本身的内容是没有变得。当然这样的打包速度也没差多少

单独打包

当修改了webpack配置或者升级webpack,每次打包只会把index.js本身的内容打包成main.xxx.js,额外的代码就会打包成runtime.xxx.js。
这样的好处就是:只要index.js他本身的内容没变,用户对应的main.xxx.js的缓存就是有效的

简单来说:如果不单独打包,那修改webpack配置的时候,会导致用户的缓存失效,必须重新下载最新的main.js。如果单独打包,只要我不修改index,js的内容(以及他依赖的源代码),用户就不需要再次下载,节省用户的带宽,那么用户打开页面的速度就会降低,提高了整个页面的加载性能。

用splitChunks将node依赖单独打包

我们写react或vue项目的时候,react,vue的包都会打包进main.js里面,会出现几个问题:

  1. 打包速度会比较慢(本身代码只写了一点,但是为了加载react的文件,导致速度变慢)
  2. 编译时可以缓存之前的版本,所以没必要(其实vue和react.js只要打包一遍就没必要再打包了,除非升级过他们,缓存)
  3. 假设我要升级react和vue,其实跟上面的runtime是同一个问题,就算升级了,我本身的main.xxx.js是没有变化的。

文档https://webpack.js.org/plugins/split-chunks-plugin/

splitChunks:分开一个文件
代码:
image.png
在index.js里面引入React试一下
image.png
打包
image.png
就打包出了vendors.xxx.js的文件,react就在里面
这样就做到了,只要来自node_modules的文件都会单独打包到vendors里面

再来看看index,html
image.png
加载的顺序也是很有意思的。先是加载必须的额外代码runtime,然后是vendors,react的代码,然后加载main.js,最后加载css。
当然实际上是会先加载css,因为他的js标签上加了defer

固定moduleIds

做法很简单,加一行代码就可以了
image.png
deterministic:确定性的
就是为了防止打包出来的js id变了。跟runtime单独打包的想法是差不多的。
有必要,虽然用处不是特别大
文档也是有的https://webpack.docschina.org/configuration/optimization/
image.png

webpack多页面配置

通过htmlwebpackplugin来做就好了,每new一个HtmlWebpackPlugin,都会生成多一个页面,所以多页面,一般是用循环遍历你的项目文件来做的。
比如 我现在是固定的写法,一般肯定是要根据项目文件生成的
image.png
filename是生成的html的文件名,chunks是这个生成的html依赖了哪些js

新建一个src/admin.js用于测试:
image.png
但是目前还不可以打包出两个页面。因为webpack默认只会打包index.js,他不会打包admin.js
所以就需要添加多入口
image.png
这就是告诉webpack,我要打包两个文件,分别是index.js和admin.js。
然后通过htmlwebpackplugin告诉webpack我要打包两个html,分别是index.html和admin.html

打包
image.png
成功打包出了两个html
看一下index.html的内容
image.png
没问题的引入

看一下admin.html的内容
image.png
好像没有引入vendors。
admin.js没用到react,所以确实没有vendors。

这个多页是存在问题的。 肯定是需要根据项目文件去构造出webapck的配置的。

common chunks 共有文件打包成一个

多页面的话会有一些优化细节。
如果上面的admin和index同时引入了同一个文件,会出现问题。
新建一个share.js让admin.js和index.js同时引入使用
image.png
打包完看看
dist/admin.js
image.png
dist/main.js
image.png
这就有一个问题:如果share.js是一个超大的文件,1m以上,那么admin.js也至少有1m的体积,因为它把整个share.js都引入了。同理mian.js也是会1m以上的。
也就是说,同一个js文件,被放到了两个js文件里面,用户要下载两次这个js文件(用户也很难知道自己下载了两次share.js,因为它隐藏在了admin和mian里面)

所以现在就需要common chunks了
在之前的vendors下面加几行代码就可以了。
image.png

minSize:0 不管这个文件多小,我都要优化
minChunks:2 只要这个文件被至少两个其他文件引用了,就认为这个文件是共有文件,
chunks:all 跟vendors是一样的,不管同步还是异步文件都要优化
name:’common’ 就名字
priority:5 优先级 因为上面的vendors也是可以设置优先级的,你只要优先级比vendors低就可以了。

为什么优先级要比vendors要低呢?
因为有时候这个文件,确实符合common的条件,被两个文件引用,但他是node_modules里面的文件呢,所以我们需要保证vendors的优先级更高一点

打包看看
image.png
看看admin.html
image.png
引入了common.js 那么也可以认为admin.js里面没有写入了share.js了,都在common.js里面了

总结

webpack的优化技巧还有很多,但是也逃不出来我们现在的处理逻辑:code Split 代码分割

现在我们已经分割了几个级别了

  1. runtime
  2. node_modules => vendors // 全局
  3. common // 模块
  4. self(main/admin) 入口文件自身的依赖 // 自身

根据全局,模块,自身的层次去操作,这样项目的代码就可以被合理地分割