webpack v4 中的断舍离 - 代码分离 SplitChunksPlugin(一)

栏目: 编程工具 · 发布时间: 6年前

内容简介:Time went by...  webpack已经从v3版本升级升级到了v4版本,刚刚我在官网看见升级到案例地址代码分离主要目的是防止代码重复,减少代码体积,达到加载速度快减少服务器压力和带宽等目的。webpack v3使用

Time went by...  webpack已经从v3版本升级升级到了v4版本,刚刚我在官网看见升级到 v4.16.5 。最近webpack的升级速度很快,几乎两个星期就会有一个小版本的更新。软件更新速度快是一件好事情,会让一款软件更加稳定和便捷,但对于使用着来说无疑是增加了学习成本。

案例地址 github.com/z354392349/…

代码分离主要目的是防止代码重复,减少代码体积,达到加载速度快减少服务器压力和带宽等目的。webpack v3使用 CommonsChunkPlugin插件配置代码分离 但在webpack v4中被废除了,但新增了 SplitChunksPlugin 作为替代品,并且配置过程更为便捷高效。今天我就将代码分离的使用方法分享给大家。 Remember me my name is 铅笔画不出的黑白

安装方法

npm install webpack-cli webpack -g   // 在全局环境 和 项目内安装  
复制代码

层级目录

假设一个学校有两个班级A班级和B班级,有三名老师分别是英语老师、数学老师、语文老师。(这个例子我想了很久,应该比较好理解吧,试想你上学的情景)老师给不同的班级上课,那么此时班级内的学生就相当于公用变量。为防止代码的重复我们需要将学生打包到一个文件内。

project
|- scr
    |- classes  
        |- class-a
        |- class-b
        |- class-c
    |- english
    |- math
    |- chinese
复制代码

package.json

{
  "name": "school",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },/[p-]
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "import-local": "^1.0.0",
    "lodash": "^4.17.10",
    "webpack": "^4.16.5",
    "webpack-cli": "^3.1.0"
  }
}

复制代码

minimize

minimize 属性不算是SplitChunksPlugin下的属性,但事两者之间是兄弟关系,都是Optimization(优化)下的属性, 是负责代码压缩的,在这里介绍minimize的原因是webpackV4版本中默认将压缩打开了,为了更直观的看到本文的效果,我们暂时将minimize设置为false,minimize的具体设置就不在这里展开了。 (看例1)

automaticNameDelimiter

连接符:此选项允许您指定用于生成名称的分隔符。假设我们生成了一个公用文件名字叫version,class-a,和class-b都依赖他,并且我们设置的连接符是"~"那么,最终生成的就是 version~class-a~class-b.js。(看例1)

minSize

模块被分离前最小的模块大小以字节(b)为单位,例如class-a(~137b)、class-b (~142b) class-c (~142b) 都将会被分离被打包为一个新文件,如果minSize设置为421以上它们就不会被分离,如果设置为421以下(包括421)它们就会被分离合并为新的文件。(看例1)

注意:这里可能会产生很小误差,我在测试本案例时中文会有5kb的误差,英文没有产生误差,另外编辑器大多是以UTF-8格式,webpack应该是GBk格式计算。如果你想精确的知道webpack计算出文件的大小可以在打包完成后看webpack的输出。

webpack v4 中的断舍离 - 代码分离 SplitChunksPlugin(一)

maxSize

使用maxSize告诉webpack尝试将大于maxSize的块拆分成更小的部分。拆解后的文件最小值为minSize,或接近minSize的值。这样做的目的是避免单个文件过大,增加请求数量,达到减少下载时间的目的。但是这个值设置的时候要掌握好,如果设置的过小产生过多小文件会适得其反。另外HTTP1.0中最大的请求数量为6。在HTTP2.0中则没有限制。

将案例1中 splitChunks.maxSize 设置为130你就会发现, class-a、class-b、class-c。会被分离为三个独立的文件。注意:这只是一个案例,为了演示效果,在实际开发中不能这么用。

例1

