Webpack中Compiler詳解以及自定義loader和plugin詳解

Webpack Compiler 源碼全面解析

Compiler

在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述

類圖解析:

1. Tapable 基類

Webpack 插件系統的核心,提供鉤子注冊(plugin)和觸發(applyPlugins)能力。CompilerCompilation 均繼承此類,支持插件通過生命周期鉤子介入構建流程。

2. Compiler 類

在這里插入圖片描述
在這里插入圖片描述

? 核心屬性

 ? `options`:整合 Webpack 配置(入口、出口、Loader 等)  ? `hooks`:包含 `run`(構建啟動)、`compile`(編譯開始)、`emit`(資源生成前)等鉤子,插件可監聽這些事件  

? 核心方法

 ? `run()`:啟動構建流程,觸發 `beforeRun` 和 `run` 鉤子  ? `compile()`:創建 `Compilation` 實例,進入模塊解析階段

3. Compilation 類

在這里插入圖片描述

? 核心屬性

 ? `modules`:所有被處理的模塊集合,包含源碼和依賴信息  ? `chunks`:代碼分塊(如通過 `SplitChunksPlugin` 分割的公共模塊)  ? `assets`:最終輸出的文件內容(如 JS、CSS、圖片等)  

? 核心方法

 ? `addEntry()`:從入口文件遞歸分析依賴,構建模塊依賴圖  ? `seal()`:凍結依賴圖,執行 Tree Shaking 和代碼壓縮等優化  ? `emitAsset()`:將資源寫入磁盤,觸發 `emit` 鉤子

4 協作關系

? 生命周期:Compiler 管理全局構建流程(如初始化配置、觸發鉤子),而 Compilation 負責單次編譯的具體實現(模塊解析、優化、輸出)

? 實例化:每次構建(包括開發模式下文件變化)時,Compiler 會創建新的 Compilation 實例,確保資源狀態隔離。

應用場景示例:
? 插件開發:通過監聽 Compiler.hooks.emit 修改輸出內容(如刪除注釋)

? 性能優化:利用 Compilation.modules 分析模塊體積,實現按需加載。

在這里插入圖片描述


在前端工程化中,自定義 Webpack 的 Loader 和 Plugin 是擴展構建流程的核心能力。以下從實現原理、開發步驟、典型場景等維度深入解析兩者的設計與應用:


自定義loader和plugin

一、自定義 Loader 的實現

1. 核心原理與開發步驟

? 本質與作用

Loader 是文件轉換器,將非 JS 文件(如 Markdown、CSS)轉換為 Webpack 可處理的模塊。其開發需遵循單一職責原則,且需保持無狀態。

? 實現步驟:

  1. 創建函數:導出一個處理文件內容的函數,接收 source(文件內容)作為輸入。
  2. 處理內容:通過正則或工具庫(如 markedbabel)對內容轉換,例如將 Markdown 轉 HTML。
  3. 返回結果:需返回 JS 代碼字符串,支持 module.exports 或 ES Modules 導出。
  4. 配置使用:在 webpack.config.jsmodule.rules 中通過 test 匹配文件類型并串聯 Loader。
2. 同步與異步 Loader

? 同步處理:直接返回結果,適用于簡單轉換(如字符串替換)。

module.exports = function (content) {return content.replace(/world/g, 'loader'); // 替換文本
};

? 異步處理:通過 this.async() 實現異步操作(如網絡請求、文件讀取)。

module.exports = function (content) {const callback = this.async();fetchData().then(() => callback(null, processedContent));
};
3. 典型場景示例

? 多語言翻譯:替換代碼中的 __t('KEY') 為對應語言字符串。

? 資源優化:使用 svgo 壓縮 SVG 文件,或通過 imagemin 生成 WebP 圖片。

? 語法轉換:自定義 Babel Loader 實現 ES6 轉 ES5。


二、自定義 Plugin 的實現

在這里插入圖片描述

1. 核心機制與生命周期

? 實現原理:

Plugin 通過監聽 Webpack 生命周期鉤子(如 emitdone)介入構建流程,操作 compilercompilation 對象。

? 開發步驟:

  1. 創建類:定義包含 apply 方法的類,接收 compiler 對象。
  2. 注冊鉤子:在目標鉤子(如 emit)中掛載邏輯,操作資源或生成附加文件。
  3. 配置使用:在 plugins 數組中實例化插件。
2. 典型場景示例

? 打包報告生成:在 done 鉤子中生成包含構建時間、模塊大小的 JSON 報告。

? 資源修改:在 emit 階段遍歷 compilation.assets,刪除 JS 注釋或修改文件內容。

compiler.hooks.emit.tap('MyPlugin', (compilation) => {Object.keys(compilation.assets).forEach(name => {if (name.endsWith('.js')) {const content = compilation.assets[name].source().replace(/\/\*.*?\*\//g, '');compilation.assets[name] = { source: () => content, size: () => content.length };}});
});

? 自動化注入:類似 HtmlWebpackPlugin,動態生成 HTML 并插入腳本。

3. 高級應用

? 自定義鉤子:通過 tapable 創建同步/異步鉤子,擴展插件間的通信能力。

? 多插件協作:結合其他插件(如 CleanWebpackPlugin)清理構建目錄。


三、Loader 與 Plugin 的協同與對比

維度LoaderPlugin
作用層級單文件處理(如轉譯、壓縮)全局流程控制(如資源優化、報告生成)
執行時機模塊加載階段任意構建階段(通過鉤子介入)
配置方式module.rules 中定義規則鏈plugins 數組實例化
典型工具babel-loadercss-loaderHtmlWebpackPluginTerserPlugin

四、調試與優化建議

  1. Loader 調試
    ? 使用 loader-runner 獨立測試邏輯。

    ? 通過 this.getOptions() 獲取配置參數,結合 schema.json 校驗參數合法性。

  2. Plugin 性能優化
    ? 在 afterEmit 階段執行耗時操作,避免阻塞主流程。

    ? 利用 compilation.fileTimestamps 緩存文件修改時間,減少重復處理。


五、總結

自定義 Loader 和 Plugin 是 Webpack 生態靈活性的核心體現。Loader 聚焦于文件級轉換,適合語法兼容、資源預處理等場景;Plugin 則通過生命周期鉤子實現全局控制,適用于構建優化、自動化注入等復雜需求。兩者的協同使用可覆蓋從模塊處理到工程化優化的全鏈路需求,開發者可根據具體場景選擇合適方案。


  1. 自定義 Loader:將 Markdown 轉換為 HTML。
  2. 自定義 Plugin:構建結束發送通知(以控制臺模擬為例,實際可擴展為系統通知)。
  3. 自定義 Plugin:構建時檢測重復依賴并輸出警告。

樣例

🔧 1. 自定義 Markdown 轉 HTML Loader

依賴:安裝 marked(或 markdown-it

npm install marked --save-dev
loaders/md-to-html-loader.js
const marked = require('marked');module.exports = function (source) {const html = marked(source);// 返回一段 JS 模塊代碼,導出 HTML 字符串return `export default ${JSON.stringify(html)}`;
};
webpack.config.js 中配置:
module.exports = {module: {rules: [{test: /\.md$/,use: path.resolve(__dirname, 'loaders/md-to-html-loader.js')}]}
};

🔔 2. 自定義構建結束發送通知 Plugin

控制臺通知實現(也可以結合 node-notifier 發桌面通知)

plugins/build-notifier-plugin.js
class BuildNotifierPlugin {apply(compiler) {compiler.hooks.done.tap('BuildNotifierPlugin', (stats) => {const time = (stats.endTime - stats.startTime) / 1000;console.log(`? 構建完成!耗時 ${time.toFixed(2)}`);});}
}module.exports = BuildNotifierPlugin;
webpack.config.js 中配置:
const BuildNotifierPlugin = require('./plugins/build-notifier-plugin');module.exports = {plugins: [new BuildNotifierPlugin()]
};

可選增強:使用 node-notifier 發系統彈窗提示。


🧩 3. 自定義重復依賴檢測 Plugin

這個插件會分析所有模塊中使用的依賴包并查找是否存在多個版本的情況(如多個 lodash)

plugins/duplicate-dependency-plugin.js
const path = require('path');
const fs = require('fs');class DuplicateDependencyPlugin {apply(compiler) {compiler.hooks.emit.tapAsync('DuplicateDependencyPlugin', (compilation, callback) => {const moduleVersions = {};compilation.modules.forEach((module) => {if (module.resource && module.resource.includes('node_modules')) {const parts = module.resource.split('node_modules' + path.sep);if (parts[1]) {const pkgPath = parts[1].split(path.sep);const name = pkgPath[0].startsWith('@') ? `${pkgPath[0]}/${pkgPath[1]}` : pkgPath[0];const packageJsonPath = path.join(module.resource.split('node_modules')[0], 'node_modules', name, 'package.json');try {const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));if (!moduleVersions[name]) {moduleVersions[name] = new Set();}moduleVersions[name].add(pkg.version);} catch (err) {// 忽略找不到 package.json 的模塊}}}});// 輸出重復依賴警告Object.entries(moduleVersions).forEach(([name, versions]) => {if (versions.size > 1) {console.warn(`?? 發現重復依賴:${name},版本有:${[...versions].join(', ')}`);}});callback();});}
}module.exports = DuplicateDependencyPlugin;
webpack.config.js 中配置:
const DuplicateDependencyPlugin = require('./plugins/duplicate-dependency-plugin');module.exports = {plugins: [new DuplicateDependencyPlugin()]
};

📦 最終項目結構參考

webpack-project/
├── loaders/
│   └── md-to-html-loader.js
├── plugins/
│   ├── build-notifier-plugin.js
│   └── duplicate-dependency-plugin.js
├── src/
│   └── index.js
├── content/
│   └── example.md
├── webpack.config.js
└── package.json

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/79519.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79519.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79519.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HAProxy + Keepalived + Nginx 高可用負載均衡系統

1. 項目背景 在現代Web應用中,高可用性和負載均衡是兩個至關重要的需求。本項目旨在通過HAProxy實現流量分發,通過Keepalived實現高可用性,通過Nginx提供后端服務。該架構能夠確保在單點故障的情況下,系統仍然能夠正常運行&#…

Kubernetes控制平面組件:Kubelet詳解(一):API接口層介紹

云原生學習路線導航頁(持續更新中) kubernetes學習系列快捷鏈接 Kubernetes架構原則和對象設計(一)Kubernetes架構原則和對象設計(二)Kubernetes架構原則和對象設計(三)Kubernetes控…

VIC-2D 7.0 為平面樣件機械試驗提供全視野位移及應變數據軟件

The VIC-2D系統是一個完全集成的解決方案,它基于優化的相關算法為平面試樣的力學測試提供非接觸、全場的二維位移和應變數據,可測量關注區域內的每個像素子集的面內位移,并通過多種張量選項計算全場應變。The VIC-2D 系統可測量超過 2000%變形…

多線程訪問Servlet如何謹慎處理共享資源

1. 避免共享狀態(最佳實踐) 核心思想:Servlet 本身應設計為無狀態(Stateless),不依賴實例變量存儲請求相關數據。 實現方式: 將變量聲明在方法內部(局部變量)&#xff0…

從Windows到Mac的過渡:學習筆記與心得

作為一名長期使用Windows操作系統的用戶,當我決定轉換到Mac時,心中充滿了期待與好奇。Mac以其獨特的操作系統和設計風格著稱,雖然有許多相似之處,但仍有不少差異需要適應。為了幫助其他有類似轉換需求的朋友,我總結了一…

TestNG接口自動化

第一章、 Rest assured接口測試框架 一、概述 接口自動化的框架,主要是用來做接口自動化測試,返回的報文都是JSON 語法比較簡單,只需要掌握常用的方法 用例運行的速度非常快 斷言的機制 Json 封裝相關方法,jsonpath,x…

【速寫】KV-cache與解碼的再探討(以束搜索實現為例)

文章目錄 1 Beam Search 解碼算法實現2 實現帶KV Cache的Beam Search解碼3 關于在帶kv-cache的情況下的use_cache參數 1 Beam Search 解碼算法實現 下面是一個使用PyTorch實現的beam search解碼算法: 幾個小細節: 束搜索可以加入length_penalty&#…

ABP-Book Store Application中文講解 - 前期準備 - Part 3:Acme.BookStore項目模塊詳解之二

1. 匯總 ABP-Book Store Application中文講解-匯總-CSDN博客 2. 前一章 ABP-Book Store Application中文講解 - 前期準備 - Part 3:Acme.BookStore項目模塊詳解 項目之間的引用關系。 目錄 1. .Domain.Shared 2. .Domain 3. .Application.Contracts 4. .Application 5…

【Leetcode刷題隨筆】349. 兩個數組的交集

1. 題目描述 給定兩個數組nums1和nums2&#xff0c;返回它們的交集。輸出結果中的每個元素一定是唯一的。我們可以不考慮輸出結果的順序。 示例1: 輸入:nums1 [1,2,2,1], nums2 [2,2] 輸出&#xff1a;[2] 題目條件&#xff1a; 1 < nums1.length, nums2.length < 10…

Unity打包安卓失敗 Build failure 解決方法

【Unity】打包安卓失敗 Build failure 的解決方法_com.android.build.gradle.internal.res.linkapplicat-CSDN博客 unity在打包時設置手機屏幕橫屏豎屏的方法_unity打包默認橫屏-CSDN博客

Window、CentOs、Ubuntu 安裝 docker

Window 版本 網址&#xff1a;https://www.docker.com/ 下載 下載完成后&#xff0c;雙擊安裝就可以了 Centos 版本 卸載 Docker &#xff08;可選&#xff09; yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-log…

Matlab自學筆記五十四:符號數學工具箱和符號運算、符號求解、繪圖

1.什么是符號數學工具箱&#xff1f; 符號數學工具箱是Matlab針對符號對象的運算功能&#xff0c;它引入了一種特殊的數據類型 - 符號對象&#xff1b; 該數據類型包括符號數字&#xff0c;符號變量&#xff0c;符號表達式和符號函數&#xff0c;還包含符號矩陣&#xff0c;以…

OpenCV進階操作:圖像的透視變換

文章目錄 前言一、什么是透視變換&#xff1f;二、透視變換的過程三、OpenCV透視變換核心函數四、文檔掃描校正&#xff08;代碼&#xff09;1、預處理2、定義輪廓點的排序函數3、定義透視變換函數4、讀取原圖并縮放5、輪廓檢測6、繪制最大輪廓7、對最大輪廓進行透視變換8、旋轉…

【python】基礎知識點100問

以下是Python基礎語法知識的30條要點整理,涵蓋數據類型、函數、控制結構等核心內容,結合最新資料歸納總結: 基礎30問 一、函數特性 函數多返回值 支持用逗號分隔返回多個值,自動打包為元組,接收時可解包到多個變量 def func(): return 1, "a" x, y = func()匿…

采用AI神經網絡降噪算法的通信語音降噪(ENC)模組性能測試和應用

采用AI降噪的語言通話環境抑制模組性能效果測試 隨著AI時代來臨.通話設備的環境噪音抑制也進入AI降噪算法時代. AI神經網絡降噪技術是一款革命性的語音處理技術&#xff0c;他突破了傳統單麥克風和雙麥克風降噪的局限性,利用采集的各種日常環境中的噪音樣本進行訓練學習.讓降噪…

openwrt目錄結構(部分)

1&#xff0c;openwrt 原始目錄需要注意的目錄 tools: 該目錄下存放著一些&#xff0c;編譯工程的自動化工具包和一些在編譯過程用到的命令包&#xff0c; 查看目錄下的Makefile&#xff0c;知道其會在編譯過程中將依賴包下載 例如&#xff1a; autoconf / lzma / mkimage/ …

RDB和AOF的區別

Redis提供兩種主要的持久化機制&#xff1a;RDB&#xff08;Redis Database&#xff09;和AOF&#xff08;Append Only File&#xff09;&#xff0c;它們在數據持久化方式、性能影響及恢復策略上各有特點。以下是兩者的對比分析及使用建議&#xff1a; RDB&#xff08;快照持久…

基于大模型的甲狀腺結節診療全流程預測與方案研究報告

目錄 一、引言 1.1 研究背景與目的 1.2 研究意義 1.3 國內外研究現狀 二、大模型預測原理與方法 2.1 相關大模型概述 2.2 數據收集與預處理 2.3 模型訓練與驗證 三、術前預測與評估 3.1 結節性質預測 3.1.1 良惡性判斷 3.1.2 與傳統診斷方法對比 3.2 手術風險預測…

逆向破解:x64dbg

文章目錄 一、CPU窗口1、反匯編窗口2、寄存器窗口3、棧地址窗口4、十六進制數據窗口5、堆棧參數解析窗口 二、常用快捷鍵三、字符串檢索功能四、調試功能1、上一步 一、CPU窗口 1、反匯編窗口 2、寄存器窗口 寄存器窗口用于顯示和解釋當前線程環境下CPU寄存器的各種狀態值和內…

免布線視頻樁如何重塑停車管理模式

傳統停車管理常因布線復雜、維護成本高而難以推廣&#xff0c;而“免布線視頻樁”通過無線設計、低功耗與高精度檢測&#xff0c;為城市停車提供高效解決方案。作為智慧城市建設的創新工具&#xff0c;免布線視頻樁以即裝即用、長效續航等特性&#xff0c;正在重塑停車管理模式…