Webpack實戰(九):實現資源按需加載-資源異步加載

第八篇[《教你搞懂webpack如果實現代碼分片(code splitting)》] (https://blog.csdn.net/lfcss/article/details/104099412) 主要分享了webpack實現代碼分片 的幾種方式:合理地規劃入口,使用Commons-ChunkPlugin或SplitChunks配置。這幾種方法實現了資源按需加載。今天我分享另外一種實現方法–資源異步加載。

資源異步加載主要解決的問題是,當模塊數量過多、資源體積過大時,可以把一些暫時使用不到的模塊延遲加載。這樣使頁面初次渲染的時候用戶下載的資源儘可能小,後續的模塊等到恰當的時機再去觸發加載。

webpack資源異步加載的方法

在webpack中主要提供兩種方法:import函數和require.ensure。在webpack4之前,webpack 在編譯時,會靜態地解析代碼中的 require.ensure(),同時將模塊添加到一個分開的 chunk 當中。這個新的 chunk 會被 webpack 通過 jsonp 來按需加載。今天主要webpack4以後的import加載。

Webpack中的import

與正常ES6中的import語法不同,通過import函數加載的模塊及其依賴會被異步地進行加載,並返回一個Promise對象。
一般正常的模塊加載代碼如下:

// index.js
import { add } from  './index2.js';
console.log(add(2,3));

// index2.js
export function add(a, b) {
  return a + b
}

打包的效果及運行效果:
在這裏插入圖片描述
在這裏插入圖片描述
假設index2.js的資源體積很大,並且我們在頁面初次渲染的時候並不需要使用它,就可以對它進行異步加載。
index.js和index2.js代碼如下:

// index.js
import('./index2.js').then(({add}) => {
  console.log(add(2,3))
})

// index2.js
export function add(a, b) {
  return a + b
}

webpack.config.js配置代碼如下:

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  context: path.join(__dirname, './src'),
  entry: {
    index: './index.js'
  },
  output: {
    //path: path.join(__dirname, 'dist'),
    filename: '[name].js',
    publicPath: '/dist/'
  },
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', {
          loader: 'css-loader',
          options: {
            modules: {
              localIdentName: '[path][name]__[local]--[hash:base64:5]',
            }
          }
        }]
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            presets: [
              [
                'env', {
                  modules: false
                }
              ]
            ]
          }
        }
      }
    ],
  }
}

打包的效果及運行效果:
在這裏插入圖片描述
在這裏插入圖片描述
首屏加載的JS資源地址是通過頁面中的script標籤來指定的,而間接資源(通過首屏JS再進一步加載的JS)的位置則要通過output.publicPath來指定。上面我們的import函數相當於使index2.js成爲了一個間接資源,我們需要配置publicPath來告訴Webpack去哪裏獲取它。

由上圖可以看出,Chrome的nextwork面板看到一個0.js的請求,它就是index2及其依賴產生的資源。觀察面板中的Initinator字段,可以看出它是有index.js產生的請求。查看index.js可以看出,是由這段代碼動態的在head頭部添加script標籤引入的方式,引入0.js,查看源代碼並不能找到這段引入的代碼,所以是js動態添加進去的。
在這裏插入圖片描述

在element 面板能查到script標籤動態插入的0.js代碼。
在這裏插入圖片描述

注意:import函數還有一個比較重要的特性。ES6 Module中要求import必須出現在代碼的頂層作用域,而Webpack的import函數則可以在任何我們希望的時候調用

異步chunk的配置

由上面的方法我們已經實現了異步資源,但是此產生的資源名稱都是數字如0.js,比較隨機,不具有可讀可維護性。此時就需要我們去配置Webpack的一些參數來爲其添加有意義的名字,便於我們維護它們。

我們在Webpack的配置中添加了output.chunkFilename,用來指定異步chunk的文件名。其命名規則與output.filename基本一致,不過由於異步chunk默認沒有名字,其默認值是[id].js。
配置代碼爲:

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  context: path.join(__dirname, './src'),
  entry: {
    index: './index.js'
  },
  output: {
    //path: path.join(__dirname, 'dist'),
    filename: '[name].js',
    publicPath: '/dist/',
    chunkFilename:'[name].js'
  },
  mode: 'development',
  // optimization: {
  //   splitChunks: {
  //     chunks: 'all'
  //   }
  // },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', {
          loader: 'css-loader',
          options: {
            modules: {
              localIdentName: '[path][name]__[local]--[hash:base64:5]',
            }
          }
        }]
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            presets: [
              [
                'env', {
                  modules: false
                }
              ]
            ]
          }
        }
      }
    ],
  }
}

index.js修改爲:

import(/* webpackChunkName:'index2'*/'./index2.js').then(({add}) => {
  console.log(add(2,3))
})

在這裏插入圖片描述
在index.js中,我們通過特有的註釋來讓Webpack獲取到異步chunk的名字,並配置output.chunkFilename爲[name].js,由上圖可以看出,0變成了index2.js

chrome network上的element面板效果如下圖:
在這裏插入圖片描述

總結

資源異步加載方法import()和require.ensure(),也可以有效地縮小資源體積,同時更好地利用緩存,給用戶更友好的體驗。如果想了解更多,請掃描二維碼:
在這裏插入圖片描述

發佈了255 篇原創文章 · 獲贊 162 · 訪問量 45萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章