// class-a.js
export default [
    {student: "大红", age: 18},
    {student: "大米", age: 19},
    {student: "大爱", age: 17},
    {student: "大明", age: 20}
]
复制代码
// class-b.js
export default [
    {student: "小红", age: 18},
    {student: "小米", age: 19},
    {student: "小爱", age: 17},
    {student: "小明", age: 20}
]
复制代码
// class-c.js
export default [
    {student: "张三", age: 18},
    {student: "李四", age: 19},
    {student: "王五", age: 17},
    {student: "赵六", age: 20}
]
复制代码
// webpack.config.js
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    mode: "production",
    entry: {
        english: "./src/english.js",
        math: "./src/math.js",
        chinese: "./src/chinese.js",
    },
    output: {
        filename: "[name].bundle.js",
        path: path.resolve(__dirname, 'dist'),
    },
    plugins: [
        new CleanWebpackPlugin(['dist'])
    ],
    optimization: {
        minimize: false,
        splitChunks: {
            chunks: "all",  //  async
            minSize: 400,
            automaticNameDelimiter: '~',
        }
    },
};

复制代码
// english.js
import classA from './classes/class-a';
import classB from './classes/class-b';
import classC from './classes/class-c';

let engligh = {
    teacher: 'english', age: 47
};

classA.push(engligh);
classB.push(engligh);
classC.push(engligh);

复制代码
// chinese.js
import classA from './classes/class-a';
import classB from './classes/class-b';
import classC from './classes/class-c';

let engligh = {
    teacher: 'english', age: 47
};

classA.push(engligh);
classB.push(engligh);
classC.push(engligh);
复制代码
// math.js
import classA from './classes/class-a';
import classB from './classes/class-b';
import classC from './classes/class-c';


let math = {
    teacher: 'math', age: 47
};

classA.push(math);
classB.push(math);
classC.push(math);
复制代码

运行webpack 你会发现在 dist 下会有三个文件chinese.build.js、english.build.js、math.bundle.js 和公共文件chinese~english~math.bundle.js。

chunks

表示对哪些模快进行优化,可选字符串值有 allasyncinitial 、和函数。

  • async 表示对动态(异步)导入的模块进行分离。(看例2.1)
  • initial 表示对初始化值进行分离优化。(看例2.2)
  • all 表示对所有模块进行分离优化,一般情况下都用all (看例2.3)
  • 函数 代表对指定的模块快分离优化,相当于定制优化。(看例2.4)

例2.1

更改下列文件,其他文件不变和例1一样。

// chinese.js
import classC from './classes/class-c';

let engligh = {
    teacher: 'english', age: 47
};


import(/* webpackChunkName: "async-class-a" */ './classes/class-a').then(classA =>{
    classA.push(engligh);
});
import(/* webpackChunkName: "async-class-a" */ './classes/class-b').then(classB =>{
    classB.push(engligh);
});
classC.push(engligh);

复制代码
// english.js
import classB from './classes/class-b';
import classC from './classes/class-c';

let engligh = {
    teacher: 'english', age: 47
};

import( /* webpackChunkName: "async-class-a" */  './classes/class-a').then(classA =>{
    classA.push(engligh);
});

classB.push(engligh);
classC.push(engligh);

复制代码
// math.js
import classB from './classes/class-b';
import classC from './classes/class-c';


let math = {
    teacher: 'math', age: 47
};
import(/* webpackChunkName: "async-class-a" */  './classes/class-a').then(classA =>{
    classA.push(engligh);
});
classB.push(math);
classC.push(math);

复制代码
webpack.config.js
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    mode: "production",
    entry: {
        english: "./src/english.js",
        math: "./src/math.js",
        chinese: "./src/chinese.js",
    },
    output: {
        filename: "[name].bundle.js",
        path: path.resolve(__dirname, 'dist'),
    },
    plugins: [
        new CleanWebpackPlugin(['dist'])
    ],
    optimization: {
        minimize: false,
        splitChunks: {
            chunks: "async",  // async、 initial 、 all
            minSize: 0,
            automaticNameDelimiter: '~',
        }
    },
};

复制代码
webpack v4 中的断舍离 - 代码分离 SplitChunksPlugin(一)

