抽取公共代码

如果要彻底明白 Webpack V4 版本如何抽取公共代码,就要设计一个场景来支持抽取公共代码的多种形式,能够从代码运行的结果中查看实际的效果,从效果中深入理解各个参数的作用。

场景设计

在设计场景之前,首先要明白公共代码抽取常见的几种情况:

  1. 抽取 Webpack 运行时代码
  2. 直接加载的代码抽取(静态引入)
    • node_modules 中的代码
    • 项目中的业务代码
  3. 按需加载的代码抽取(动态引入)
    • node_modules 中的代码
    • 项目中的业务代码

经过分析会发现,现在常见的场景就五种,设计一个应用场景包含这五种情况,就可以很好的理解 Webpack V4 如何抽取公共代码了。

设计场景如下:

其中带有 ~ 的表示是动态引入
module 是一个独立的功能模块,chunk 是很多 module 打包的结果,bundle 是很多 chunk 最后生成的结果

打包入口动态和静态导入的模块:

入口 模块A 模块B 模块C 模块D
pageA moduleA moduleB moudleC moudleD~
pageB moduleA moduleB moudleC~ moudleD~
pageC moduleA moduleB~ moudleC~ moudleD~
pageD moduleA~ moduleB~ moudleC~ moudleD~

模块中动态和静态导入的 node_modules 中的模块:

模块 react vue lodash jquery
moduleA react vue lodash jquery~
moduleB react vue lodash~ jquery~
moduleC react vue~ lodash~ jquery~
moduleD react~ vue~ lodash~ jquery~

入口文件中的代码(以 pageA.js 为例,其他的入口文件中的代码类似):

import './module/moduleA';
import './module/moduleB';
import './module/moduleC';
import('./module/moduleD');

console.log('pageA');

模块中的代码(以 moduleA.js 为例,其他的模块文件中的代码类似):

import 'react';
import 'vue';
import 'lodash';
import('jquery');

console.log('moduleA');

export default 'moduleA';

最终打包之后的预期效果:

  1. node_modules 的按需加载模块在一个 chunk 中,包含 react、vue、lodash、jquery
  2. node_modules 的直接加载的模块在一个 chunk 中,包含 react、vue、lodash
  3. 项目中按需加载的模块在一个 chunk 中,包含 moduleA、moduleB、moduleC、moduleD
  4. 项目中直接加载的模块在一个 chunk 中,包含 moduleA、moduleB、moduleC
  5. 有一个 Webpack 的运行时 chunk:runtime.bundle.js

import(‘react‘);
import(‘vue‘);
import(‘lodash‘);
import(‘jquery‘);

认识配置

在 Webpack V4 中已经提供了抽取公共代码的默认配置。

官方给出的默认配置:

module.exports = {
  optimization: {
    splitChunks: {
      automaticNameDelimiter: '~',
      name: true,
      chunks: 'async',
      minSize: 30000,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  }
};

各个选项的说明:

  • optimization.automaticNameDelimiter:指定生成名字中的分隔符,Webpack 将使用 chunk 的名字和 chunk 的来源,如 vendors~main.js
  • optimization.name:分割块的名称,提供 true 会自动生成基于 chunk 和缓存组键的名称
  • optimization.maxAsyncRequests:按需加载时,并行请求的最大数量,默认是 5
  • optimization.maxInitialRequests:一个入口最大的并行请求数,默认是 3
  • optimization.minChunks:在分割之前,这个代码块最小应该被引用的次数,默认是 1
  • optimization.chunks需要关心的属性,一般可以指定三种形式 all(全部的 chunk,包含所有类型的 chunk)、async(按需加载的 chunk) 和 initial(初始的 chunk)
  • optimization.minSize需要关心的属性,一个新的 chunk 的最小体积,默认是 30000,即 30K
  • optimization.cacheGroups:该属性是一个对象,上面的属性可以在该对象中使用,如果在该对象中不使用,则默认继承上面的属性值
    • cacheGroups:是一个对象,下面的所有属性都是自定义的,一般是打包后的模块名称
    • cacheGroups.name需要关心的属性,抽取公共代码的 chunk 名字
    • cacheGroups.priority需要关心的属性,抽取公共代码的优先级,数字越大,优先级越高
    • cacheGroups.reuseExistingChunk需要关心的属性,是否重用 chunk,如果当前块包含已经从主bundle中分离出来的模块,那么它将被重用,而不是生成一个新的模块,一般设置为 true
    • cacheGroups.test需要关心的属性,匹配规则,一般使用正则表达式来匹配,如 /[\\/]node_modules[\\/]/ 是匹配 node_modules 中的模块

下面的例子中主要是演示上面指出的需要关心的属性。

准备工作

为了能够更好的查看程序执行的效果,需要做以下几个准备工作。

1.创建 package.json 并安装相关依赖和指定运行的 scripts

  "scripts": {
    "build": "webpack --mode production"
  },
  "devDependencies": {
    "webpack": "^4.17.1",
    "webpack-cli": "^3.1.0"
  },
  "dependencies": {
    "jquery": "^3.3.1",
    "lodash": "^4.17.10",
    "react": "^16.4.2",
    "vue": "^2.5.17"
  }

2.创建 Webpack 的配置文件 webpack.config.js,并输入公共的配置内容

const { resolve } = require('path');

const webpackConfig = {};

// 入口
webpackConfig.entry = {
  pageA: './src/pageA.js',
  pageB: './src/pageB.js',
  pageC: './src/pageC.js',
  pageD: './src/pageD.js'
};

// 出口
webpackConfig.output = {
  path: resolve(__dirname, './dist'),
  filename: '[name].bundle.js',
  // chunkFilename 的作用就是设置 chunk 的名字,抽取公共代码的时候有用
  chunkFilename: "[id].[name].chunk.js"
};

// 优化相关
webpackConfig.optimization = {
  splitChunks: {
    automaticNameDelimiter: '~',
    name: true,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    minChunks: 1,
    minSize: 0, // 这里自定义不管文件有多小,都要抽取公共代码
    cacheGroups: {}
  }
};

module.exports = webpackConfig;

3.执行命令

$ yarn build

查看未抽取公共代码的效果

上面准备工作中配置的 webpack.config.js 是没有经过抽取公共代码的,执行命令之后,会发现控制台中输出下面的结果:

          Asset       Size                   Chunks             Chunk Names
   6.6.chunk.js  284 bytes                        6  [emitted]
   0.0.chunk.js  219 bytes                        0  [emitted]
   2.2.chunk.js   7.21 KiB                        2  [emitted]
   3.3.chunk.js   69.3 KiB                        3  [emitted]
   4.4.chunk.js   64.3 KiB                        4  [emitted]
   5.5.chunk.js   85.3 KiB                        5  [emitted]
   1.1.chunk.js  311 bytes                        1  [emitted]
   7.7.chunk.js  217 bytes                        7  [emitted]
pageA.bundle.js    143 KiB  8, 0, 2, 3, 4, 6, 7, 12  [emitted]  pageA
pageB.bundle.js    143 KiB     9, 0, 2, 3, 4, 7, 12  [emitted]  pageB
pageC.bundle.js    143 KiB       10, 0, 2, 3, 4, 12  [emitted]  pageC
pageD.bundle.js   2.22 KiB                       11  [emitted]  pageD
 12.12.chunk.js  190 bytes                       12  [emitted]

从上面的结果中可以看出,没有抽取公共代码,下面就逐步优化,来抽取公共代码。

抽取 Webpack 运行时代码

在抽取 Webpack 运行时代码的时候,需要指定 runtimeChunk 属性:

  • true:表示每个入口都抽取一个公共的运行时代码
  • ‘single‘:表示多个入口抽取一个公共的运行时代码,一般使用这种方式
// 抽取运行时代码
webpackConfig.optimization.runtimeChunk = 'single';

执行命令之后,查看控制台:

            Asset       Size                   Chunks             Chunk Names
     7.7.chunk.js  284 bytes                        7  [emitted]
     0.0.chunk.js  219 bytes                        0  [emitted]
     2.2.chunk.js   7.21 KiB                        2  [emitted]
     3.3.chunk.js   69.3 KiB                        3  [emitted]
     4.4.chunk.js   64.3 KiB                        4  [emitted]
     5.5.chunk.js   85.3 KiB                        5  [emitted]
runtime.bundle.js   2.16 KiB                        6  [emitted]  runtime
     1.1.chunk.js  311 bytes                        1  [emitted]
     8.8.chunk.js  217 bytes                        8  [emitted]
 9.pageA.chunk.js    141 KiB  9, 0, 2, 3, 4, 7, 8, 13  [emitted]  pageA
10.pageB.chunk.js    141 KiB    10, 0, 2, 3, 4, 8, 13  [emitted]  pageB
11.pageC.chunk.js    141 KiB       11, 0, 2, 3, 4, 13  [emitted]  pageC
12.pageD.chunk.js  328 bytes                       12  [emitted]  pageD
   13.13.chunk.js  190 bytes                       13  [emitted]

这时,会发现多了一个 runtime.bundle.js 文件,这个文件就是 Webpack 的运行时代码。

抽取公共代码

下面抽取的公共代码就只包含了四部分:项目中的静态导入、项目中的动态导入、node_modules 中的静态导入、node_modules 中的动态导入。

这四种情况,自己划分了一下优先级,可以在代码中看出来。

node_modules 中的直接加载的代码:

webpackConfig.optimization.splitChunks.cacheGroups.nodeSrc = {
  name: 'nodeSrc',
  reuseExistingChunk: true,
  test: /[\\/]node_modules[\\/]/,
  chunks: 'initial', // 指定为初始的 chunk
  priority: 3
};

node_modules 中的按需加载的代码:

webpackConfig.optimization.splitChunks.cacheGroups.nodeAsync = {
  name: 'nodeAsync',
  reuseExistingChunk: true,
  test: /[\\/]node_modules[\\/]/,
  chunks: 'async', // 指定为按需加载的 chunk
  priority: 2
};

项目中的直接加载的代码:

webpackConfig.optimization.splitChunks.cacheGroups.commonSrc = {
  name: 'commonSrc',
  reuseExistingChunk: true,
  chunks: 'initial', // 指定为初始的 chunk
  priority: 1
};

项目中的按需加载的代码:

webpackConfig.optimization.splitChunks.cacheGroups.commonAsync = {
  name: 'commonAsync',
  reuseExistingChunk: true,
  chunks: 'async', // 指定为按需加载的 chunk
  priority: 0
};

执行命令之后,可以看到打包之后的最终效果:

                 Asset       Size  Chunks             Chunk Names
0.commonAsync.chunk.js  946 bytes       0  [emitted]  commonAsync
  1.nodeAsync.chunk.js    226 KiB    1, 4  [emitted]  nodeAsync
  2.commonSrc.chunk.js   1.22 KiB       2  [emitted]  commonSrc
     runtime.bundle.js   2.19 KiB       3  [emitted]  runtime
    4.nodeSrc.chunk.js    141 KiB       4  [emitted]  nodeSrc
      5.pageA.chunk.js   74 bytes       5  [emitted]  pageA
      6.pageB.chunk.js   74 bytes       6  [emitted]  pageB
      7.pageC.chunk.js   74 bytes       7  [emitted]  pageC
      8.pageD.chunk.js   72 bytes       8  [emitted]  pageD

如果感觉这种带数字的名字查看不直观,就修改 output 中的 chunkFilename 的值为 "[name].chunk.js"

最终经过 Webpack 打包后的代码就是预期的结果。

参考资料

原文地址:https://www.cnblogs.com/negivup/p/9525599.html

时间: 2024-10-08 22:07:15

抽取公共代码的相关文章

基于webpack实现多html页面开发框架六 提取公共代码

一.解决什么问题 1.如果a.js和b.js都引用了common.js,那在打包的时候common.js会被重复打入到a.js和b.js,造成重复打包 2.单独打包common.js对性能有帮助,浏览器下载一次后会缓存下来,不会重复下载 二.未抽取公共代码的状况 基于之前代码,测试如下: 1.在assets/js文件夹下新建common.js,输入如下代码: 1 export function printCommon(){ 2 console.log("common"); 3 } 2.

系统管理模块_部门管理_改进_抽取添加与修改JSP页面中的公共代码_在显示层抽取BaseAction_合并Service层与Dao层

系统管理模块_部门管理_改进1:抽取添加与修改JSP页面中的公共代码 commons.jspf <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <meta http-equiv="Conten

如何在vuejs中抽出公共代码

当我们在使用vue构建中大型项目时,通常会遇到某些经常用的方法以及属性,比如说搭建一个员工管理系统,请求的url需要一个共同的前缀,或者在某几个view中需要用到时间,这个时间是通过某方法格式化之后的等等,如果每次用到都写共同的代码,那样如果之后有变动的话维护起来会非常麻烦. 所以我们就得想办法抽出公共代码,因为vue是组件化开发,我们就会很自然的与es6的module模块化联系到一起.其实当我们在搭建项目结构时就应该先提前埋下伏笔,有一个util文件夹,里面放的就是我们要写的公共代码,其实很多

通达OA公共代码 php常用检测函数

通达OA公共代码 php常用检测函数 从通达OA公共代码扒下的php常用检测函数代码,学习php的朋友可以参考下. check_type.php(使用类型检验函数) 复制代码 代码如下: <?php /*********************/ /* */ /* Version : 5.1.0 */ /* Author : RM */ /* Comment : 071223 */ /* */ /*********************/ function is_number( $str )

webpack提取公共代码。

webpack.optimize.CommonsChunkPlugin这个是内置方法到时候new就行了. 首先创 var webpack=require('webpack') var path=require('path') module.exports={ entry:{ 'pageA':'./src/pageA', 'pageB':'./src/pageB', 'vendor':['lodash'] }, output:{ path:path.resolve(__dirname, './di

The way of Webpack learning (II.) -- Extract common code(多页面提取公共代码)

学习之路基于webpack3.10.0,webpack4.0之后更新. 多页面提取公共代码!!! 一:文件关系 pageA --> subA.subB --> moduleA pageB --> subA.subB --> moduleA 那么pageA.pageB 的公共代码就是subA.subB .moduleA. 二:webpack.config.js文件配置 var webpack = require('webpack') var path = require('path'

webpack配置提取公共代码

公共代码提取功能是针对多入口文件的: 背景:在pageA.js和pageB.js中分别引用subPageA.js和subPageB.js webpack.config.js文件: 1 var path = require('path') 2 module.exports = { 3 entry:{ 4 pageA:'./src/pageA.js', 5 pageB:'./src/pageB.js' 6 }, 7 output: { 8 filename: "[name].js", 9

【直接拿来用のandroid公共代码模块解析与分享】の Notification和NotificationManager

本文源代码托管在https://github.com/ASCE1885/asce-common,欢迎fork Android项目做得多了.会发现原来非常多基础的东西都是能够复用,这个系列介绍一些自己项目中经常使用到的公共模块代码(当然仅仅谈技术不谈业务),一来整理好了自己以后能够直接用,二来也分享给大家,希望能略微降低大家的加班时间,提高些许效率. Android Notification的原理和作用这里就不作说明了,相信是个android开发人员都用过不止一次了,下面仅仅介绍怎样封装成公共的模

如何引入公共代码?

刚开始写项目的时候,有多少个页面,就复制多少次公共的代码(如头部,尾部).显然这不是明智之举.下面介绍一种引入公共头部的方法. 1.首先在页面引入该JavaScript文件(include.js). (function(window, document, undefined) { var Include39485748323 = function() {} Include39485748323.prototype = { //倒序循环 forEach: function(array, callb