搜尋
首頁web前端js教程Webpack的Bundle Split和Code Split有什麼差別? (詳解)
Webpack的Bundle Split和Code Split有什麼差別? (詳解)Jan 15, 2019 am 09:49 AM
javascriptnode.jswebpack

這篇文章帶給大家的內容是關於Webpack的Bundle Split和Code Split有什麼不同? (詳解)有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

說之前也是對 chunk 這個概念有些模糊,而且很多時候網路上的文章大部分在將程式碼分離動態載入之類的。寫這篇文章的目的也是要讓其他那些像我曾經對這個概念不是很清楚的童鞋有個清晰的認識。廢話不多說,擼起袖子直接乾!

Let's pe in!

#

Webpack 文件分离包括两个部分,一个是 Bundle 的分离,一个是 Code 代码的分离:

  • Bundle splitting: 实际上就是创建多个更小的文件,并行加载,以获得更好的缓存效果;主要的作用就是使浏览器并行下载,提高下载速度。并且运用浏览器缓存,只有代码被修改,文件名中的哈希值改变了才会去再次加载。

  • Code splitting: 只加载用户最需要的部分,其余的代码都遵从懒加载的策略;主要的作用就是加快页面加载速度,不加载不必要加载的东西。

准备工作

在进行文件分离之前的准备工作,我们先写一些代码:

入口文件 src/index.js:

const { getData } = require('./main')
const { findMaxIndex } = require('./math')

let arr = [1,2,123,21,3,21,321,1]

findMaxIndex(arr)
getData('./index.html')

两个依赖模块:

src/main.js:

const axios = require('axios')

const getData = url => {
    axios.get(url).then(d => {
        console.log(d.status)
        console.log(d.data.length)
    })
}

module.exports = {
    getData
}

src/math.js:

const _ = require('lodash')

const findMaxIndex = arr => {
    let x = _.max(arr)
    let r = Array.prototype.indexOf.call(arr, x)
    console.log(r);
}

module.exports = {
    findMaxIndex
}

增加一个 webpack 配置文件 webpack.config.js:

const path = require('path')

module.exports = {
    mode: 'development',
    entry: path.resolve(__dirname, 'src/index.js'),
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash].js'
    },
}

文件分离之前打包需要的时间

在 bundle split 和 code split 操作之前,我们先看一下当前默认打包的效果:

Webpack的Bundle Split和Code Split有什麼差別? (詳解)

全部依赖都被打包到 main.xxx.js 中去,大小是 609k

开始分离操作

Bundle Split

Bundle Split 的主要任务是将多个引用的包和模块进行分离,避免全部依赖打包到一个文件下

基本用法

Webpack 4 中需要使用到 optimization.splitChunks 的配置:

const path = require('path')

module.exports = {
    mode: 'development',
    entry: path.resolve(__dirname, 'src/index.js'),
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash].js'
    },
    optimization: {
        splitChunks: {
            chunks: 'all'
        }
    }
}
optimization.splitChunks 的意思是将所有来自 node_modules 中的依赖全部打包分离出来,这个时候我们再看打包的文件是个什么样子:

Webpack的Bundle Split和Code Split有什麼差別? (詳解)

增加了 splitChunks 的配置,我们第三方模块都被打包到了 vendors~main.xxx.js 中去了,这个文件大小有 604k,而入口文件 main.xxx.js 则只有 7k

虽然说这样将第三方模块单独打包出去能够减小入口文件的大小,但这样仍然是个不小的文件;这个小的测试项目中我们使用到了 axios 和 lodash 这两个第三方模块,因此我们希望的应该是将这两个模块单独分离出来两个文件,而不是全部放到一个 vendors 中去,那么我们继续配置 webpack.config.js:

将每个 npm 包单独分离出来

这里我们需要使用到 webpack.HashedModuleIdsPlugin 这个插件

参考官方文档

直接上代码:

const path = require('path')
const webpack = require('webpack')

module.exports = {
    mode: 'development',
    entry: path.resolve(__dirname, 'src/index.js'),
    plugins: [
        new webpack.HashedModuleIdsPlugin() // 根据模块的相对路径生成 HASH 作为模块 ID
    ],
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash].js'
    },
    optimization: {
        runtimeChunk: 'single',
        splitChunks: {
            chunks: 'all', // 默认 async 可选值 all 和 initial
            maxInitialRequests: Infinity, // 一个入口最大的并行请求数
            minSize: 0, // 避免模块体积过小而被忽略
            minChunks: 1, // 默认也是一表示最小引用次数
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/, // 如果需要的依赖特别小,可以直接设置成需要打包的依赖名称
                    name(module, chunks, chcheGroupKey) { // 可提供布尔值、字符串和函数,如果是函数,可编写自定义返回值
                        const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1] // 获取模块名称
                        return `npm.${packageName.replace('@', '')}` // 可选,一般情况下不需要将模块名称 @ 符号去除
                    }
                }
            }
        }
    }
}

这里我们主要做了几件事:

为了避免每次打包的文件哈希变化,我们可以使用 webpack 内置的 HashedModuleIdsPlugin,这样可以避免每次打包的文件哈希值变化

首先增加 maxInitialRequests 并设置成 Infinity,指定这个入口文件最大并行请求数

然后将 minSize 和 minChunks 分别设置成 0 和 1,即使模块非常小也将其提取出来,并且这个模块的引用次数只有 1 也要提取

最后配置匹配的依赖以及分离出的文件名格式

另外,我们还将运行时代码分离出来,这块代码还可以配合 InlineManifestWebpackPlugin 直接插入到 HTML 文件中。这里我们将这个配置设置成 single,即将所有chunk的运行代码打包到一个文件中

这样 Bundle Split 的操作基本就完成了,让我们看看效果如何:

Webpack的Bundle Split和Code Split有什麼差別? (詳解)

所依赖的几个模块都被分离出去了

使用 HtmlWebpackPlugin 这个插件将 js 代码注入 html 文件中

npm i -D html-webpack-plugin

修改 webpack.config.js 文件:

// 配置文件引入这个插件

var HtmlWebpackPlugin = require('html-webpack-plugin');
// ...
module.exports = {
    // ...
    plugins: [
        new HtmlWebpackPlugin(),
        new webpack.HashedModuleIdsPlugin() // 根据模块的相对路径生成 HASH 作为模块 ID
    ],
    // ...
}

安装 http-server 或使用 vscode 的插件 Live Server 将代码放入一个本地服务器中,打开浏览器的调试窗口进入到 Network 面板:

Webpack的Bundle Split和Code Split有什麼差別? (詳解)

可以看到我们将模块单独分离出来并行加载,这样比单独加载一个庞大的包要快不少,接下来我们还要进行代码分离,将不必要加载的模块延迟加载

Code Split

代码分离实际上就是只加载用户需要使用到的部分代码,不是必须的就暂时不加载。

这里我们要用到 require.ensure 这个方法去获取依赖,这样 webpack 打包之后将会增加运行时代码,在设定好的条件下才会触发获取这个依赖。

在 ES6 中我们可以用 Dynamic Imports 来替代上述方案,如果使用 ES6 语法那么需要使用到 babel 以及 babel 的插件 plugin-syntax-dynamic-import,在浏览器中为了保证兼容性,还需要安装 promise 的 polyfill,用法大同小异,可直接观摩 webpack 的官方文档

修改我们的代码:

const { getData } = require('./main')

let arr = [1,2,123,21,3,21,321,1]

getData('./index.html')

setTimeout(() => {
    require.ensure(['./math'], function(require) {
        const { findMaxIndex } = require('./math')
        console.log(findMaxIndex(arr))
    })
}, 3000)
我们设定了一个定时器,只有在 3000 毫秒以后,浏览器才会去请求这个 math 模块

编译之后,打开调试面板刷新浏览器:

Webpack的Bundle Split和Code Split有什麼差別? (詳解)

在页面刚加载完毕后,浏览器会尝试获取上述这么几个模块,因为模块都很小很快就加载完成了

Webpack的Bundle Split和Code Split有什麼差別? (詳解)

在 3500ms 左右,浏览器才会去获取 requie.ensure 方法定义的 math 模块,因 math 模块又包含依赖 lodash,因此这个 lodash 第三方模块也会被按需加载。

这样我们就完成了代码分离的操作,这样做的优势就是不需要第一时间加载的模块,可以推迟加载,以页面的加载速度。当然,上面的 timeout 定时器完全可以换成其他诸如按钮点击之类的事件来触发。

以上是Webpack的Bundle Split和Code Split有什麼差別? (詳解)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:segmentfault。如有侵權,請聯絡admin@php.cn刪除
Vercel是什么?怎么部署Node服务?Vercel是什么?怎么部署Node服务?May 07, 2022 pm 09:34 PM

Vercel是什么?本篇文章带大家了解一下Vercel,并介绍一下在Vercel中部署 Node 服务的方法,希望对大家有所帮助!

node.js gm是什么node.js gm是什么Jul 12, 2022 pm 06:28 PM

gm是基于node.js的图片处理插件,它封装了图片处理工具GraphicsMagick(GM)和ImageMagick(IM),可使用spawn的方式调用。gm插件不是node默认安装的,需执行“npm install gm -S”进行安装才可使用。

怎么使用pkg将Node.js项目打包为可执行文件?怎么使用pkg将Node.js项目打包为可执行文件?Jul 26, 2022 pm 07:33 PM

如何用pkg打包nodejs可执行文件?下面本篇文章给大家介绍一下使用pkg将Node.js项目打包为可执行文件的方法,希望对大家有所帮助!

一文解析package.json和package-lock.json一文解析package.json和package-lock.jsonSep 01, 2022 pm 08:02 PM

本篇文章带大家详解package.json和package-lock.json文件,希望对大家有所帮助!

分享一个Nodejs web框架:Fastify分享一个Nodejs web框架:FastifyAug 04, 2022 pm 09:23 PM

本篇文章给大家分享一个Nodejs web框架:Fastify,简单介绍一下Fastify支持的特性、Fastify支持的插件以及Fastify的使用方法,希望对大家有所帮助!

node爬取数据实例:聊聊怎么抓取小说章节node爬取数据实例:聊聊怎么抓取小说章节May 02, 2022 am 10:00 AM

node怎么爬取数据?下面本篇文章给大家分享一个node爬虫实例,聊聊利用node抓取小说章节的方法,希望对大家有所帮助!

手把手带你使用Node.js和adb开发一个手机备份小工具手把手带你使用Node.js和adb开发一个手机备份小工具Apr 14, 2022 pm 09:06 PM

本篇文章给大家分享一个Node实战,介绍一下使用Node.js和adb怎么开发一个手机备份小工具,希望对大家有所帮助!

图文详解node.js如何构建web服务器图文详解node.js如何构建web服务器Aug 08, 2022 am 10:27 AM

先介绍node.js的安装,再介绍使用node.js构建一个简单的web服务器,最后通过一个简单的示例,演示网页与服务器之间的数据交互的实现。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中