webpack code split(一)

327 阅读4分钟

一、什么是code split

一般我们会在入口文件main.js中引入了第三方库,假设我们引入的是moment,再假设他有2M;同时我们编写的几万行的业务代码有1M,那此时我们运行npm run build打包,最终出来的是main.js大小是3M,那就意味着用户首次打开index.html需要等待一个3M的js资源加载完成之后才会去执行文件里面的逻辑,进而把页面渲染出来。那么这将带打来几个问题:

  1. 打包文件会很大,首屏加载时间过长
  2. 资源重复加载:我们每次更新我们的业务逻辑代码,这将意味着每次重新访问页面都将需要加载这3M的js资源。但我们的第三方库一般情况下是不会改变的,是不需要每次都重新加载此资源

所以我们需要对代码进行分开打包,也就是我们的code split

二、如果进行code split

演示案例的准备工作

  1. 创建相应的目录并安装webpack
mkdir code-split
cd demo-01
npm init -y
npm install webpack webpack-cli --save-dev

image.png

  • webpack.config.js
// 基本配置
const path = require('path');
module.exports = {
  mode: "production",
  entry: './src/main.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};
  • 其他js文件随心情随便写点js代码
function add(x, y) {
  retur x + y
}

console.log(add(1, 2))
  1. 执行命令npx webpack打包

image.png

1. entry
  • 单入口 webpack.config.js
// 基本配置
const path = require('path');
module.exports = {
  mode: "production",
  entry: './src/main.js',
  output: {
    filename: '[name].chunk.[contenthash:10].js', // 修改输出文件的命名规则,便于我们区分
    path: path.resolve(__dirname, 'dist'),
  },
};

main.js中引入test.js

+ import { mult } from "./test.js"

function add(x, y) {
  return x + y
}

console.log(add(1, 2))
+ console.log(mult)

运行npx webpack打包,将会生成一个chunk文件 image.png

  • 多入口 其他不变仅修改webpack.config.js中的entry配置:
// 基本配置
const path = require('path');

module.exports = {
  mode: "production",
  // entry: './src/main.js',
  entry: {
    main: './src/main.js',
    test: './src/test.js'
  },
  output: {
    filename: '[name].chunk.[contenthash:10].js',
    path: path.resolve(__dirname, 'dist'),
  }
};

运行npx webpack打包,将会生成两个chunk文件 image.png

2.SplitChunksPlugin

webpack5 split-chunks-plugin

// webpack5 默认配置
module.exports = {
  // ...
  optimization: {
    splitChunks: {
        chunks: 'async',// 指明要分割的插件类型, async:异步插件(动态导入),inital:同步插件,all:全部类型
        minSize: 20000,// 文件最小大小,单位bite;即超过minSize有可能被分割;
        minRemainingSize: 0,// webpack5新属性,防止0尺寸的chunk
        maxSize: 0,
        minChunks: 1, // 模块的最小引用次数,如果引用次数低于这个值,将不会被优化
        maxAsyncRequests: 30,// 设置async chunks的最大并行请求数 webpack4,5区别较大
        maxInitialRequests: 30,// 设置initial chunks的最大并行请求数 webpack4,5区别较大
        enforceSizeThreshold: 50000,
        cacheGroups: {
          defaultVendors: { // 缓存组,自定义拆包规则在此定义
            test: /[\\/]node_modules[\\/]/,
            priority: -10,
            reuseExistingChunk: true
          },
          default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true
          }
        }
      }
  // ...
};
// webpack4 默认配置
module.exports = {
  // ...
  splitChunks: {
      chunks: "async", // initial:直接引入的模块 | async:按需引入的模块 | all:all in
      minSize: 20000, // 最小包体积,这里的单位是byte,超过这个大小的包会被splitChunks优化
      minChunks: 1, // 模块的最小引用次数,如果引用次数低于这个值,将不会被优化
      maxAsyncRequests: 5, // 设置async chunks的最大并行请求数
      maxInitialRequests: 3, // 设置initial chunks的最大并行请求数
      automaticNameDelimiter: '~', // 产出chunks的文件名分割符
      name: true, // true:根据提取chunk的名字自动生成,false:根据缓存组IdHint生成,string:生成文件命即为这个string
      cacheGroups: { // 缓存组,自定义拆包规则在此定义
        vendors: { // 默认配置,node_modules的chunk
          test: /[\/]node_modules[\/]/, 
          priority: -10 
        }, 
        default: { //业务代码的chunk
          minChunks: 2, 
          priority: -20, 
          reuseExistingChunk: true //复用已存在的chunks
        } 
      }
    }
  // ...
};

演示案例:多入口文件打包

  • webpack.config.js
// 增加optimization配置
const path = require('path');

module.exports = {
  mode: "production",
  // entry: './src/main.js',
  entry: {
    main: './src/main.js',
    test: './src/test.js'
  },
  output: {
    filename: '[name].chunk.[contenthash:10].js',
    path: path.resolve(__dirname, 'dist'),
  },
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
};
  • 修改main.js,在其中引入vue,先npm install vue
import { mult } from "./test.js"
import { VueElement } from "Vue"

function add(x, y) {
  return x + y
}

console.log(add)
console.log(mult)
console.log(VueElement)
  • 运行npx webpack打包,将会生成三个chunk文件

如果注释掉webpack.config.js中的optimization,将只会生成两个chunk文件 image.png

如果存在两个src/*.js同时引用一个第三方库,将只会打包一次chunk文件 修改test.js代码,使其引入vue.js;main.js不变

import { VueElement } from "Vue"

function mult(x, y) {
  return x * y
}

console.log(mult)
console.log(VueElement)

export {
  mult
}

image.png

3. 通过js代码,动态导入

修改main.js中的代码,使其动态引入test.js;


import { VueElement } from "Vue"

function add(x, y) {
  return x + y
}

console.log(add)
console.log(VueElement)

// 将单独打包
import(/* webpackChunkName: 'test' */"./test.js").then((mult) => console.log(mult)).catch(err => console.log(err))

修改webpack.config.js中的配置,采用单页面模式并关闭optimization;

// 基本配置
const path = require('path');

module.exports = {
  mode: "production",
  entry: './src/main.js',
  output: {
    filename: '[name].chunk.[contenthash:10].js',
    path: path.resolve(__dirname, 'dist'),
  }
};

运行npx webpack打包,将会生成两个chunk文件 image.png