博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
webpack SplitChunksPlugin实用指南
阅读量:6413 次
发布时间:2019-06-23

本文共 5172 字,大约阅读时间需要 17 分钟。

提到前端打包工具,毫无疑问想先到的是webpack。但是前端发展地很快,时不时会有新东西出现,打包工具这边之前也出现parcel和rollup。各种工具的碰撞,相互汲取优点,促进技术的发展。

webpack4中支持了零配置的特性,同时对块打包也做了优化,CommonsChunkPlugin已经被移除了,现在是使用optimization.splitChunks代替。

下面就开始介绍splitChunks的内容。

默认情况

首先webpack会根据下述条件自动进行代码块分割:

  • 新代码块可以被共享引用,或者这些模块都是来自node_modules文件夹里面
  • 新代码块大于30kb(min+gziped之前的体积)
  • 按需加载的代码块,并行请求最大数量应该小于或者等于5
  • 初始加载的代码块,并行请求最大数量应该小于或等于3

块打包默认情况下只会影响按需加载模块,因为对初始块也进行优化打包会影响HTML中的script标签数,增加请求数。

接下来看些例子来理解默认情况的打包。

模块全部是同步引入

// indexA.jsimport React from 'react'import ReactDOM from 'react-dom'import _ from 'lodash'console.log(_.join(['a', 'b'], '~'))ReactDOM.render(  
SplitChunk
, document.getElementById('root'))复制代码

默认情况只会影响按需加载模块,所以所有内容全部被打包到一起了。

有模块动态导入

这里首先使用符合 的 import() 语法

// indexA.jsimport React from 'react'import ReactDOM from 'react-dom'import _ from 'lodash'import(/* webpackChunkName: "async-jquery" */ 'jquery').then(component => {  console.log(component)})console.log(_.join(['a', 'b'], '~'))ReactDOM.render(  
SplitChunk
, document.getElementById('root'))复制代码

这里jquery使用动态导入,打包结果中可以看到jquery被单独打包了

react按需加载

同样的我们试要react按需加载,使用react-router提供的

AsyncModule模块按上面方案异步加载Dashboard

import React from 'react'import ReactDOM from 'react-dom'import {BrowserRouter, Route} from 'react-router-dom'import AsyncModule from './AsyncModule.jsx'import _ from 'lodash'import $ from 'jquery'console.log(_.join(['a', 'b'], '~'))ReactDOM.render(  
, document.getElementById('root'))复制代码

从打包结果可以看到按需加载的模块被打包到0.js去了。

讲完了webpack默认情况下对打包块的优化,接下来看splitChunks配置项。

配置项

相关配置项:

