webpack 文档(指南) - 代码块分割(抽离公用模块代码)

webpack 的代码分离的方式有以下三种:

  • 入口起点:entry 使用多入口
  • 防止重复:使用 SplitChunksPlugin 去重和分离 chunk
  • 动态导入:通过模块的内联函数调用(懒加载)来分离代码

入口起点

以入口分割代码的方式,只需要配置多入口就可以。

index.js

console.log('index.js');

index2.js

console.log('index2.js');

webpack.config.js

var HtmlWebpackPlugin = require('html-webpack-plugin');
var {CleanWebpackPlugin} = require('clean-webpack-plugin');
module.exports = {
    mode: 'development',
    entry: {
        index: './index.js',
        index2: './index2.js'
    },
    output: {
        publicPath: '',
        path: __dirname + '/dist',
        filename: '[name].js'
    },
    module: {
        rules: []
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({template: './index.html'}),
    }
}

打包目录如下,项目代码被分割为了两个 chunk

在这里插入图片描述

动态导入

index.js

console.log('index.js');

import('./async').then((res) => {
    console.log(res);
})
import('./async2').then((res) => {
    console.log(res);
})

webpack.config.js

var HtmlWebpackPlugin = require('html-webpack-plugin');
var {CleanWebpackPlugin} = require('clean-webpack-plugin');
module.exports = {
    mode: 'development',
    entry: {
        index: './index.js'
    },
    output: {
        publicPath: '',
        path: __dirname + '/dist',
        filename: '[name].js',
        chunkFilename: '[name].async.js'
    },
    module: {
        rules: []
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({template: './index.html'}),
    ]
}

打包目录如下,代码被分割为了 3 个 chunk

在这里插入图片描述

防止重复

有些时候,可能很多的 chunk 引入了同一个模块,那么者模块就是可以被抽离出来的,webpack 可以借助 SplitChunksPlugin 插件来抽离公用模块代码( webpack4 使用 CommonsChunkPlugin 插件),不需要安装这个插件,只需要在 webpack 的配置项中加入 optimization.splitChunks 的配置即可。

webpack.config.js(文档例子的配置)

module.exports = {
  //...
  optimization: {
    splitChunks: {
      // async - 表示只抽离异步 chunk 的共用模块代码
      // initial - 表示只抽离入口 chunk 中公用模块代码
      // all - 表示抽离所有公用模块代码,一般设为这个即可
      chunks: 'async',
      // 生成 chunk 的最小大小
      minSize: 30000,
      // 超过这个大小会提示
      maxSize: 0,
      // 公用模块被多少个chunk共享时才抽离,一般为 2
      minChunks: 1,
      // 懒加载的最大并行请求数,
      // 按需加载时,可能还需并行请求抽离的公用模块(Promise.all([])),
      // 请求总数不能超过这个值,超过则不继续抽离公用模块代码
      maxAsyncRequests: 5,
      // 入口点的最大并行请求数
      // 项目启动后,第一次并行加载的 js 文件数不能超过这个数,超过则不继续抽离
      maxInitialRequests: 3,
      // 抽离的公共模块的文件名连接符,对懒加载抽离公用的 chunk 不生效
      automaticNameDelimiter: '~',
      // 为 true 时,抽离的模块名会使用组名称
      name: true,
      // 缓存组,可覆盖父级的配置
      // 它可以使用 test ,priority,reuseExistingChunk 
      // 利用这个可以配置细粒度的抽离公用代码配置选项
      cacheGroups: {
        // 组名称
        vendors: {
          // 只抽离第三方模块
          test: /[\\/]node_modules[\\/]/,
          // 优先级
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          // 如果模块已经被抽离,则不再抽离,直接复用抽离的 chunk
          reuseExistingChunk: true
        }
      }
    }
  }
};

准备公用模块文件:入口 chunk 公用模块文件、按需加载 chunk 的公用模块文件、某个入口 chunk 和某个按需加载 chunk 的公用模块文件。还有其他情况的公用模块,这里就不一一实践了,只要配置了公用模块代码抽离的配置选项,webpack 就会智能的对这些公用代码进行抽离。

