webpack实现代码分割

1,652 阅读5分钟

  在webpack3中可以通过CommonsChunkPlugin来进行代码分割,但是webpack4中,官方提倡使用SplitChunksPlugin这个插件,所以本次主要讲解的也是在webpack4中通过SplitChunksPlugin这个插件来实现代码分割的方法。

  首先要先弄懂一个预备知识点,就是在webpack中,什么叫做chunk,什么叫做bundle?下面这种图可以帮助我们更好地理解:

  在webpack的打包配置entry中有两个入口:index和utils。分别对应index.js文件和utils.js文件,其中index.js文件引用了common.js和index.css。那么webpack打包的时候就会把前三个文件作为一个chunk,utils.js文件作为一个chunk。但是在webpack配置中,用MiniCssExtractPlugin插件抽离出了css文件,所以产生了.css和.js两个bundle文件。总之,chunk是webpack打包时候的一个概念,一个打包的入口代表一个chunk。而产生出来的可以在浏览器中运行的单个文件就叫做bundle。

  其实上文中通过在webpack配置文件中配置两个entry入口,其中utils把一些工具函数挂载到全局,也可以算是一种代码切割,但是有没有更加灵活的方式呢?我们来看下SplitChunksPlugin插件。SplitChunksPlugin插件的介绍可以在webpack的官方文档中找到:

从文档中可以看到SplitChunksPlugin的默认配置如下:

下面会一点点来讲解。

  代码分割有两种场景:一种是同步引入代码模块的分割,还有一种是异步引入的代码模块的分割。

一、同步代码分割:

  在业务代码中引入lodash,通过之前讲的webpack-bundle-analyzer插件分析打包情况如下:

可以看出我们的src文件和node_modules文件都是在一个bundle中。如果我们想把node_module中的库文件单独打包到一个chunk中,我们可以把官网上的SplitChunksPlugin的默认配置拷贝到打包配置文件中,然后做如下修改:

其中chunks表示可以配置成initial、async、all分别表示静态引入、动态引入和两种情况下来进行代码分割。

  minSize为可以进行代码分割的最小包体积,默认为30000Byte。而在打包分析中我们看到lodash的包体积在webpack处理完后是将近70KB,大于SplitChunksPlugin的最小打包体积。所以在做如上修改以后,便能够将lodash打包到单独的chunk中。打包后的情况如下:

从图中我们可以看到,lodash被单独打包到了叫做vendors~index.js的chunk中。

  下面再来完善一下上面分析的打包流程,满足了minSize的条件以后,顺着条件往下走可以走到cacheGroups配置,cacheGroups中有不同的对象,对象中的test即为测试正则,当引用的模块名满足了这个测试正则后,才会按照当前对象的规则打包。

  vendors这个键名即是打完包的前缀名,而automaticNameDelimiter中配置的就是前缀后面的连接符,vendors~index.js后面就是引入此模块的entry中配置的入口文件名index。

  如果我们想要,自定义lodash打包的文件名,我们可以在vendors中配置filename为vendors.js如下:

那么打完包的lodash的chunk就叫做vendors.js了,而cacheGroups上方的name:true的意思就是使cacheGroups中的filename生效。

接下来介绍在splitChunks中剩余的配置:

  minChunks是什么意思呢?他的意思就是在entry中配置的入口,引用了该模块的最少个数,只有满足了最少有minChunks个chunk引用了当前模块,才会进行单独打包。

  maxAsyncRequests表示代码分割完后,同时可以请求的最大数量。

  maxInitialRequests表示首页中的最大请求数,如果代码分割后,首页请求的请求数大于这个数,就不会再继续代码分割了。

二、异步代码分割:

  大家可能还不是很熟悉异步加载的语法,可以在官网的API部分中找到import异步加载的语法说明,其实就是ES6的一种语法:

  而在webpack的使用中,webpack通过一种叫做“魔法注释”的功能丰富了打包功能,下面会详细看到。

  在webpack中SplitChunksPlugin默认就会对异步引入的代码进行分割,但是为了支持异步引入模块的语法,我们还是需要安装babel的plugin-syntax-dynamic-import插件来支持异步加载的语法。

下面来详细看下我们的业务代码:

  在index.js中,我们通过click事件动态引入了handleClick.js文件,其中注释的部分就是通过魔法注释来给分割的chunk命名为handleClick。

在handleClick.js文件中,我们为文档添加元素(其中process.env.NODE_ENV是运行时环境变量,可以参考之前几期的推送)。

从下面的运行效果我们可以看到,当网页刷新的时候,先加载出来index.html文件和index.js文件。当点击网页的时候,才会去请求handleClick.js文件,并且网页上出现“123”。

其实异步代码分割还有一个大家可能更熟悉的名字——懒加载。

  但是,如果被异步加载的模块很大,我们在真实项目中操作完了再临时请求,会不会还是加载很慢。为了解决这个问题,可以使用魔法注释中的webpackPrefetch来让浏览器加载完首页的js文件后空闲的时候去加载异步分割的bundle文件。

参考: segmentfault.com/q/101000000… juejin.cn/post/684490… coding.imooc.com/lesson/316.…

如果您对本文感兴趣想关注更多技术文章,请关注作者公众号,更多好文章为您呈现~