Webpack 4教程 - 第四部分,使用SplitChunksPlugin分離代碼

来源:https://www.cnblogs.com/powertoolsteam/archive/2019/02/22/10416293.html
-Advertisement-
Play Games

Webpack 4 給我們帶來了一些變化。其中包括更快地打包,引入了SplitChunksPlugin,並淘汰掉之前的CommomsChunksPlugin。在本文,你將學習如何拆分輸出代碼以提高應用的性能。 ...


轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。
原文出處:https://wanago.io/2018/06/04/code-splitting-with-splitchunksplugin-in-webpack-4/

Webpack 4 給我們帶來了一些變化。其中包括更快地打包,引入了SplitChunksPlugin,並淘汰掉之前的CommomsChunksPlugin。在本文,你將學習如何拆分輸出代碼以提高應用的性能。

代碼分離的思想

先說重要的:在Webpack中,到底什麼是代碼分離?代碼分離允許你把代碼拆分到多個文件中。如果使用得當,你的應用性能會提高很多。因為瀏覽器能緩存你的代碼。

每當你做出一次修改,包含修改的文件需要被所有訪問你網站的人重新下載。但你並不會經常修改應用的依賴庫(譯者註:你常修改的是你的業務邏輯)。如果你能把那些依賴庫拆分到完全分離的文件中,即使業務邏輯發生了更改,訪問者也不需要再次下載依賴庫,直接使用之前的緩存就可以了。

使用Webpack時,你會得到一個或多個生成的輸出文件,這些文件包含了我們源碼的最終輸出。而它們由代碼塊(chunks)組成。

入口(Entry)

入口定義了我們代碼中應用是從哪裡開始執行的,這也是Webpack開始打包的地方。你可以定義一個入口(常見於單頁應用),或者多個入口(常見於多頁應用)。

定義一個入口,就會得到一個chunk。如果你只使用字元串定義一個入口,那麼這個chunk名為main。如果你使用對象定義了多個入口,那麼它們會以entry對象的屬性來命名。下麵的例子會得到相同的chunk:

// 例1
entry: './src/index.js'
// 例2
entry: {
  main: './src/index.js'
}

輸出(Output)

在配置文件中,輸出配置是一個對象,它指明瞭Webpack應該在哪兒和如何對我們的打包結果和資源進行輸出。雖然可能有多個入口,但是只能有一個輸出配置對象。而chunk名稱的用處,就在於根據入口對應不同的輸出。你可以為我們的打包輸出定義一個固定的文件名,但若想代碼分離,就不應該這麼做。你可以使用[name]為我們的輸出文件創建文件名的模板:

output: {
  filename: '[name].[chunkhash].bundle.js',
  path: path.resolve(__dirname, 'dist')
}

一件值得註意的重要東西是[chunkhash]:它是一個基於文件內容的屬於特定chunk的哈希值。它僅會隨著文件內容的改變而改變。因此,瀏覽器就可以利用這一點來緩存它。如果打包輸出的文件名變了,瀏覽器就知道自己需要重新下載它。一個chunkhash可能長這樣:0c553ebfd158e16da428。

我們的主chunk會被打包進一個叫main.[chunkhash].bundle.js的文件。

SplitChunksPlugin

由於有了SplitChunksPlugin,你可以把應用中的特定部分移至不同文件。如果一個模塊在不止一個chunk中被使用,那麼利用代碼分離,該模塊就可以在它們之間很好地被共用。這是Webpack的預設行為。

// utilities/users.js
export default [
  { firstName: "Adam", age: 28 },
  { firstName: "Jane", age: 24 },
  { firstName: "Ben",  age: 31 },
  { firstName: "Lucy", age: 40 }
]
// a.js
import _ from 'lodash';
import users from './users';

const adam = _.find(users, { firstName: 'Adam' });
// b.js
import _ from 'lodash';
import users from './users';

const lucy = _.find(users, { firstName: 'Lucy' });
// webpack.config.js
module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  }
};

如果運行它,你會看到Webpack創建了兩個文件:a.[chunkhash].bundle.js和b.[chunkhash].bundle.js,而且每一個文件都包含對lodash庫的拷貝:這並不好!我之前說過,為共用的庫創建分離的文件是Webpack的一個預設行為,但這隻涉及非同步的chunk,即意味著只作用於我們非同步引入的那些文件。我們會在介紹懶載入的時候討論這個話題。為了使這個預設行為能支持所有類型的chunks,我們需要稍微改一下Webpack的配置:

// webpack.config.js
module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all"
    }
  },
};

現在我們看到,創建了額外的vendors~a~b.[chunkhash].bundle.js文件,它包含了lodash庫的代碼。這是因為我們預設有一些cacheGroups配置:

splitChunks: {
  chunks: "all",
  cacheGroups: {
    vendors: {
      test: /[\\/]node_modules[\\/]/,
      priority: -10
    },
    default: {
      minChunks: 2,
      priority: -20,
      reuseExistingChunk: true
    }
  }
}

