Webpack學習-Plugin

来源:https://www.cnblogs.com/wuxiaobin/archive/2019/03/22/10579187.html
-Advertisement-
Play Games

原文地址:http://wushaobin.top/2019/03/15/webpackPlugin/ 什麼是Plugin? 在 "Webpack學習-工作原理(上)" 一文中我們就已經介紹了 的基本概念,同時知道了webpack其實很像一條生產線,要經過一系列處理流程後才能將源文件轉換成我們理想的 ...


什麼是Plugin?

Webpack學習-工作原理(上)一文中我們就已經介紹了Plugin的基本概念,同時知道了webpack其實很像一條生產線,要經過一系列處理流程後才能將源文件轉換成我們理想的輸出結果。而webpack構建過程中,會在特定的時機廣播對應的事件,插件可以監聽這些事件的發生,Plugin在webpack構建流程中就是這樣的一個角色。同時我們也介紹了很多整個構建流程會廣播的事件,那麼這篇文章我們一起詳細地學習一下如何編寫Plugin

其實Plugin本質上就是一個class,一個最基礎的Plugin代碼如下:

    class BasePlugin {
        // 構造函數,接收options配置
        constructor(options) {
            ...
        }
        apply(compiler) {
            // 在此處去監聽webpack廣播的所有事件
            compiler.plugin('compilation', function(compilation) {
                ...
            });
        }
    }

    moudle.exports = BasePlugin;

我們可以再看看,webpack會怎麼配置Plugin,

    module.exports = {
        plugins: [
            new BasePlugin(options)
        ]
    }

我們回憶一下,Webpack學習-工作原理(上)文章中們介紹過webpack的構建詳細流程,初始化的時候會去new Plugin(),那麼便是會去實例化webpack配置plugins所有的插件,那麼第一步插件實例化就有了,而插件中的apply方法會在開始編譯時依次被調用,並且傳入Compiler對象(後面會深入介紹),然後調用Compiler.run()開始編譯。

瞭解Compiler 和 Compilation

  • Compiler對象包含了Webpack環境所有的配置信息,包含options,loaders,plugins這些信息,這個對象在webpack啟動時被實例化,全局唯一,可以簡單理解成就是webpack實例
  • Compilation代表著一次新的編譯,包含當前的模塊資源、編譯生成的資源,變化的文件,之前我們瞭解到compilation事件中compilation對象也會提供很多事件給插件做擴展,同時很多事件的的回調中都會將compilation傳入,以便使用
  • Webpack的事件機制應用了觀察者模式,Compiler和Compilation同時繼承Taptable,所以可以直接在Compiler和Compilation對象廣播和監聽事件,廣播事件[Compiler | Compilation].apply('event-name', params),監聽事件[Compiler | Compilation].plugin('event-name', function(params){...}),event-name不能和現有的事件重名

開發插件需註意的點

  • 只要能拿到Compiler或是Compilation對象,就能廣播新的事件,供其他插件使用
  • Compiler或是Compilation對象為同一個引用,一旦修改就會影響後面的插件
  • 如果事件是非同步的,會帶兩個參數,第二個參數為回調函數,在插件處理完任務時需要調用回調函數通知webpack,才會進入下一個處理流程。如:
  compiler.plugin('emit',function(compilation, callback) {
    // 支持處理邏輯

    // 處理完畢後執行 callback 以通知 Webpack 
    // 如果不執行 callback,運行流程將會一直卡在這不往下執行 
    callback();
  });

常用api

讀取輸出資源、代碼塊、模塊及其依賴

class Plugin {
  apply(compiler) {
    compiler.plugin('emit', function (compilation, callback) {
      // compilation.chunks 存放所有代碼塊,是一個數組
      compilation.chunks.forEach(function (chunk) {
        // chunk 代表一個代碼塊
        // 代碼塊由多個模塊組成,通過 chunk.forEachModule 能讀取組成代碼塊的每個模塊
        chunk.forEachModule(function (module) {
          // module 代表一個模塊
          // module.fileDependencies 存放當前模塊的所有依賴的文件路徑,是一個數組
          module.fileDependencies.forEach(function (filepath) {
          });
        });

        // Webpack 會根據 Chunk 去生成輸出的文件資源,每個 Chunk 都對應一個及其以上的輸出文件
        // 例如在 Chunk 中包含了 CSS 模塊並且使用了 ExtractTextPlugin 時,
        // 該 Chunk 就會生成 .js 和 .css 兩個文件
        chunk.files.forEach(function (filename) {
          // compilation.assets 存放當前所有即將輸出的資源
          // 調用一個輸出資源的 source() 方法能獲取到輸出資源的內容
          let source = compilation.assets[filename].source();
        });
      });

      // 這是一個非同步事件,要記得調用 callback 通知 Webpack 本次事件監聽處理結束。
      // 如果忘記了調用 callback,Webpack 將一直卡在這裡而不會往後執行。
      callback();
    })
  }
}

監聽文件變化

// 當依賴的文件發生變化時會觸發 watch-run 事件
compiler.plugin('watch-run', (watching, callback) => {
    // 獲取發生變化的文件列表
    const changedFiles = watching.compiler.watchFileSystem.watcher.mtimes;
    // changedFiles 格式為鍵值對,鍵為發生變化的文件路徑。
    if (changedFiles[filePath] !== undefined) {
      // filePath 對應的文件發生了變化
    }
    callback();
});

