日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

webpack3的CommonsChunkPlugin插件详解

發(fā)布時(shí)間:2023/12/2 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 webpack3的CommonsChunkPlugin插件详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

webpack打出來(lái)的包在不做處理的情況下是非常大的,所有依賴都被塞進(jìn)一個(gè)文件中,文件中有業(yè)務(wù)代碼,有業(yè)務(wù)代碼依賴的第三方庫(kù)代碼,還有webpack生成的運(yùn)行時(shí)代碼等。這樣的一個(gè)文件不方便靜態(tài)資源緩存,并且初始化頁(yè)面的時(shí)候下載了所有的JS這是沒必要的,拖慢了頁(yè)面速度。所以對(duì)于webpack打包的資源文件進(jìn)行分割按需加載是很重要的一件事情。

webpack4都出來(lái)了為啥要寫一篇關(guān)于webpack3的文章。

目前webpack3應(yīng)用的還是很多,并且學(xué)習(xí)相關(guān)知識(shí)協(xié)查找過(guò)相關(guān)資料很多遍,所以這次總結(jié)一下通過(guò)webpack3分割代碼的方法,方便后期需要的時(shí)候方便查閱。

在webpack3中使用的分割thunk方法主要是使用webpack自帶的插件(webpack.optimize.CommonsChunkPlugin)實(shí)現(xiàn)的。

首先通過(guò)webpack來(lái)構(gòu)建項(xiàng)目

目錄結(jié)構(gòu):

|— src

? |— index.html

? |— indexa.js

? |— indexb.js

|— webpack.config.js

|— node_modules

? |— jquery/

indexa.js

import $ from 'jquery'$() // 調(diào)用一下console.log('我是indexa.js')

indexb.js

import $ from 'jquery'$() // 調(diào)用一下console.log('我是indexb.js')

webpack.config.js

// output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: {indexa: './src/indexa.js',indexb: './src/indexb.js'},output: {path: path.resolve('./dist/'),filename: '[name].[chunkHash].js'},plugins: [new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

上面的示例中有兩個(gè)入口,一個(gè)是pagea.js,另一個(gè)是pageb.js。這兩個(gè)入口都引入了jquery.js,并且打包結(jié)果中我們看到j(luò)query.js被同時(shí)打到了兩個(gè)入口文件中。

提取公共第三方庫(kù)jquery

這樣的結(jié)果顯然不是我們期望的,我們期望兩個(gè)入口都引入的jquery被打到單獨(dú)的包中,然后在兩個(gè)入口引入這個(gè)包即可。這就需要借助webpack.optimize.CommonsChunkPlugin插件,下面修改webpack.config.js文件為:

// output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin') let webpack = require('webpack') let CommonsChunkPlugin = webpack.optimize.CommonsChunkPluginmodule.exports = {entry: {indexa: './src/indexa.js',indexb: './src/indexb.js',jquery: ['jquery'] // 依賴的第三方庫(kù)node_modules中},output: {path: path.resolve('./dist/'),filename: '[name].[chunkHash].js'},plugins: [new CommonsChunkPlugin({name: 'jquery', // 如果有該名稱的chunk則選擇這個(gè)chunk提取公共文件,這里是jquery,如果沒有則生成的文件是這個(gè)名稱的chunk}),new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

通過(guò)CommonsChunkPlugin插件我們提取了在indexa和indexb中都引入的jquery庫(kù)這樣打包結(jié)果中pagea.js和pageb.js就大幅減小了。

提取自定義公共模塊

通常我們不止有第三方的公共模塊,我們自己也會(huì)寫一些公用的工具方法。現(xiàn)加入公用工具方法文件utils.js。

utils.js

function common () {console.log('我是工具方法') }export {common }

修改pagea.js文件

import $ from 'jquery' import {common} from './utils.js'common() // 新加的$() // 調(diào)用一下console.log('我是indexa.js')

修改pageb.js文件

import $ from 'jquery' import {common} from './utils.js'common() // 新加的$() // 調(diào)用一下console.log('我是indexb.js')

打包后發(fā)現(xiàn)自己的公共方法文件被打包到了jquery……js文件中了,我們并不希望這樣,因?yàn)榈谌綆?kù)一般是不會(huì)修改的,我們希望每次打包第三方庫(kù)的名稱不變,這樣有助于客戶端緩存。所以我們需要從當(dāng)前的jquery…js中提取出自己的公共方法文件。