module.exports = {  //...  optimization: {    splitChunks: {      chunks: 'async',       minSize: 30000,      minChunks: 1,      maxAsyncRequests: 5,      maxInitialRequests: 3,      automaticNameDelimiter: '~',       name: true,      cacheGroups: {}    }  }}复制代码
  • chunks: 表示哪些代码需要优化,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为async
  • minSize: 表示在压缩前的最小模块大小,默认为30000
  • minChunks: 表示被引用次数,默认为1
  • maxAsyncRequests: 按需加载时候最大的并行请求数,默认为5
  • maxInitialRequests: 一个入口最大的并行请求数,默认为3
  • automaticNameDelimiter: 命名连接符
  • name: 拆分出来块的名字,默认由块名和hash值自动生成
  • cacheGroups: 缓存组。缓存组的属性除上面所有属性外,还有test, priority, reuseExistingChunk
    • test: 用于控制哪些模块被这个缓存组匹配到
    • priority: 缓存组打包的先后优先级
    • reuseExistingChunk: 如果当前代码块包含的模块已经有了,就不在产生一个新的代码块

配置项基本就上面这些,我们重点来看下chunks和cacheGroups。

chunks

chunks的取值是有initial, async, all。默认情况下是async,在本文第一部分已经介绍了它的表现,所以现在来看下其它两个的表现。

initial, all模式会将所有来自node_modules的模块分配到一个叫vendors的缓存组;所有重复引用至少两次的代码,会被分配到default的缓存组。

// indexA.jsimport './Dashboard.jsx'// indexB.jsimport './Dashboard.jsx'// Dashboard.jsximport React from 'react'复制代码
// webpack.config.jssplitChunks: {  chunks: 'initial'}复制代码

打包表现正如上面所述,产生了两个代码块vendors, default。

可以通过配置optimization.splitChunks.cacheGroups.default: false禁用default缓存组。

// webpack.config.jssplitChunks: {  chunks: 'initial',  cacheGroups: {    default: false  }}复制代码

至于all和initial的差别,可以看下这篇文章(要科学上网)

里面有提到initial模式下会分开优化打包异步和非异步模块。而all会把异步和非异步同时进行优化打包。也就是说moduleA在indexA中异步引入,indexB中同步引入,initial下moduleA会出现在两个打包块中,而all只会出现一个。

cacheGroups

使用cacheGroups可以自定义配置打包块。

// indexA.jsimport React from 'react'import ReactDOM from 'react-dom'import _ from 'lodash'import $ from 'jquery'// indexB.jsimport React from 'react'import ReactDOM from 'react-dom'import('lodash')import $ from 'jquery'// webpack.config.jsoptimization: {    splitChunks: {      cacheGroups: {        commons: {          name: 'commons',          chunks: 'initial',          minChunks: 2        }      }    }  }复制代码

根据开头介绍webapck分割条件,一些公共模块被打包进了commons,自定义打包块的优先级是0,所以现在公共模块会被打包进commons,而不是上述提到的默认打包块vendors(优先级为负)。

但是这边为什么lodash为什么没打包在一起呢?可以回顾下initial和all的区别。接下来实验下all的效果。

// indexA, indexB同上// webpack.config.jsoptimization: {    splitChunks: {        cacheGroups: {            commons: {                name: 'commons',                chunks: 'all',                minChunks: 2            }        }    }}复制代码

结果在预期中,lodash被打包在一起了。

提取第三方库

最后看下之前CommonsChunkPlugin常用的分离部分第三方库功能。这边你可以想一下怎么操作。

上面已经提到了设置chunks: initial || all都可以提取出第三方库。但是它是把所有第三库提取出来,所以我们在只提取react和react-dom的情况下,需要自定义一个cacheGroup。

// indexA.jsimport React from 'react'import ReactDOM from 'react-dom'import _ from 'lodash'import $ from 'jquery'// webpack.config.jsentry: {    indexA: path.join(__dirname, 'src/indexA.js')},optimization: {    splitChunks: {        chunks: 'all',        cacheGroups: {            vendors: {                test: /react/,                name: 'vendors'            }        }    }}复制代码

我们去重写了vendors打包块,只打包匹配react的模块,所以达到了之前CommonsChunkPlugin的功能。

或者

// index.jsximport React from 'react'import ReactDOM from 'react-dom'// webpack.config.jsentry: {    indexA: path.join(__dirname, 'src/indexA.js'),    vendor: ["react", "react-dom"]},optimization: {    splitChunks: {        cacheGroups: {            vendor: {                name: "vendor",                chunks: "initial"            }        }    }}复制代码

webpack 打包入口增加一个vendor入口,里面包括所有需要另外打包出来的库,然后在cacheGroups设置这个打包块chunks: initial || all,也能把indexA和vendor中重复的库提取到vendor打包块中。

optimization.runtimeChunk

最后提一下runtimeChunk,通过optimization.runtimeChunk: true选项,webpack会添加一个只包含运行时(runtime)额外代码块到每一个入口。(译注:这个需要看场景使用,会导致每个入口都加载多一份运行时代码)

总结

webpack4的splitChunks功能是比较强大的,不过推荐还是使用默认模式,或者提取一下第三方库。

参考材料

转载地址:http://ngdra.baihongyu.com/

你可能感兴趣的文章
如何侦查SQL执行状态
查看>>
CentOS 7 命令行如何连接无线网络
查看>>
Ubuntu 12.04上享用新版本Linux的功能
查看>>
logstash + grok 正则语法
查看>>
Zimbra开源版(v8.6)安装说明
查看>>
Android性能优化之TraceView和Lint使用详解
查看>>
linux centos7.2 安装mysq,nginx,php
查看>>
myrocks之事务处理
查看>>
基于pgrouting的路径规划之一
查看>>
LBS核心技术解析
查看>>
Fible Channel over Convergence Enhanced Ethernet talk about
查看>>
讨论:今日头条适配方案使用中出现的问题
查看>>
CSS3 3D翻转动画
查看>>
送给即将踏入软考征途的你
查看>>
要命啦!Word中快速录入大全,内含快捷键小技巧,快来一起学习!
查看>>
javascript实现音频mp3播放
查看>>
html5-离线缓存
查看>>
linux系统安装完后的常见工作
查看>>
在Linux服务器、客户端中构建密钥对验证进行远程连接
查看>>
揪出MySQL磁盘消耗迅猛的真凶
查看>>