首先,是vendors,它包含的文件來自於你node_modules。再者,是所有其他共用模塊的預設緩存組。這裡有一個小點:有一些冗餘。a.[chunkhash].bundle.js和b.[chunkhash].bundle.js都包含了users.js的內容。這是因為,SplitChunksPlugin預設地只會分離大於30Kb的文件。我們可以輕鬆地修改它:

// webpack.config.js
module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 0 // 修改了這裡
    }
  }
};

結果是,它新創建了屬於預設緩存組的名為a~b.[chunkhash].bundle.js的文件。因為我們的users.js文件所占空間遠遠小於30Kb,在沒有修改minSize屬性的情況下,它不會被打包到單獨的分離文件。在真實環境下,這是一件好事,因為這樣不會帶來實質的性能提升,反而會強制瀏覽器為分離出的文件(它現在是很小的)再發一次額外的請求。

我們可以進一步,為僅在utilities目錄下的做特殊處理:

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        utilities: {
          test: /[\\/]src[\\/]utilities[\\/]/,
          minSize: 0
        }
      }
    }
  }
};

這樣我們的輸出包含4個文件:a.[chunkhash].bundle.js,b.[chunkhash].bundle.js,vendors~a~b.[chunkhash].bundle.js和utilities~a~b.[chunkhash].bundle.js。(譯者註:這需要在打包之前,把users.js文件移至./src/utilities目錄下,並修改a.js和b.js中的相關引用路徑)。雖然我們現在可以讓minSize:0成為全局設置(即放在splitChunks對象中作為其屬性),但即使這樣,預設的緩存組也不會被創建。因為,所有可能被引入的文件都應該在我們剛創建的utilities組下。這個組具的優先順序是0,高於預設緩存組的優先順序。你可能已經註意到了,預設緩存組的優先順序被設置為了-20。

還有其他的配置供你使用,可查看SplitChunksPlugin文檔

總結

即使你只有一個入口(常發生於大多數單頁應用中),把你的依賴放入一個獨立的文件依然是個好主意。這其實很容易做到,因為使用SplitChunksPlugin是Webpack 4的預設行為,可能你設置一下chunks: 'all'就足夠了。如果你想讓我討論此相關話題,歡迎留言。很快我們將會學習如何使用懶載入,讓你的應用性能更上一層樓。敬請期待!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • select * from dba_jobs ;select * from dba_scheduler_job_run_details t; >這個語句通過制定job名,來查看job的運行的詳細信息 select * from dba_scheduler_jobs; >這個語句可以查看所有job,及 ...
  • 正如前面所講的, redis 的數據結構就是一系列的鍵值對鍵 -> printable ASCII (可列印的 ASCII 碼, 最大值是 512MB)值 -> Primitives (基本的) string 字元串 (最大值是 512MB) Containers (of string) (以其他形 ...
  • 屏幕尺寸 #define kScreenWidth [UIScreen mainScreen].bounds.size.width #define kScreenHeight [UIScreen mainScreen].bounds.size.height 手機型號 #define kISiPhon ...
  • android 動畫分為兩類,View Animation(視圖動畫)和property Animation(屬性動畫),View Animation(視圖動畫)包含了Tween Animation和Frame Animation, property Animation包含Value Animati ...
  • 在iOS開發中經常遇到一些欄位和類型的定義,例如配置生產和測試不同環境的參數等,這時候經常用到#define、const以及typedef。那麼它們之間有什麼區別呢?我們接下來一個一個具體瞭解下。 一、基本概念 1.1、#define #define並不是定義全局變數,而是巨集定義。也就是說並不是真正 ...
  • EasyMessenger ====== "直達Github項目地址" 一款用於Android平臺的基於Binder的進程間通信庫,採用 生成IPC通信需要的代碼。 相對於 具備如下優勢: 採用Java聲明介面,更方便 介面方法支持重載 同時支持同步和非同步通信 目前支持如下數據類型: boolean ...
  • 前言: 代理模式是iOS中非常重要的一個模式,iOS SDK中的系統控制項幾乎都用到了代理模式。代理模式用來處理事件監聽、參數傳遞功能。 協議創建(Protocol): 可手打如下代碼,或者在代碼塊裡面搜索"protocol",然後把協議的代碼拖拽出來 @protocol FullcellDalega ...
  • 在製作完成室內三維地圖的功能後,最經常有的需求就是如何做人員的軌跡回放,一般流程都是從資料庫中查詢軌跡坐標後,經過後臺查詢介面返回給前端,接下來的事情都交給JS來完成。如果想做好一個性能好的軌跡回放功能,還是很有技術含量的,比如我要加一個時間軸,可以隨時拖動時間查詢,然後能快速響應顯示人的軌跡?這就... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...