這篇文章主要介紹了Webpack的Bundle Split和Code Split有哪些區(qū)別,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。
雙峰網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)建站,雙峰網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為雙峰數(shù)千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的雙峰做網(wǎng)站的公司定做!
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)打包的效果:
全部依賴都被打包到 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
中的依賴全部打包分離出來,這個時候我們再看打包的文件是個什么樣子:
增加了 splitChunks 的配置,我們第三方模塊都被打包到了 vendors~main.xxx.js 中去了,這個文件大小有 604k,而入口文件 main.xxx.js 則只有 7k
雖然說這樣將第三方模塊單獨(dú)打包出去能夠減小入口文件的大小,但這樣仍然是個不小的文件;這個小的測試項(xiàng)目中我們使用到了 axios 和 lodash 這兩個第三方模塊,因此我們希望的應(yīng)該是將這兩個模塊單獨(dú)分離出來兩個文件,而不是全部放到一個 vendors 中去,那么我們繼續(xù)配置 webpack.config.js:
這里我們需要使用到 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 的操作基本就完成了,讓我們看看效果如何:
所依賴的幾個模塊都被分離出去了
使用 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 面板:
可以看到我們將模塊單獨(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)試面板刷新瀏覽器:
在頁面剛加載完畢后,瀏覽器會嘗試獲取上述這么幾個模塊,因?yàn)槟K都很小很快就加載完成了
在 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)容對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,遇到問題就找創(chuàng)新互聯(lián),詳細(xì)的解決方法等著你來學(xué)習(xí)!