Webpack实战(八):教你搞懂webpack若是实现代码分片(code splitting)

2020年春节已过,原本打算回郑州,却由于新型冠状病毒感染肺炎的疫情公司推迟了上班的时间,我也推迟了去郑州的时间,在家多陪娃几天。之前都是在书房学习写博客,今天比较特殊,抱着电脑,在楼顶晒着太阳,陪着家人,写着博客。javascript

前面的几篇文章主要告诉你们如何安装、配置webpack、webpack实现样式分离等,今天这篇文章主要跟你们分享若是webpack如何实现代码分片。css

如今工程项目中,实现高性能应用的其中重要的一点就是让用户每次只加载必要的资源,优先级别不过高的资源采用延迟加载等技术渐进地进行加载获取。html

Webpack 做为打包工具所特有的一项技术就是代码分片技术,经过这项技术咱们能够把代码按照特定的形式进行拆分,使用按需加载资源,没必要要所有加载下来。 代码分片能够有效下降首屏加载资源的大小,可是咱们同时又面临着其余问题,好比如何对项目模块进行分片,分片后的资源如何进行管理等等。今天咱们须要对这些问题进行分析解决。java

利用入口划分代码

在Webpack中,配置参数中每一个入口都将生成一个对应的资源文件,经过入口的配置咱们能够进行一些简单有效的代码拆分。node

对于项目中经常会引入一些第三方库和工具,这些通常不会改动的,能够把它们单独放在一个入口中,由该入口的资源不会常常更新,所以能够有效利用客户端缓存这些资源,让用户没必要在每次请求页面时候都从新加载。react

//webpack.config.js
entry: {
	index: './index.js',
	lib: ['lib-1', 'lib-2']
}

//index.html
<script src="dist/lib.js"></script>
<script src="dist/index.js"></script>
复制代码

这种拆分方法主要适合于那些将接口绑定在全局对象上的库,由于业务代码中的模块没法直接引用库中的模块,两者属于不一样的依赖树。webpack

对于多页面应用来讲,咱们能够利用入口划分的方式拆分代码。好比,为每个页面建立一个入口,并放入只涉及该页面的代码,同时再建立一个入口来包含全部公共模块,并使每一个页面都进行加载。可是这样仍会带来公共模块与业务模块处于不一样依赖树的问题。另外,不少时候不是全部的页面都须要这些公共模块。这就须要咱们利用webpack专用的插件来解决这种问题了。web

CommonsChunkPlugin

CommonsChunkPlugin是webpack4以前内部自带的插件,webpack4以后用的是SplitChunks。CommonsChunkPlugin主要是用来提取第三方库和公共模块,避免首屏加载的bundle文件或者按需加载的bundle文件体积过大,从而致使加载时间过长,是一把优化项目的利器。浏览器

优势:缓存

  • 开发过程当中减小了重复模块打包,能够提高开发速度;
  • 减少总体资源体积;
  • 合理分片后的代码能够更有效地利用客户端缓存。 首页经过一个简单的例子也说明,假设咱们当前项目中有a.js 和b.js 两个入口文件,而且都引入了react,下面是未使用CommonsChunkPlugin的配置
//webpack.config.js
module.exports = {
	entry: {
		a: './a.js',
		b: './b.js'
	},
	output: {
		filename: '[name].js'
	}
}

//a.js
import React from 'React'
... //省略

// b.js 
import React from 'React'
... //省略
复制代码

若是打包,从打包的资源体积能够看出,react被分别打包到a.js 和b.js中。

更改webpack.config.js,添加CommonsChunkPlugin配置

const webpack = require('webpack');
module.exports = {
	entry: {
		a: './a.js',
		b: './b.js'
	},
	output: {
		filename: '[name].js'
	},
	plugins: [
	new webpack.optimize.CommonsChunkPlugin({
	name: 'commons',
	filename: 'commons.js'
})
]
}

复制代码

在配置文件的头部引入Webpack,接着使用其内部CommonsChunkPlugin函数建立了一个插件实例,并传入配置对象,配置参数能够理解为

  • name:用于指定公共chunk的名字
  • filename: 提取后的资源文件名 打包后能够看到,产出的资源中多了一个commons.js,而a.js 和b.js文件的体积也减小了,这是因为把react及依赖的模块提到commons.js的缘由。 不过咱们须要注意的是,咱们须要在页面引入其余j s以前,先引入公用的commons.js文件。

在提取公共模块方面,CommonsChunkPlugin能够知足不少场景的需求,可是它也有一些欠缺的地方。 1)一个CommonsChunkPlugin只能提取一个vendor,假如咱们想提取多个vendor则须要配置多个插件,这会增长不少重复的配置代码。

2)前面咱们提到的manifest实际上会使浏览器多加载一个资源,这对于页面渲染速度是不友好的。

3)因为内部设计上的一些缺陷,CommonsChunkPlugin在提取公共模块的时候会破坏掉原有Chunk中模块的依赖关系,致使难以进行更多的优化。好比在异步Chunk的场景下CommonsChunkPlugin并不会按照咱们的预期正常工做。

optimization.SplitChunks

optimization.SplitChunks(简称SplitChunks)是Webpack 4为了改进CommonsChunk-Plugin而从新设计和实现的代码分片特性。它不只比CommonsChunkPlugin功能更增强大,还更简单易用。

配置文件web pack.config.js为:

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  context: path.join(__dirname, './src'),
  entry: {
    index: './index.js'
  },
  output: {
    // path: path.join(__dirname, 'dist'),
    filename: 'index.js',
    publicPath: '/dist/'
  },
  mode: 'development',
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', {
          loader: 'css-loader',
          options: {
            modules: {
              localIdentName: '[path][name]__[local]--[hash:base64:5]',
            }
          }
        }]
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            presets: [
              [
                'env', {
                  modules: false
                }
              ]
            ]
          }
        }
      }
    ],
  }
}
复制代码

须要引入的两个index.js文件和index2.js文件

// index
import index2 from  './index2.js';
import React from 'react'
document.write('index.js', React.version);

//index2
import React from 'react'
document.write('index2.js', React.version);


复制代码

使用optimization.splitChunks替代了CommonsChunkPlugin,并指定了chunks的值为all,这个配置项的含义是,SplitChunks将会对全部的chunks生效(默认状况下,SplitChunks只对异步chunks生效,而且不须要配置) 打包结果以下图:

在这里插入图片描述

本来咱们打包的结果应该是index.js,可是因为SplitChunks的存在,又生成了一个vendors~index.index.js,而且把react提取到了里面。 运行的效果以下图:

在这里插入图片描述
在使用CommonsChunkPlugin的时候,咱们大多数时候是经过配置项将特定入口中的特定模块提取出来,也就是更贴近命令式的方式。而SplitChunks的不一样之处在于咱们只须要设置一些提取条件,如提取的模式、提取模块的体积等,当某些模块达到这些条件后就会自动被提取出来。SplitChunks的使用更像是声明式的。

SplitChunks默认情形下的提取条件:

  • 提取后的chunk可被共享或者来自node_modules目录。这一条很容易理解,被屡次引用或处于node_modules中的模块更倾向因而通用模块,比较适合被提取出来。
  • 提取后的Javascript chunk体积大于30kB(压缩和gzip以前),CSS chunk体积大于50kB。这个也比较容易理解,若是提取后的资源体积过小,那么带来的优化效果也比较通常。
  • 在按需加载过程当中,并行请求的资源最大值小于等于5。按需加载指的是,经过动态插入script标签的方式加载脚本。咱们通常不但愿同时加载过多的资源,由于每个请求都要花费创建连接和释放连接的成本,所以提取的规则只在并行请求很少的时候生效。
  • 在首次加载时,并行请求的资源数最大值小于等于3。和上一条相似,只不过在页面首次加载时每每对性能的要求更高,所以这里的默认阈值也更低。

SplitChunks提取方式

SplitChunks 默认的提取方式是异步提取,当咱们在chunks上配置参数为all的时候,不是异步资源也能够提取。

SplitChunks 配置

optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 30000,
      minRemainingSize: 0,
      maxSize: 0,
      minChunks: 1,
      maxAsyncRequests: 6,
      maxInitialRequests: 4,
      automaticNameDelimiter: '~',
      name: true,
      automaticNameMaxLength: 30,
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  }
复制代码

(1)匹配模式经过chunks咱们能够配置SplitChunks的工做模式。它有3个可选值,分别为async(默认)、initial和all。async即只提取异步chunk,initial则只对入口chunk生效(若是配置了initial则上面异步的例子将失效),all则是两种模式同时开启。

(2)匹配条件minSize、minChunks、maxAsyncRequests、maxInitialRequests都属于匹配条件,

(3)命名配置项name默认为true,它意味着SplitChunks能够根据cacheGroups和做用范围自动为新生成的chunk命名,并以automaticNameDelimiter分隔。如vendors~a~b~c.js意思是cacheGroups为vendors,而且该chunk是由a、b、c三个入口chunk所产生的。

(4)cacheGroups能够理解成分离chunks时的规则。默认状况下有两种规则——defaultVendors和default。defaultVendors用于提取全部node_modules中符合条件的模块,default则做用于被屡次引用的模块。咱们能够对这些规则进行增长或者修改,若是想要禁用某种规则,也能够直接将其置为false。当一个模块同时符合多个cacheGroups时,则根据其中的priority配置项肯定优先级。

总结

有关webpack实现代码分片的几种方法:合理地规划入口,使用Commons-ChunkPlugin或SplitChunks就暂时分享到这里,这仅表明我的的观点,如想了解更多请扫描二维码

在这里插入图片描述
最后友情提醒你们要戴口罩,勤洗手,尽可能减小外出,作好预防 措施,远离新型冠状病毒。
相关文章
相关标签/搜索