[譯] 優化 WEBPACK 以更快地構建 REACT

Starrier發表於2019-03-02
[譯] 優化 WEBPACK 以更快地構建 REACT

如果您的 Webpack 構建緩慢且有大量的庫 —— 別擔心,有一種方法可以提高增量構建的速度!Webpack 的 DLLPlugin 允許您將所有的依賴項構建到一個檔案中。這是一個取代分塊的很好選擇。該檔案稍後將由您的主 Webpack 配置,甚至可以在共享同一組依賴項的其他專案上使用。典型的 React 應用程式可能包含幾十個供應商庫,這取決於您的 Flux、外掛、路由和其他工具(如 lodash)。我們將通過允許 Webpack 跳過 DLL 中包含的任何引用來節省寶貴的構建時間。

本文假設您已經熟悉典型的 Webpack 和 React 設定。如果沒有,請檢視 SurviveJS 在 Webpack 和 React 方面的優秀內容,當您的構建時間逐步增加時,請回到本文。

第 1 步,列出您的供應商

構建和維護 DLL 的最簡單的方法是在您的專案中建立一個 JS 檔案 —— vendors.js,其中引入您使用的所有庫。例如,在我們最近的專案中,我們的 vendors.js 檔案內容如下:

require("classnames");
require("dom-css");
require("lodash");
require("react");
require("react-addons-update");
require("react-addons-pure-render-mixin");
require("react-dom");
require("react-redux");
require("react-router");
require("redux");
require("redux-saga");
require("redux-simple-router");
require("redux-storage");
require("redux-undo");
複製程式碼

這是我們將要“構建”的 DLL 檔案,它沒有任何功能,只是匯入我們使用的庫。

注意: 您也可以在這裡使用 ES6 風格的 import,但是我們需要用 Bable 來構建 DLL。您仍然可以像您習慣的那樣,在您的主專案中使用 import 和其他所有 ES2015 語法糖。

第 2 步,構建 DLL

現在我們可以建立一個 Webpack 配置來構建 DLL。這將從您的應用程式主 Webpack 配置中完全分離,並且會影響部分檔案。它不會被您的 Webpack 中介軟體、Webpack 伺服器或其他任何東西呼叫(手動或通過預構建除外)。

我們稱之為 webpack.dll.js

var path = require("path");
var webpack = require("webpack");

module.exports = {
    entry: {
        vendor: [path.join(__dirname, "client", "vendors.js")]
    },
    output: {
        path: path.join(__dirname, "dist", "dll"),
        filename: "dll.[name].js",
        library: "[name]"
    },
    plugins: [
        new webpack.DllPlugin({
            path: path.join(__dirname, "dll", "[name]-manifest.json"),
            name: "[name]",
            context: path.resolve(__dirname, "client")
        }),
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin()
    ],
    resolve: {
        root: path.resolve(__dirname, "client"),
        modulesDirectories: ["node_modules"]
    }
};
複製程式碼

這是典型的 Webpack 配置,除了 webpack.DLLPlugin 以外,它包含 name、context 和 mainifest 路徑。mainifest 非常重要,它為其他 Webpack 配置提供了您到已經構建模組的對映。context 是客戶端原始碼的根,而 name 是入口的名稱,在本例中是“供應商”。繼續嘗試使用命令 webpack --config=webpack.dll.js 執行這個構建。最後,您應該得到一個包含模組的排列對映 —— dllvendor-manifest.json 已經包含了您所有供應商庫的精簡包 ——  distdlldll.vendor.js

第 3 步,構建專案

**注意:**下述示例不包含 sass、assets、或熱載入程式。如果您已經在配置中使用了,它們仍然可以正常工作。

現在我們需要做的就是新增 DLLReferencePlugin,並將其指向我們已經構建的 DLL。您的 webpack.dev.js 可能是如下模樣:

var path = require("path");
var webpack = require("webpack");

module.exports = {
    cache: true,
    devtool: "eval", //or cheap-module-eval-source-map
    entry: {
        app: path.join(__dirname, "client", "index.js")
    },
    output: {
        path: path.join(__dirname, "dist"),
        filename: "[name].js",
        chunkFilename: "[name].js"
    },
    plugins: [
        //Typically you`d have plenty of other plugins here as well
        new webpack.DllReferencePlugin({
            context: path.join(__dirname, "client"),
            manifest: require("./dll/vendor-manifest.json")
        }),
    ],
    module: {
        loaders: [
            {
                test: /.jsx?$/,
                loader: "babel",
                include: [
                    path.join(__dirname, "client") //important for performance!
                ],
                query: {
                    cacheDirectory: true, //important for performance
                    plugins: ["transform-regenerator"],
                    presets: ["react", "es2015", "stage-0"]
                }
            }
        ]
    },
    resolve: {
        extensions: ["", ".js", ".jsx"],
        root: path.resolve(__dirname, "client"),
        modulesDirectories: ["node_modules"]
    }
};
複製程式碼

我們還做了一些其他事來提高效能,包括:

  • 確保我們有 cache: true
  • 確保 Babel 在查詢中載入程式有 cacheDirectory:true
  • 在 bable loader 中使用 include(您應該在所有的 loader 中這樣做)
  • 將 devTool 設定為 eval,因為我們正在為構建時間優化 #nobugs

第 4 步,包含 DLL

此時,您已經生成了一個供應商 DLL 檔案,並且您的 Webpack 構建並生成 app.js 檔案。您需要在模版中提供幷包含這兩個檔案,但 DLL 應該是第一位的。您可能已經使用 HtmlWebpackPlugin 設定了模版。因為我們不關心熱過載 DLL,所以除了在主 app.js 之前包含 <script src="dll/dll.vendor.js"></script> 之外,您實際上不需要做任何事。如果您使用的是 webpack-middleware 或者您自己定製化的伺服器,則還需要確保為 DLL 提供服務。此時,一切都應該按原樣執行,但是使用 Webpack 進行增量構建的速度應該非常快。

第 5 步,構建指令碼

我們可以使用 NPM 和 package.json 新增一些為我們構建的簡單指令碼。要清除 dist 資料夾,請繼續執行 npm i rimraf --saveDev。現在可以新增到您的 package.json 中了:

"scripts": {
    "clean": "rimraf dist",
    "build:webpack": "webpack --config config.prod.js",
    "build:dll": "webpack --config config.dll.js",
    "build": "npm run clean && npm run build:dll && npm run build:webpack",
    "watch": "npm run build:dll && webpack --config config.dev.js --watch --progress"
  }
複製程式碼

現在您可以執行 npm run watch。如果您喜歡手動執行 build:dll,則可以將其從監視指令碼中刪除,以便更快地啟動。

就這樣,夥計們!

我希望這能讓您深入瞭解 InVision 如何使用 Webpack 的 DLLPlugin 來提高構建速度。如果您有任何問題或想法,歡迎發表評論。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章