initial-common.js

// 入口 chunk 公用模块
function initialCommon(a, b) {
    return a * b;
}
var res = initialCommon(1, 2);
console.log(res);

async-common.js

/**
 * 懒加载 chunk 的公用模块 
 */

function asyncCommon(a, b) {
    return a * b;
}
var res = asyncCommon(1, 2);
console.log(res);

index1-async1-common.js

/**
 * 某个入口 chunk 和某个按需加载 chunk 的公用模块
 */

function index1Async1Common(a, b) {
    return a * b;
}
var res = index1Async1Common(1, 2);
console.log(res);

接着是按需加载的两个 chunk

async1.js

console.log('async1.js');

// 引入懒加载 chunk 的公用模块
import './async-common';

// 引入口 chunk index.js 模块和本模块的公用模块文件
import './index1-aysnc1-comon';

async2.js

console.log('async2.js');

// 引入懒加载 chunk 的公用模块
import './async-common';

接下来是两个入口 chunk

index1.js

console.log('index1.js');

// 引入口 chunk 公用模块
import './initial-common';

// 引入某个入口 chunk 和某个懒加载的 chunk 的公用模块
import './index1-aysnc1-comon';

import('./async1').then((res) => {
    console.log(res);
})

import('./async2').then((res) => {
    console.log(res);
})

index2.js

console.log('index2.js');

// 引入口 chunk 公用模块
import './initial-common';

最后是 webpack 的配置。

webpack.config.js

var HtmlWebpackPlugin = require('html-webpack-plugin');
var {
  CleanWebpackPlugin
} = require('clean-webpack-plugin');
module.exports = {
  mode: 'development',
  entry: {
    index1: './index1.js',
    index2: './index2.js'
  },
  output: {
    publicPath: '',
    path: __dirname + '/dist',
    filename: '[name].js',
    chunkFilename: '[name].async.js'
  },
  module: {
    rules: []
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './index.html'
    }),
  ],
  optimization: {
    splitChunks: {
      chunks: 'all',
      name: true,
      // 这个值太大的话,不会抽离公用模块!
      // 如果公用模块代码体积很小,也不需要抽离
      minSize: 0,
      minChunks: 2,
      automaticNameDelimiter: '~',
      cacheGroups: { // 缓存组的配置会覆盖父层的配置
        venders: {
          priority: 1, // 优先级,第一个执行
          test: /node_modules/, // 是第三方模块
        },
        common: {
          priority: 2,
        }
      }
    }
  }
}

看下打包目录。

在这里插入图片描述
入口 chunk 的公用模块。

common~index1~index2.async.js

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["common~index1~index2"],{

"./initial-common.js":
(function(module, exports) {

eval(`
  function initialCommon(a, b) {\r\n    
    return a * b;\r\n
  }\r\n
  var res = initialCommon(1, 2);\r\n
  console.log(res);\n\n
  //# sourceURL=webpack:///./initial-common.js?`);

})

}]);

按需加载 chunk 的公用模块。

0.async.js

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],{

"./async-common.js":
(function(module, exports) {

eval(`
  function asyncCommon(a, b) {\r\n    
    return a * b;\r\n
  }\r\n
  var res = asyncCommon(1, 2);\r\n
  console.log(res);\n\n
  //# sourceURL=webpack:///./async-common.js?`);
})

}]);

入口 chunk 对应的 index.js 文件和按需加载 chunk 对应的 async1.js 文件的公用模块被打包到了 index1.js 中 。

index1.js(代码片段)

"./index1-aysnc1-comon.js":
(function(module, exports) {

eval(`
  function index1Async1Common(a, b) {\r\n    
    return a * b;\r\n
  }\r\n
  var res = index1Async1Common(1, 2);\r\n
  console.log(res);\n\n
  //# sourceURL=webpack:///./index1-aysnc1-comon.js?`);
}),
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值