Webpack實戰 - 使用動態 entry 改善調試體驗

本文相關代碼已經存放在 dynamic-entry,可自行下載使用html

0. 多入口 (複習)

webpack 的優點不言而喻,所以在實際應用中咱們也經常使用它調試 多入口 應用,所謂 多入口 是指多個HTML頁面會使用多個入口文件,在官方教程 MULTIPLE ENTRY POINTS 介紹瞭如何配置:node

{
    entry: {
        a: "./a",
        b: "./b",
        c: ["./c", "./d"]
    },
    output: {
        path: path.join(__dirname, "dist"),
        filename: "[name].entry.js"
    }
}

這裏指定了 3 個入口文件,打包以後分別會在 dist 文件夾中生成 3 個打包以後的 js 文件:a.entry.jsb.entry.jsc.entry.js,可被至少 3 個不一樣的 HTML 頁面直接引用;webpack

上述是最基本的使用,實際中還可使用 multiple-commons-chunks 等提升打包的速度、性能;git

1. 動態 entry 的場景

像上面那樣直接應用 Webpack 的多入口功能,在普通的工程項目中並不存在什麼問題,還簡單高效;github

然而若是你使用 Webpack 構建較大型的頁面系統,遂着業務的擴大,入口的數量會逐漸增多,縱使每一個入口文件都很小,在調試的時候等全部的入口文件都 ready 所耗費的時間也是很是巨大的,讓用戶等待過久顯然很不友好web

用戶等待時間隨着模塊數量而線性增長(見下圖):express

等待時間隨着模塊數量的增長而線性增長

假設業務模塊有100個,而當前本身僅僅須要調試 A 模塊,若是使用默認的多模塊入口方式,用戶 必須等這100個模塊啓動以後才能調試 A 模塊,很明顯這會讓用戶抓狂;npm

比較合理的作法是,不管當前用戶模塊目錄下有多少個模塊,默認都只其構建一個模塊,當用戶想要調試另一個模塊的時候,再動態添加一個 entry 到 webpack 系統中,這就減小了用戶等待的時間,提升了調試時的用戶體驗微信

使用動態entry

2. 實現動態 entry 的原理

目前業界並無現成的動態 entry 方案,須要本身分析 webpack 源碼找到解決方案;(若是不清楚 webpack 流程的,能夠參考 @七珏 同窗的 細說webpack之流程篇app

2.一、先分析 webpack 源碼中處理單入口的 entry 狀況,在 WebpackOptionsApply.js 有:

WebpackOptionsApply

  • 這裏首先是加載 EntryOptionPlugin.js 而後觸發添加 entry 入口
  • 而後觸發 entry-option 事件節點,將 contextentry 做爲參數傳入

2.二、 繼續看 EntryOptionPlugin.js 文件,在 entry-option 事件節點中調用 SingleEntryPlugin 構造函數構建單入口模塊:

構建單入口模塊


咱們能夠依樣畫葫蘆,利用官方的 SingleEntryPlugin 的對象來完成動態添加入口的功能。

  1. 咱們像日常那樣建立單入口文件配置文件
  2. 依據 webpack(config) 獲取 compiler 實例;
  3. 而後調用 compiler.apply(new SingleEntryPlugin(process.cwd(),...); 新增一個構建入口
  4. 通知 webpack 讓新入口生效

3. 示例

本節的代碼放在倉庫 dynamic-entry 中,能夠到下載獲取

這裏咱們以 express 框架爲例,講解如何實現動態 entry ;具體操做步驟以下:

  1. 下載 dynamic-entry 代碼:git clone https://github.com/boycgit/dynamic-entry
  2. cd dynamic-entry && npm install && node server.js
  3. 啓動 web 服務(可訪問 http://localhost:3000 ),默認只會構建一個 src/index1.js

默認構建單個

  1. 而後訪問 http://localhost:3000/add,再去看命令行,你會發現如今會構建 src/index1.jssrc/index2.js 這兩個文件,這就是所謂的動態 entry

動態entry

簡要分析一下源碼,在 server.js 中:

...
var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
var webpackDevMiddleware = require('webpack-dev-middleware');

...

var webpackDevMiddlewareInstance = webpackDevMiddleware(compiler, webpackDevMiddlewareParam);
app.use(webpackDevMiddlewareInstance); // 應用針對 express 框架的 webpack 調試中間件

...

var once = true;
// 新增入口
app.get('/add', function(req, res) {
  // 應用單入口插件
  console.log('apply SingleEntryPlugin');
  compiler.apply(new SingleEntryPlugin(process.cwd(), './src/index2.js','index2'));
  once && webpackDevMiddlewareInstance.invalidate(); // 強制從新構建一次,不用調用屢次,後續的觸發由webpack本身 hot reload
  once = false; // 置 once 就是 false
  res.send('already apply SingleEntryPlugin');
});
  • 這裏用到了 webpack-dev-middleware 模塊,是 webpack 調試用的 express 中間件,它提供調試時候將構建的文件輸出到文件系統,可讓用戶訪問獲取;
  • 註冊 /add 路由,當用戶訪問此頁面的時候會調用 compiler.apply 新增一個構建入口
  • 調用 webpackDevMiddlewareInstance.invalidate() 強制 webpack 從新構建一次,這個方法只須要調用1次(所以這兒由 once 變量進行控制),後續的觸發由webpack本身 hot reload

從上面的過程可見,動態 entry 實施的過程是借鑑 webpack 自身的 SingleEntryPlugin 插件進行的,在可靠性方面有很大的保障;其他的代碼則是借用現有的 express 中間件獲取所須要的 compiler 等對象協助此過程;

4. 總結

目前動態 entry 以後已經運用在若干個內部構建器中,在應用動態 entry 以後,明顯地改善了用戶體驗;

此篇文章但願能給有相似場景的同窗提供幫助;

5. 參考文章

下面的是個人公衆號二維碼圖片,歡迎關注。
我的微信公衆號

相關文章
相關標籤/搜索