运行webpakck dist下会有五个文件,chinese.bundle.js、english.bundle.js、math.bundle.js 以及动态加载的 async-class-a.bundle.js、async-class-b.bundle.js 而非动态导入的 class-c.js则不会被拆分为一个新文件。

注意为什么会是这个名字,因为我导入时写了 /* webpackChunkName: "async-class-a" */ , /* webpackChunkName: "async-class-b" */ output.chunkFilename 此选项决定了非入口(non-entry) chunk 文件的名称。

该项操作webpack只关心异步(动态)导入,即使 english.js、 math.js 、chinese.js 都引入了 class-c.js,也不会被打包为一个独立的文件。

例2.2

webpack.config.jsoptimization.splitChunks.chunks 的值更改为 initial ,这个属性的意思是告诉webpack,我希望将动态导入的文件和非动态导入的文件分别打包,如果一个模块被动态引入,也被非动态引入。那么这个模块将会被分离2次。被分别打包到不同的文件中。

运行webpack,dist下会有7个文件,不要惊慌我将会解答每个文件生成的过程。 english.bundle.js、math.bundle.js、chinese.bundle.js、这三个是入口文件不做过多的解释。

async-class-a.bundle.js 是因为chinese.js、english.js、math.js。 都异步引入了class-a。

async-class-b.bundle.js 是因为chinese.js异步引入了class-b。然而english~math.bundle.js 文件的内容和async-class-b.bundle.js几乎完全一样,都包含了class-b模块。这是因为 english.js、math.js都非异步的引入了class-b。

chinese~english~math.bundle.js 是因为chinese.js、english.js、math.js。 都非异步引入了class-c.js。

例2.3

webpack v4 中的断舍离 - 代码分离 SplitChunksPlugin(一)
webpack.config.jsoptimization.splitChunks.chunks 的值更改为 all

,此时的webpack就犹如上面的哈士奇一样,根本不会区分动态还是非动态,只是将需要的文件分离出一份。

运行webpack 你会发现dist下有6个文件,其中三个是入口文件english.bundle.js 、 math.bundle.js、 chinese.bundle.js , 这没什么好说的。class-a.js、class-b.js、class-c.js 文件被分别打包为 async-class-a.bundle.js、async-class-b.bundle.js、chinese~english~math.bundle.js。

从打包结果来看,我猜测webpack的内部原理就是只要这个模块被动态加载了一次,就按动态加载处理。然后共享给其他非动态的模块。这里点可以从async-class-b.bundle.js的处理结果中看出。

例2.4

将webpack.config.js的optimization.splitChunks.chunks的值更改为一个函数,这个函数返回Boolean值。如果值为ture 则分离优化这个模块。为false则不分离优化。

改操作在我测试过程中可选项为入口文件math、english、chinese (注意:这是入口文件名称,不是文件名)

// webpack.config.js  optimization.splitChunks.chunks

chunks: function (chunk) {
            return chunk.name !== ''
        },
复制代码

运行webpack你会发现,输出结果和 chunks: 'all' 一样。因为所有返回值都是ture,下面我们在测试入口文件为false的情况。

// webpack.config.js  optimization.splitChunks.chunks

chunks: function (chunk) {
            return chunk.name !== 'math'
        },
复制代码

运行webpack,结果还是和 chunks: 'all' 几乎一样,但是仔细看chinese~english~math.bundle.js文件变成了 chinese~english.bundle.js。打开math.bundle.js文件,在文件的下面你会发现class-b.js,class-c.js模块的全部内容,他们并没有被分离出去。但是class-a.js模块却被分离出去。仔细看文件最后的几行代码,class-a.js模块是动态加载的。

由此我们可以得出结论,当一个模块是非动态加载的那么他将不会被分离出去,如果这个模块是动态加载的,她就会被分离出去,并且还是动态引入关系。

maxInitialRequests

入口点处的最大并行请求数,换句话来讲就是每一个入口文件打包完成后最多能有多少个模块组成。为了更好的理解本案例(例3),我将会更改下列代码。

