webpack4 optimization配置splitChunks和namedChunks

添加分析工具

想要實時查看打包變化,能夠經過一個打包分析利器。webpack-bundle-analyzer
安裝javascript

npm i webpack-bundle-analyzer --save-dev
複製代碼

package.json裏面添加命令vue

"analyz": "NODE_ENV=production npm_config_report=true npm run build"
複製代碼

webpack配置java

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [new BundleAnalyzerPlugin()],
複製代碼

執行node

npm npm run analyz
複製代碼

工具配置好以後webpack

首先看下webpack的默認打包配置web

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 30000,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      automaticNameDelimiter: '~',
      name: true,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  }
};
複製代碼

解析下參數npm

  1. chunk: 含義是拆分模塊的範圍,它有三個值async、initial和all。

async表示只從異步加載得模塊(動態加載import())裏面進行拆分 initial表示只從入口模塊進行拆分 all表示以上二者都包括json

  1. minSize:最小拆分組件大小
  2. minChunks:最小引用次數
  3. maxAsyncRequests:限制異步模塊內部的並行最大請求數的
  4. maxInitialRequests:容許入口並行加載的最大請求數
  5. automaticNameDelimiter:文件名的鏈接符
  6. name: split 的 chunks name
  7. cacheGroups:緩存組

默認爲vendors和default。能夠設置權重值priority。緩存

vendor通常放置node_modules裏面的文件, default放置公共組件異步

增長模塊標識

咱們須要加添加幾個文件進行測試
可是如今個問題
假如我先創建一個btest文件,再創建一個atest文件,進行打包後,發現btest的文件的hash也會發生變化。
這是由於,webpack在創建依賴的時候的文件是按照ascall碼進行排序的,而後新插入的文件就會發生變化。
解決辦法,
給模塊的名字加上標識。這樣在打包的時候就會按照標識進行。 配置以下

optimization: {
            namedChunks:true, //增長模塊標識
            splitChunks: {
                // 配置
            }
        },
plugins: [
     new webpack.HashedModuleIdsPlugin(), //模塊增長標識,開發環境建議用 NamedModulePlugin
],
複製代碼

再進行打包,發現問題解決,再回到咱們的打包方案分析。

打包分析

如今打包有幾種方案
1. node—modules和公共組件(好比loading)引用超過兩次以上都會打包到base文件。

webpack配置以下

optimization: {
            splitChunks: {
                cacheGroups: {
                    base:{
                        chunks: 'initial', //initial表示提取入口文件的公共部分
                        minChunks: 2, //表示提取公共部分最少的文件數
                        minSize: 0, //表示提取公共部分最小的大小
                        name: 'base' //提取出來的文件命名
                    }
                }
            }
        },
複製代碼

打包分析結果以下

如今咱們在atest裏面引入loading組件

<template>
  <div>
    atest
  </div>
</template>
<script>
import Loading from '../components/loading/loading' //引入Loading組件
export default {

}
</script>
複製代碼

再次打包

和咱們想的同樣,只有atest發生變化 而後在btest裏面再引入loading
再次打包

發現 atest btest base 都發生了變化。
由於loading被引入超過了兩次,loading先從atest抽離,atset發生變化。base加入loading組件發生變化。 可是這就是隱患之一,可是咱們能夠把minChunks設置爲1,這樣的話,全部被引用的組件都會被base.js裏面去的。
可是若是base文件太大的話,緩存的代價太大了,因此咱們換一個策略

2. 分離式打包,node_modules會單獨打包,每一個引入的組件會打包到一個文件中。 webpack配置以下

optimization: {
            namedChunks:true,
            splitChunks: {
                chunks: 'all',
                minSize: 0,
                minChunks: 1,
                maxAsyncRequests: 10,
                maxInitialRequests: 10,
                // automaticNameDelimiter: '~',
                name: true,
                cacheGroups: {
                  vendors: {
                    minChunks: 1,
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10 // 權重
                  },
                  default: {
                    minChunks: 1,
                    priority: -20, // 權重
                    reuseExistingChunk: true
                  }
                }
              }
        },
複製代碼

設置兩個緩存組:其中vendors是放node_modules打包後的文件
老樣子,添加atest文件和btest文件
打包分析

vendor放置的就是node_moldules裏面的vue相關文件
如今咱們在atest裏面引入loading組件 ,而後在btest文件頁引入loading組件 打包分析

其中的atest~btest就是分離出來的loading組件,可是這個配置是存在一個問題的?能夠看到我在default裏面將minChunks的值改爲1,表明是當組件被引用超過一次就會打包出來,咱們看下,只有atest引入loading引入的時候的狀況 只有atest引入

<div>
    atest
  </div>
</template>
<script>
import myCom from '../components/testCom/testCom'
export default {
    
}
</script>
複製代碼

打包分析