為了監聽 HTML 文件的變化,我們需要把 HTML 文件加入到依賴列表中,可以怎麼做:

compiler.plugin('after-compile', (compilation, callback) => {
  // 把 HTML 文件添加到文件依賴列表,好讓 Webpack 去監聽 HTML 模塊文件,在 HTML 模版文件發生變化時重新啟動一次編譯
    compilation.fileDependencies.push(filePath);
    callback();
});

修改輸出資源

// 設置 compilation.assets 的代碼如下:
compiler.plugin('emit', (compilation, callback) => {
  // 設置名稱為 fileName 的輸出資源
  compilation.assets[fileName] = {
    // 返迴文件內容
    source: () => {
      // fileContent 既可以是代表文本文件的字元串,也可以是代表二進位文件的 Buffer
      return fileContent;
      },
    // 返迴文件大小
      size: () => {
      return Buffer.byteLength(fileContent, 'utf8');
    }
  };
  callback();
});
// 讀取 compilation.assets 的代碼如下:
compiler.plugin('emit', (compilation, callback) => {
  // 讀取名稱為 fileName 的輸出資源
  const asset = compilation.assets[fileName];
  // 獲取輸出資源的內容
  asset.source();
  // 獲取輸出資源的文件大小
  asset.size();
  callback();
});

判斷webpack使用了哪些插件

// 判斷當前配置使用使用了 ExtractTextPlugin,
// compiler 參數即為 Webpack 在 apply(compiler) 中傳入的參數
function hasExtractTextPlugin(compiler) {
  // 當前配置所有使用的插件列表
  const plugins = compiler.options.plugins;
  // 去 plugins 中尋找有沒有 ExtractTextPlugin 的實例
  return plugins.find(plugin=>plugin.__proto__.constructor === ExtractTextPlugin) != null;
}

對於上面常用api的講解,我們可以知道compiler和compilation在plugin中占據著舉足輕重的作用,那麼具體它們長什麼樣子的,我們編寫個例子列印出來看看,下麵以extract-text-webpack-plugin插件進行斷點調試的截圖,可以來看看這兩個分別列印出來的東西,

compiler
compilation

總結

一般情況下,我們是不需要去寫Plugin,但是有時候我們有些業務需求是沒有插件可以滿足的,那麼我們便得需要自己去寫Plugin,那瞭解Plugin的一些相關知識點就是有必要的,我們不一定要每個鉤子或是API都相當熟,但是我們需要思路,瞭解如何編寫Plugin,也是有必要的,Plugin中最重要的compiler和compilation,一個Plugin插件也就是圍繞著這個去擴展,對應詳細內容可以去webpack官網瞭解,compiler鏈接compilation鏈接


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

-Advertisement-
Play Games
更多相關文章
  • 程式6:用*號輸出字母C的圖案 console.log(' ****'); console.log(' ***'); console.log(' **'); console.log(' *'); console.log('*'); console.log(' *'); console.log(' * ...
  • 非同步請求 其實什麼是非同步請求已經不用多說了,通俗的說,就是整個頁面不會刷新,需要更新的部分數據做局部刷新,其他數據不變。 學到這裡,你應該用過jquery里的ajax了,所以很能理解了,不多說了。詳細的就自己百度了 在vue中,可以做非同步請求的有vue-resource和axios ... ...
  • global對象 瀏覽器端JavaScript中的全局對象為“window”,在瀏覽器中定義的變數都會成為“window”對象的屬性。 不像瀏覽器端JavaScript,在Nodejs中沒有window對象,Nodejs中的全局對象為“global”,並且我們定義的變數不會作為“global”的屬性 ...
  • 在開始講 Angular 各個核心知識點之前,想先來講講開發工具 WebStorm 的一些配置以及相應配置文件如 tslint.json 的配置。 因為我個人比較註重代碼規範、代碼風格,而對於這些規範,我只有一個觀點: 一切需要依賴開發人員的主觀意識去遵守的規範都沒有多大意義。 以前做 Androi ...
  • 事件機制 React事件主要分為兩部分: 事件註冊與事件分發。下麵先從事件註冊說起。 事件註冊 假設我們的程式如下: 事件註冊主要發生在初始化Dom屬性的時候,調用 方法,對一些類型dom進行事件綁定。 js switch (tag) { case 'iframe': case 'object': ...
  • 一、自定義函數function 函數就是功能、方法的封裝。函數能夠幫我們封裝一段程式代碼,這一段代碼會具備某一項功能,函數在執行時,封裝的這一段代碼都會執行一次,實現某種功能。而且,函數可以多次調用。 1.1函數的定義和調用 語法: 定義:把需要實現的功能預先做好 執行:需要的時候執行這個功能,而且 ...
  • transform 變形屬性屬性:translate 平移,rotate 旋轉, scale 縮放,skew 傾斜 ◆ translate :指定對象的2D平移第一個參數對應X軸,第二參數對應Y軸;如果第二個參數未提供,則預設為0;translate(10px,10px)X軸 往左邊移動 對應第一個 ...
  • 頭部... 內容內容內容內容內容內容 底部。。。 .HolyGrail { display: flex; min-height: 100vh; flex-direction: column; } header, footer { height:80px; line-height: 80px; tex... ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...