webpack v4 中的断舍离 - 代码分离 SplitChunksPlugin(一)

例3

// chinese.js 
import classC from './classes/class-c';
import classB from './classes/class-b';

let chinese = {
    teacher: 'chinese', age: 47
};


classB.push(chinese);
classC.push(chinese);
复制代码
// english.js
import classA from './classes/class-a';
import classC from './classes/class-c';

let engligh = {
    teacher: 'english', age: 47
};


classA.push(engligh);
classC.push(engligh);
复制代码
// math.js
import classA from './classes/class-a';
import classB from './classes/class-b';


let math = {
    teacher: 'math', age: 47
};
classA.push(math);
classB.push(math);
复制代码
// webpack.config.js
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    mode: "production",
    entry: {
        english: "./src/english.js",
        math: "./src/math.js",
        chinese: "./src/chinese.js",
    },
    output: {
        filename: "[name].bundle.js",
        path: path.resolve(__dirname, 'dist'),
    },
    plugins: [
        new CleanWebpackPlugin(['dist'])
    ],
    optimization: {
        minimize: false,
        splitChunks: {
            chunks: 'all',
            maxInitialRequests: 1,
            minSize: 0,
            automaticNameDelimiter: '~',
        }
    },
};
复制代码

例3.1

maxInitialRequests 设置为了1,运行webpack在dist文件夹内只有三个入口文件,也就是说打包完成后每个入口文件最多之只能由1个文件组成。所以没有分离出来任何独立的模块。

例3.2

maxInitialRequests 设置为了2,运行webpack相比于例3.1在dist下会多出一个english~math.bundle.js文件。文件内是class-a.js模块,但是class-b.js和class-c.js模块也被引入了两次。为什么偏偏class-a.js被分离出来了呢。我带着这个疑问反复的测试。最终结果是可能和模块名称有关。如果将class-a.js更换为class-d.js那么被分离的就是class-b.js文件。

一个入口打包完成后最多之能有2个文件组成。english.bundle.js 和 math.bundle.js 都引入english~math.bundle.js 已经达到上限了。chinese.bundle.js 也没有必要自找麻烦把模块分离出来再引入进去,所以 chinese.bundle.js就没有任何模块分离出来。

例3.3

maxInitialRequests 设置为了3,这就相当于每个入口文件打包完成后最多可由3个模块组成, 运行webpack在dist文件夹下面有6个文件,class-a.js、class-b.js、class-c.js 全部都被分离出来了。但是当你将 maxInitialRequests 设置为了3以上时在运行webpack,答案和3是一样的。因为webpack 没有必要再分离出更多的模块。

maxAsyncRequests

按需加载时并行请求的最大数目,但是很抱歉这个属性我理解的可能不是很到位,无法写出案例给各位,如果哪位同学可以写出这个属性的demo请联系我。我会很感谢。 engineering.wingify.com/posts/demys… 这个demo 是我在Google上看到的,是关于这个属性的使用方法。这个属性我还会继续研究,如果有研究成果我写出一个demo给大家。

总结

maxSize的优先级高于maxInitialRequest / maxAsyncRequests。 实际优先级为maxInitialRequest / maxAsyncRequests <maxSize <minSize。


以上所述就是小编给大家介绍的《webpack v4 中的断舍离 - 代码分离 SplitChunksPlugin(一)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

统计思维:程序员数学之概率统计

统计思维:程序员数学之概率统计

Allen B.Downey / 张建锋、陈钢 / 人民邮电出版社 / 2013-5 / 29.00元

代码跑出来的概率统计问题; 程序员的概率统计开心辞典; 开放数据集,全代码攻略。 现实工作中,人们常被要求用数据说话。可是,数据自己是不能说话的,只有对它进行可靠分析和深入挖掘才能找到有价值的信息。概率统计是数据分析的通用语言,是大数据时代预测未来的根基。 站在时代浪尖上的程序员只有具备统计思维才能掌握数据分析的必杀技。本书正是一本概率统计方面的入门图书,但视角极为独特,折......一起来看看 《统计思维:程序员数学之概率统计》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换