能夠看到引入的testCom組件並無被單獨打包出來。可是咱們設置了minChunks:1,按理說testCom組件應該被分出來,可是結果並無,如今猜測是可能只知足了被引用一次,可是沒有知足其餘條件,或者是由於key設置爲了default的緣由。這個等以後再作研究,
咱們如今先替換掉default,換回咱們的base

vendors: {
        minChunks: 1,
        test: /[\\/]node_modules[\\/]/,
        priority: -10, // 權重
        minSize: 0,
    },
    base: {
        priority: -20, // 權重
        chunks: 'initial', //initial表示提取入口文件的公共部分
        minChunks: 1, //表示提取公共部分最少的文件數
        minSize: 0, //表示提取公共部分最小的大小
        name: '
    }
複製代碼

來看下打包結果

node_modules引用打包到了vendors,公共組件打包到base裏面,一切都如此美好,這個也能知足開發需求。
下面咱們來研究一個新的東西
3. 所有打散式打包,node_modules會打成包,每一個組件本身單獨打包。
如今咱們已經實現了分離打包,公共組件,好比loading都打進了base文件,可是若是咱們想把loading單獨打包出來,造成loading.js,或者咱們再引入一個toast組件,也要打包成toast.js文件,這個怎麼進行操做?也有辦法!

先上代碼

vendors: {
        name:'vendors',
        minChunks: 1,
        test: /[\\/]node_modules[\\/]/,
        priority: -10, // 權重
        minSize: 0,
    },
    default:{
        test:/[\\/]components[\\/]|[\\/]common[\\/]/,
        priority:-20, // 權重
        name(module){
            // console.log('模塊分析打印')
            // console.log(module.identifier())
            const moduleFileName = module
            .identifier()
            .split('/')
            .pop()
            .replace('.js','')
            return `${moduleFileName}`
        }
    },
複製代碼

其中的components是我存放公共組件的地方,common是存放公共js方法的地方。我只須要篩選他們下面的引入
打包結果以下

能夠看出atest裏面引入的testCom被打包出來成了一個公共組件
如今再引入一個公共方法

<template>
  <div>
    atest
  </div>
</template>
<script>
import myCom from '../components/testCom/testCom'
import '../common/widget/common'
export default {

}
</script>
複製代碼

在看打包結果

能夠看出testCom單獨打包,並且commmon也單獨打包了,ok!解決 !

這樣比較上面方式的好處是,上面那種方法,當你只改變一個組件的內容時候,會引發整個base的變化。這個弊端會隨着base文件的愈來愈大而愈來愈️明顯

代碼

最後放一下三種方案的代碼
1. node—modules和公共組件(好比loading)引用超過兩次以上都會打包到base文件。

optimization: {
            namedChunks: true,
            splitChunks: {
                chunks: 'all',
                minSize: 0,
                minChunks: 1,
                maxAsyncRequests: 100,
                maxInitialRequests: 100,
                automaticNameDelimiter: '~',
                name: true,
                cacheGroups: { 
                    base: {
                        minChunks: 1, //表示提取公共部分最少的文件數
                        minSize: 0, //表示提取公共部分最小的大小
                        name: 'base' //提取出來的文件命名
                    }
                }
    }
複製代碼

2. 分離式打包,node_modules會單獨打包,每一個引入的組件也會單獨打包。

optimization: {
            namedChunks: true,
            splitChunks: {
                chunks: 'all',
                minSize: 0,
                minChunks: 1,
                maxAsyncRequests: 100,
                maxInitialRequests: 100,
                automaticNameDelimiter: '~',
                name: true,
                cacheGroups: { 
                     vendors: {
                        minChunks: 1,
                        test: /[\\/]node_modules[\\/]/,
                        priority: -10, // 權重
                        minSize: 0,
                    },
                    base: {
                        priority: -20, // 權重
                        chunks: 'initial', //initial表示提取入口文件的公共部分
                        minChunks: 1, //表示提取公共部分最少的文件數
                        minSize: 0, //表示提取公共部分最小的大小
                        name: 'base' //提取出來的文件命名
                    }
                }
    }
複製代碼

3. 所有打散式打包,node_modules會打成包,每一個組件本身單獨打包。

optimization: {
            namedChunks: true,
            splitChunks: {
                chunks: 'all',
                minSize: 0,
                minChunks: 1,
                maxAsyncRequests: 100,
                maxInitialRequests: 100,
                automaticNameDelimiter: '~',
                name: true,
                cacheGroups: { 
                       vendors: {
                        name:'vendors',
                        minChunks: 1,
                        test: /[\\/]node_modules[\\/]/,
                        priority: -10, // 權重
                        minSize: 0,
                    },
                    default:{
                        test:/[\\/]components[\\/]|[\\/]common[\\/]/,
                        priority:-20, // 權重
                        name(module){
                            // console.log('模塊分析打印')
                            // console.log(module.identifier())
                            const moduleFileName = module
                            .identifier()
                            .split('/')
                            .pop()
                            .replace('.js','')
                            return `${moduleFileName}`
                        }
                    }
                }
    }
複製代碼
相關文章
相關標籤/搜索