分離utils.js文件和jquery等第三方庫(kù)文件

  • 修改webpack.config.js
  • // output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin') let webpack = require('webpack') let CommonsChunkPlugin = webpack.optimize.CommonsChunkPluginmodule.exports = {entry: {indexa: './src/indexa.js',indexb: './src/indexb.js',jquery: ['jquery'] // 依賴的第三方庫(kù)node_modules中},output: {path: path.resolve('./dist/'),filename: '[name].[chunkHash].js'},plugins: [new CommonsChunkPlugin({name: 'jquery', // 如果有該名稱的chunk則選擇這個(gè)chunk提取公共文件,這里是jquery,如果沒有則生成的文件是這個(gè)名稱的chunkminiChunks: Infinity // 這樣就只會(huì)打包出自身chunk和 webpack生成的一些文件}),new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

    通過(guò)打包結(jié)果發(fā)現(xiàn)我們自定義的模塊確實(shí)從jquery中提取了出來(lái),但是卻打到了每個(gè)引入的頁(yè)面中,這也是我們接受不了的。

  • 從單個(gè)頁(yè)面中分離公共方法
  • 修改webpack.config.js文件如下:

    // output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin') let webpack = require('webpack') let CommonsChunkPlugin = webpack.optimize.CommonsChunkPluginmodule.exports = {entry: {indexa: './src/indexa.js',indexb: './src/indexb.js',jquery: ['jquery'] // 依賴的第三方庫(kù)node_modules中},output: {path: path.resolve('./dist/'),filename: '[name].[chunkHash].js'},plugins: [new CommonsChunkPlugin({name: 'jquery', // 如果有該名稱的chunk則選擇這個(gè)chunk提取公共文件,這里是jquery,如果沒有則生成的文件是這個(gè)名稱的chunkminChunks: Infinity // 這樣就只會(huì)打包出自身chunk和 webpack生成的一些文件}),new CommonsChunkPlugin({name: 'utils',chunks: ['indexa', 'indexb']}),new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

    打包結(jié)果如下,可以發(fā)現(xiàn)utils被提取了出來(lái),這樣就我們的目的就達(dá)到了。

    minChunks的函數(shù)值

    我們發(fā)現(xiàn)第三方庫(kù)我們是通過(guò)entry字段手動(dòng)添加的,這樣比較麻煩,不能以后添加一個(gè)第三方庫(kù)我們就手動(dòng)修改一下entry的jquery數(shù)組。

    我們可以通過(guò)minChunks的值傳入一個(gè)函數(shù)來(lái)做,函數(shù)返回true則會(huì)被打包。修改webpack.config.js文件如下:

    // output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin') let webpack = require('webpack') let CommonsChunkPlugin = webpack.optimize.CommonsChunkPluginmodule.exports = {entry: {indexa: './src/indexa.js',indexb: './src/indexb.js',// 已經(jīng)不需要了 jquery: ['jquery'] // 依賴的第三方庫(kù)node_modules中},output: {path: path.resolve('./dist/'),filename: '[name].[chunkHash].js'},plugins: [new CommonsChunkPlugin({name: "vendor", // 修改jquery名稱為vendor,第三方庫(kù)集合minChunks: function (module, ) {// node_modules中出來(lái)的都打到這個(gè)文件中return module.context && module.context.includes("node_modules");}}),new CommonsChunkPlugin({name: 'utils',chunks: ['indexa', 'indexb']}),new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

    打包結(jié)果如下,只是將jquery…js的名稱換成了vendor…js其他沒有任何變化。

    讓moduleId固定下來(lái)

    通過(guò)上面兩張截圖的觀察我們可以發(fā)現(xiàn)indexb…js的chunkHash不一樣了,但是我們并沒有修改文件內(nèi)容。這是因?yàn)閣ebpack生成模塊的moduleId在變化。讓moduleId停止變化的插件有兩個(gè),一個(gè)是HashedModuleIdsPlugin,還有一個(gè)是NamedModulesPlugin。

    HashedModuleIdsPlugin: 該插件會(huì)根據(jù)模塊的相對(duì)路徑生成一個(gè)四位數(shù)的hash作為模塊id, 建議用于生產(chǎn)環(huán)境。

    NamedModulesPlugin: 當(dāng)開啟 HMR 的時(shí)候使用該插件會(huì)顯示模塊的相對(duì)路徑,建議用于開發(fā)環(huán)境。

    我們就選擇生產(chǎn)環(huán)境用的插件,修改webpack.config.js文件如下:

    // output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin') let webpack = require('webpack') let CommonsChunkPlugin = webpack.optimize.CommonsChunkPluginmodule.exports = {entry: {indexa: './src/indexa.js',indexb: './src/indexb.js',// 已經(jīng)不需要了 jquery: ['jquery'] // 依賴的第三方庫(kù)node_modules中},output: {path: path.resolve('./dist/'),filename: '[name].[chunkHash].js'},plugins: [new CommonsChunkPlugin({name: "vendor", // 修改jquery名稱為vendor,第三方庫(kù)集合minChunks: function (module) {// node_modules中出來(lái)的都打到這個(gè)文件中return module.context && module.context.includes("node_modules");}}),new CommonsChunkPlugin({name: 'utils',chunks: ['indexa', 'indexb']}),// 固定下來(lái)模塊的moduleIdnew HashedModuleIdsPlugin(),new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

    runtime和manifest

    其實(shí)vender中不止有node_module文件夾中的包,還包括

    runtime: 指在瀏覽器運(yùn)行時(shí),webpack 用來(lái)連接模塊化的應(yīng)用程序的所有代碼。其中包含:在模塊交互時(shí),連接模塊所需的加載和解析邏輯。包括瀏覽器中的已加載模塊的連接,以及懶加載模塊的執(zhí)行邏輯。

    manifest: 當(dāng)編譯器(compiler)開始執(zhí)行、解析和映射應(yīng)用程序時(shí),它會(huì)保留所有模塊的詳細(xì)要點(diǎn)。這個(gè)數(shù)據(jù)集合稱為 “Manifest”,當(dāng)完成打包并發(fā)送到瀏覽器時(shí),會(huì)在運(yùn)行時(shí)通過(guò) Manifest 來(lái)解析和加載模塊。無(wú)論你選擇哪種模塊語(yǔ)法,那些 import 或 require 語(yǔ)句現(xiàn)在都已經(jīng)轉(zhuǎn)換為 __webpack_require__ 方法,此方法指向模塊標(biāo)識(shí)符(module identifier)。通過(guò)使用 manifest 中的數(shù)據(jù),runtime 將能夠查詢模塊標(biāo)識(shí)符,檢索出背后對(duì)應(yīng)的模塊。

    當(dāng)模塊做出改變的時(shí)候manifest也會(huì)改變,同時(shí)也會(huì)導(dǎo)致vender改變,最后導(dǎo)致vender的緩存失效,這種失效并不是因?yàn)関ender本身內(nèi)容的改變導(dǎo)致的,所以我們需要分離runtime和manifest。

    提取runtime和manifest

    修改webpack.config.js文件如下:

    // output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin') let webpack = require('webpack') let CommonsChunkPlugin = webpack.optimize.CommonsChunkPluginmodule.exports = {entry: {indexa: './src/indexa.js',indexb: './src/indexb.js'},output: {path: path.resolve('./'),filename: '[name].[chunkHash].js'},plugins: [new CommonsChunkPlugin({name: "vendor", // 修改jquery名稱為vendor,第三方庫(kù)集合minChunks: function (module) {// node_modules中出來(lái)的都打到這個(gè)文件中return module.context && module.context.includes("node_modules");}}),new CommonsChunkPlugin({name: 'utils',chunks: ['indexa', 'indexb']}),new CommonsChunkPlugin({name: 'manifest',minChunks: Infinity}),// 固定下來(lái)模塊的moduleIdnew HashedModuleIdsPlugin(),new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

    children字段和async字段的作用

    children和async作用于動(dòng)態(tài)加載模塊。如果沒有設(shè)置children,那么在動(dòng)態(tài)引入的多個(gè)腳本中公用的部分并不會(huì)被提取出來(lái)。如果設(shè)置了childrend: true,則公共部分會(huì)被提取到主腳本中。進(jìn)一步設(shè)置async字段,那么提取出來(lái)的公共部分不會(huì)在主腳本中,而會(huì)生成一個(gè)單獨(dú)文件異步引入。

    如果動(dòng)態(tài)引入腳本和主腳本有公共的部分,那么及時(shí)沒有設(shè)置children和async字段也會(huì)被提取。

    為了去除上面的干擾重建目錄。

    |— src|— index.html|— index.js|— child1.js|— child2.js|— webpack.config.js|— node_modules|— jquery/

    index.js

    改文件為主腳本,會(huì)動(dòng)態(tài)引入兩個(gè)腳本child1.js和child2.js

    require.ensure(['./child1.js'], function () { })require.ensure(['./child2.js'], function () { })

    child1.js

    import $ from 'jquery' import {common} from './utils.js'$() common()console.log('我是child1.js')

    child2.js(和child1.js內(nèi)容相同)

    import $ from 'jquery' import {common} from './utils.js'$() common()console.log('我是child2.js')

    webpack.config.js

    先正常打包,觀察結(jié)果。

    // output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: {index: './src/index.js'},output: {path: path.resolve('./'),filename: '[name].[chunkHash].js',chunkFilename: '[name].[chunkHash].js'},plugins: [new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

    下圖我們可以看出除了index.js還多了兩個(gè)js,這兩個(gè)就是通過(guò)動(dòng)態(tài)加載引入的js被單獨(dú)打包了,并且這兩個(gè)js中公共的部分并沒有被提取。還可以注意到這時(shí)候index.js是很小的。

    提取異步加載的js中公共部分

    // output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin') let CommonsChunkPlugin = webpack.optimize.CommonsChunkPluginmodule.exports = {entry: {index: './src/index.js'},output: {path: path.resolve('./'),filename: '[name].[chunkHash].js',chunkFilename: '[name].[chunkHash].js'},plugins: [new CommonsChunkPlugin({children: true}),new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

    添加children選項(xiàng)之后:

    動(dòng)態(tài)引入進(jìn)來(lái)的文件的公共部分被提取到主塊中了。兩個(gè)動(dòng)態(tài)引入文件的尺寸減小并且主腳本的尺寸變大了。

    將動(dòng)態(tài)引入的部分單獨(dú)打包

    // output中的path需要絕對(duì)路徑 let path = require('path') // 用于將打包的js文件注入到html文件中 let HtmlWebpackPlugin = require('html-webpack-plugin') let CommonsChunkPlugin = webpack.optimize.CommonsChunkPluginmodule.exports = {entry: {index: './src/index.js'},output: {path: path.resolve('./'),filename: '[name].[chunkHash].js',chunkFilename: '[name].[chunkHash].js'},plugins: [new CommonsChunkPlugin({children: true,async: true}),new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html'})] }

    我們可以看到index.js文件又減小了并且多了一個(gè)文件。

    以上就是我理解的CommonsChunkPlugin插件中children和async的用法。

    關(guān)于自定義動(dòng)態(tài)引入腳本打包的名字可參考webpack中實(shí)現(xiàn)按需加載

    注:

    hash:一個(gè)隨機(jī)值,每次打包都會(huì)改變,建議用于開發(fā)。

    chunkHash: 根據(jù)文件內(nèi)容生成一個(gè)隨機(jī)值,建議用于生產(chǎn)便于緩存。

    Infinity:創(chuàng)建一個(gè)公共chunk,但是不包含任何模塊,內(nèi)部是一些webpack生成的runtime代碼和chunk自身包含的模塊(如果chunk存在的話)。

    多CommonsChunkPlugin:第二次使用CommonsChunkPlugin插件的時(shí)候如果不指定chunks默認(rèn)針對(duì)前一個(gè)CommonsChunkPlugin插件生成的chunk做提取。

    children部分主腳本:引入異步腳本的腳本。

    總結(jié):

  • node_modules中第三方庫(kù)的提取可以通過(guò)miniChunks傳入function來(lái)控制。
  • 分離之后chunkHash還會(huì)變是應(yīng)為moduleId在改變可以使用插件HashedModuleIdsPlugin來(lái)固定下來(lái)
  • manifest和runtime文件提取可以通過(guò)miniChunks: Infinity 來(lái)完成
  • children字段設(shè)置為true,提取異步引入子文件的公共部分到主文件中
  • async字段配合children字段使用,提取異步引入子文件的公共部分到單獨(dú)文件中
  • 參考

    webpack4:連奏中的進(jìn)化

    Webpack4之SplitChunksPlugin規(guī)則

    詳解CommonsChunkPlugin的配置和用法

    CommonsChunkPlugin中children和async屬性詳解

    Webpack2中的NamedModulesPlugin與HashedModuleIdsPlugin

    runtime和manifest

    hashed-module-ids-plugin

    NamedModulesPlugin

    webpack中ensure方法和CommonsChunkPlugin中的children選項(xiàng)

    總結(jié)

    以上是生活随笔為你收集整理的webpack3的CommonsChunkPlugin插件详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。