溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Webpack的Bundle Split和Code Split有哪些區(qū)別

發(fā)布時間:2020-09-15 10:06:52 來源:億速云 閱讀:178 作者:小新 欄目:web開發(fā)

這篇文章主要介紹了Webpack的Bundle Split和Code Split有哪些區(qū)別,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。




Webpack 文件分離包括兩個部分,一個是 Bundle 的分離,一個是 Code 代碼的分離:

  • Bundle splitting: 實(shí)際上就是創(chuàng)建多個更小的文件,并行加載,以獲得更好的緩存效果;主要的作用就是使瀏覽器并行下載,提高下載速度。并且運(yùn)用瀏覽器緩存,只有代碼被修改,文件名中的哈希值改變了才會去再次加載。

  • Code splitting: 只加載用戶最需要的部分,其余的代碼都遵從懶加載的策略;主要的作用就是加快頁面加載速度,不加載不必要加載的東西。

準(zhǔn)備工作

在進(jìn)行文件分離之前的準(zhǔn)備工作,我們先寫一些代碼:

入口文件 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 操作之前,我們先看一下當(dāng)前默認(rèn)打包的效果:

Webpack的Bundle Split和Code Split有哪些區(qū)別

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

開始分離操作

Bundle Split

Bundle Split 的主要任務(wù)是將多個引用的包和模塊進(jìn)行分離,避免全部依賴打包到一個文件下

基本用法

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有哪些區(qū)別

增加了 splitChunks 的配置,我們第三方模塊都被打包到了 vendors~main.xxx.js 中去了,這個文件大小有 604k,而入口文件 main.xxx.js 則只有 7k

雖然說這樣將第三方模塊單獨(dú)打包出去能夠減小入口文件的大小,但這樣仍然是個不小的文件;這個小的測試項(xiàng)目中我們使用到了 axios 和 lodash 這兩個第三方模塊,因此我們希望的應(yīng)該是將這兩個模塊單獨(dú)分離出來兩個文件,而不是全部放到一個 vendors 中去,那么我們繼續(xù)配置 webpack.config.js:

將每個 npm 包單獨(dú)分離出來

這里我們需要使用到 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() // 根據(jù)模塊的相對路徑生成 HASH 作為模塊 ID
    ],
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash].js'
    },
    optimization: {
        runtimeChunk: 'single',
        splitChunks: {
            chunks: 'all', // 默認(rèn) async 可選值 all 和 initial
            maxInitialRequests: Infinity, // 一個入口最大的并行請求數(shù)
            minSize: 0, // 避免模塊體積過小而被忽略
            minChunks: 1, // 默認(rèn)也是一表示最小引用次數(shù)
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/, // 如果需要的依賴特別小,可以直接設(shè)置成需要打包的依賴名稱
                    name(module, chunks, chcheGroupKey) { // 可提供布爾值、字符串和函數(shù),如果是函數(shù),可編寫自定義返回值
                        const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1] // 獲取模塊名稱
                        return `npm.${packageName.replace('@', '')}` // 可選,一般情況下不需要將模塊名稱 @ 符號去除
                    }
                }
            }
        }
    }
}

這里我們主要做了幾件事:

為了避免每次打包的文件哈希變化,我們可以使用 webpack 內(nèi)置的 HashedModuleIdsPlugin,這樣可以避免每次打包的文件哈希值變化

首先增加 maxInitialRequests 并設(shè)置成 Infinity,指定這個入口文件最大并行請求數(shù)

然后將 minSize 和 minChunks 分別設(shè)置成 0 和 1,即使模塊非常小也將其提取出來,并且這個模塊的引用次數(shù)只有 1 也要提取

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

另外,我們還將運(yùn)行時代碼分離出來,這塊代碼還可以配合 InlineManifestWebpackPlugin 直接插入到 HTML 文件中。這里我們將這個配置設(shè)置成 single,即將所有chunk的運(yùn)行代碼打包到一個文件中

這樣 Bundle Split 的操作基本就完成了,讓我們看看效果如何:

Webpack的Bundle Split和Code Split有哪些區(qū)別

所依賴的幾個模塊都被分離出去了

使用 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() // 根據(jù)模塊的相對路徑生成 HASH 作為模塊 ID
    ],
    // ...
}

安裝 http-server 或使用 vscode 的插件 Live Server 將代碼放入一個本地服務(wù)器中,打開瀏覽器的調(diào)試窗口進(jìn)入到 Network 面板:

Webpack的Bundle Split和Code Split有哪些區(qū)別

可以看到我們將模塊單獨(dú)分離出來并行加載,這樣比單獨(dú)加載一個龐大的包要快不少,接下來我們還要進(jìn)行代碼分離,將不必要加載的模塊延遲加載

Code Split

代碼分離實(shí)際上就是只加載用戶需要使用到的部分代碼,不是必須的就暫時不加載。

這里我們要用到 require.ensure 這個方法去獲取依賴,這樣 webpack 打包之后將會增加運(yùn)行時代碼,在設(shè)定好的條件下才會觸發(fā)獲取這個依賴。

在 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)
我們設(shè)定了一個定時器,只有在 3000 毫秒以后,瀏覽器才會去請求這個 math 模塊

編譯之后,打開調(diào)試面板刷新瀏覽器:

Webpack的Bundle Split和Code Split有哪些區(qū)別

在頁面剛加載完畢后,瀏覽器會嘗試獲取上述這么幾個模塊,因?yàn)槟K都很小很快就加載完成了

Webpack的Bundle Split和Code Split有哪些區(qū)別

在 3500ms 左右,瀏覽器才會去獲取 requie.ensure 方法定義的 math 模塊,因 math 模塊又包含依賴 lodash,因此這個 lodash 第三方模塊也會被按需加載。

這樣我們就完成了代碼分離的操作,這樣做的優(yōu)勢就是不需要第一時間加載的模塊,可以推遲加載,以頁面的加載速度。當(dāng)然,上面的 timeout 定時器完全可以換成其他諸如按鈕點(diǎn)擊之類的事件來觸發(fā)。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享Webpack的Bundle Split和Code Split有哪些區(qū)別內(nèi)容對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,遇到問題就找億速云,詳細(xì)的解決方法等著你來學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI