webpack5 優(yōu)化產(chǎn)出代碼

webpack產(chǎn)出代碼做性能優(yōu)化的效果無非是下面三種效果:

  • 體積更小
  • 合理分包,不重復(fù)加載
  • 速度更快、內(nèi)存使用更少

下面將通過介紹以下方案來達(dá)到以上目的:

  1. 小圖片使用base64編碼:url-loader
  2. bundlehash:應(yīng)用緩存
  3. 使用import懶加載模塊
  4. 使用splitChunks提取公共組件
  5. 使用IgnorePlugin忽略無用的模塊
  6. 使用CDN加速:添加publicPath
  7. 使用production模式:
    • 自動(dòng)開啟代碼壓縮,使得打包體積更小
    • Vue,React等會(huì)自動(dòng)刪除調(diào)試代碼(比如開發(fā)環(huán)境的warning警告),體積會(huì)比開發(fā)時(shí)更小
    • 啟動(dòng)tree-shaking,刪除無用的代碼
  8. 使用作用域提升:Scope Hosting

其實(shí)里面很多方案,我們?cè)诨A(chǔ)配置和高級(jí)配置時(shí)已經(jīng)提及過:

小圖片base64編碼

通過設(shè)置url-loader的閥值來控制,小于閥值的圖片使用base64編碼,以此來減少http請(qǐng)求

  module: {
    noParse: /jquery|lodash/,
    rules: [
      {
        test: /\.(jpg|png|jpeg|gif)$/,
        use: {
          loader:'url-loader',
          options: {
            limit: 8 * 1024,    //限制 8kb 以下使用base64
            esMoudle: false,
            name: '[name]-[hash:10].[ext]',
            // 打包到/images目錄下
            outputPath: 'images'
          }
        }
      }
    ]
  },

bundle 加 hash 值

給產(chǎn)出的文件增加hash值,當(dāng)內(nèi)容沒有變化時(shí),生成的文件名將不會(huì)變化,瀏覽器就會(huì)應(yīng)用緩存,從而提升加載速度

  output: {
    filename: '[name].[contenthash:8].js',
    path: distPath  // 輸出目錄
  },

懶加載

使用import方式懶加載組件

// index.js
setTimeout(() => {
  // 直接使用import導(dǎo)入即可,這樣加載的模塊,相當(dāng)于一個(gè)獨(dú)立的chunk存在
  import('./common/dynamicData.js').then(res => {
    console.log(res.default.msg);
  })
}, 1000)

提取公共代碼

optimization中配置splitChunks屬性,設(shè)置cacheGroups分組,一般分為兩個(gè)組:verdors(用于提取第三方庫)和common(用于提取自定義的公共模塊)
針對(duì)第三方庫,幾乎不會(huì)改變,提取出來后,改動(dòng)業(yè)務(wù)代碼不會(huì)動(dòng)到第三方庫的打包文件,這樣,就能命中緩存,加快加載速度
針對(duì)公共模塊,只用加載一次,就可以在多個(gè)模塊中使用

// webpack.prod.js
  optimization: {
    splitChunks: {
      chunks: 'all', // 表示要分割的chunk類型:initial只處理同步的; async只處理異步的;all都處理
      // 緩存分組
      cacheGroups: {
        // 第三方模塊
        verdors: {
          name: 'verdor', // chunk名稱
          test: /node_modules/,  // 設(shè)置命中目錄規(guī)則
          priority: 1, // 優(yōu)先級(jí),數(shù)值越大,優(yōu)先級(jí)越高
          minSize: 0, // 小于這個(gè)大小的文件,不分割
          minChunks: 1 // 最少復(fù)用幾次,這里意思是只要用過一次就分割出來
        },
        // 公共模塊
        common: {
          name: 'common',
          minChunks: 2,
          priority: 0,
          minSize: 0,
          minChunks: 2  // 只要引用過2次,就分割成公共代碼
        }
      }
    }
  }

IgnorePlugin

IgnorePlugin可以幫助我們忽略某些庫不需要的模塊,從而實(shí)現(xiàn)按需加載,減少打包體積

// webpack.prod.js或webpack.common.js都可以
const webpack = require('webpack')
const prodConfig = {
  plugins: [
    // webpack4寫法
    // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)

    // webpack5寫法
    new webpack.IgnorePlugin({
      resourceRegExp: /^\.\/locale$/,   // 忽略content設(shè)置的庫中的某個(gè)文件夾
      contextRegExp: /moment$/, // 要被忽略某部分內(nèi)容的庫
    })
  ]
}

使用 CDN 加速

在輸出文件配置中將CDN路徑添加至publicPath中(針對(duì)js和css文件);
針對(duì)圖片,也可以在loader的配置中添加publicPath

  output: {
    // filename: 'bundle.[chunkhash].js',  // 輸出文件名,一般要加上hash
    filename: '[name].[contenthash:8].js',
    path: distPath,  // 輸出目錄
    publicPath: 'http://cdn.xxx.com'
  },

// 或者是將圖片放到cdn中
module: { 
  rules: [
    {
        test: /\.(jpg|png|jpeg|gif)$/,
        use: {
          loader:'url-loader',
          options: {
            limit: 8 * 1024,    //限制 8kb 以下使用base64
            esMoudle: false,
            name: '[name]-[hash:10].[ext]',
            // 打包到/images目錄下
            // outputPath: 'images', // 有了publicPath,會(huì)自動(dòng)忽略outputPath,這是針對(duì)放在靜態(tài)資源服務(wù)器上的目錄
            publicPath: 'http://cdn.xxx.com'
          }
        }
      }
  ]
}

這樣打包出來的index.html中的 靜態(tài)資源,會(huì)自動(dòng)添加CND地址前綴

<script defer="defer" src="http://cdn.xxx.com/verdor.03535a89.js"></script>
<script defer="defer" src="http://cdn.xxx.com/index.c6d170da.js"></script>
圖片放至cdn服務(wù)器

這一步還需要我們將對(duì)應(yīng)的資源文件給放至對(duì)應(yīng)的CND服務(wù)器地址中

啟用production模式

mode: 'production', // 生產(chǎn)環(huán)境

啟用production模式,會(huì)使打包的體積更小,webpack4以后,只要開啟生產(chǎn)模式,就會(huì)自己幫我們實(shí)現(xiàn)以下功能:

  1. 自動(dòng)開啟代碼壓縮,比如刪除注釋、空格等,當(dāng)然可以視項(xiàng)目情況,來判斷要不要使用webpack-parallel-uglify-plugin開啟多進(jìn)程壓縮
  2. Vue,React等會(huì)自動(dòng)刪除調(diào)試代碼(比如開發(fā)環(huán)境的warning警告),體積會(huì)比開發(fā)時(shí)更小
  3. 啟用tree-shaking,刪除無用的代碼,當(dāng)注意,只有在ES Module才可以使用
    • ·ES6 Module是靜態(tài)引入,編譯時(shí)時(shí)就引入模塊的,所以才可以做靜態(tài)分析,實(shí)現(xiàn)tree-shaking
    • Commonjs是動(dòng)態(tài)引入的,是執(zhí)行時(shí)才引入,需要執(zhí)行代碼時(shí),才知道引不引入,所以沒法做靜態(tài)分析,也就無法實(shí)現(xiàn)tree-shaking

Scope Hosting

webpack分析依賴打包出來的文件,一般是一個(gè)模塊生成一個(gè)函數(shù),比如:

// test.js
export default 'module test'
// index.js
import test from './module-test'
console.log(test)

打包后大概是這樣的:

[
  function (module, exports, require) {
    var module_test = require(1)
    console.log(module_test['default'])
  },
  function (module, exports, require) {
    exports['default'] = 'module test'
  }
]

這樣,當(dāng)我們引用的模塊很多時(shí),我們打包時(shí)就會(huì)產(chǎn)生很多個(gè)函數(shù),一個(gè)函數(shù)會(huì)生成一個(gè)函數(shù)作用域,當(dāng)多個(gè)模塊時(shí),就會(huì)產(chǎn)生多個(gè)函數(shù)作用域,這樣步驟創(chuàng)建函數(shù)作用域和執(zhí)行函數(shù)、銷毀函數(shù),對(duì)js代碼的執(zhí)行和內(nèi)存是很不友好的

但如果我們按引用順序,把它們合成一個(gè)函數(shù)來執(zhí)行,所有操作都在一個(gè)函數(shù)執(zhí)行,那么性能就會(huì)好很多,比如

// bundle.js
[
  function (module, exports, require) {
    // ./module-a.js
    var module_test_defaultExport = 'module test'

    // ./index.js
    console.log(module_test_defaultExport)
  }
]

它帶來的好處有:

  • 減小代碼體積
  • 創(chuàng)建的函數(shù)作用域更少
  • 代碼可讀性會(huì)更好

但是,Scope Hosting的實(shí)現(xiàn)也是有限制的,它必須是在ES Module環(huán)境下使用

知道了原理,我們來看下Scope Hosting如何配置,它是webpack內(nèi)置的一個(gè)模塊,可以直接使用:

const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin')
  resolve: {
    // 針對(duì)npm中的第三方庫模塊,優(yōu)先采用jsnext:main中指向ES6模塊化語法的文件
    mainFields: ['jsnext:main', 'browser', 'main']
  },
  plugins: [
    // 開啟scope hoisting,作用域提升
    new ModuleConcatenationPlugin()
  ]
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容