主頁 > 知識庫 > 加速Webpack構(gòu)建技巧總結(jié)

加速Webpack構(gòu)建技巧總結(jié)

熱門標(biāo)簽:福州外呼系統(tǒng)中間件 威海人工智能電銷機(jī)器人系統(tǒng) 上海電銷卡外呼系統(tǒng)廠家 德州外呼系統(tǒng)排名 機(jī)器人電銷有什么用 貴州全自動(dòng)外呼系統(tǒng)廠家 好看的地圖標(biāo)注圖標(biāo)下載 地圖標(biāo)注員怎么去做 百度地圖標(biāo)注備注

Web 應(yīng)用日益復(fù)雜,相關(guān)開發(fā)技術(shù)也百花齊放,這對前端構(gòu)建工具提出了更高的要求。 Webpack 從眾多構(gòu)建工具中脫穎而出成為目前最流行的構(gòu)建工具,幾乎成為目前前端開發(fā)里的必備工具之一。 大多數(shù)人在使用 Webpack 的過程中都會遇到構(gòu)建速度慢的問題,在項(xiàng)目大時(shí)顯得尤為突出,這極大的影響了我們的開發(fā)體驗(yàn),降低了我們的開發(fā)效率。

本文將傳授你一些加速 Webpack 構(gòu)建的技巧,下面來一一介紹。

通過多進(jìn)程并行處理

由于有大量文件需要解析和處理,構(gòu)建是文件讀寫和計(jì)算密集型的操作,特別是當(dāng)文件數(shù)量變多后,Webpack 構(gòu)建慢的問題會顯得嚴(yán)重。 運(yùn)行在 Node.js 之上的 Webpack 是單線程模型的,也就是說 Webpack 需要處理的任務(wù)需要一件件挨著做,不能多個(gè)事情一起做。

文件讀寫和計(jì)算操作是無法避免的,那能不能讓 Webpack 同一時(shí)刻處理多個(gè)任務(wù),發(fā)揮多核 CPU 電腦的威力,以提升構(gòu)建速度呢?

使用 HappyPack

HappyPack 就能讓 Webpack 做到上面拋出的問題,它把任務(wù)分解給多個(gè)子進(jìn)程去并發(fā)的執(zhí)行,子進(jìn)程處理完后再把結(jié)果發(fā)送給主進(jìn)程。

接入 HappyPack 的相關(guān)代碼如下:

const path = require('path');
  const ExtractTextPlugin = require('extract-text-webpack-plugin');
  const HappyPack = require('happypack');
  module.exports = { 
    module: { 
      rules: [ 
        {  test: /\.js$/, 
          // 把對 .js 文件的處理轉(zhuǎn)交給 id 為 babel 的 HappyPack 實(shí)例 
          use:['happypack/loader?id=babel'], 
          // 排除 node_modules 目錄下的文件,node_modules目錄下的文件都是采用的 ES5 語法,沒必要再通過 Babel 去轉(zhuǎn)換 
          exclude: path.resolve(__dirname, 'node_modules'),
         }, 
        { 
          // 把對 .css 文件的處理轉(zhuǎn)交給 id 為 css 的 HappyPack 實(shí)例
           test: /\.css$/, 
           use:ExtractTextPlugin.extract({ 
            use: ['happypack/loader?id=css'],
       }), 
    }, 
] },
  plugins: [ 
    new HappyPack({ 
      // 用唯一的標(biāo)識符 id 來代表當(dāng)前的HappyPack 是用來處理一類特定的文件 
    id: 'babel', 
      // 如何處理 .js 文件,用法和 Loader配置中一樣 
    loaders: ['babel-loader?cacheDirectory'],
   }),
    new HappyPack({ 
        id: 'css', 
          // 如何處理 .css 文件,用法和Loader 配置中一樣 
        loaders: ['css-loader'], }), 
        new ExtractTextPlugin({ 
          filename: `[name].css`, 
      }), 
    ],
  };

以上代碼有兩點(diǎn)重要的修改:

在 Loader 配置中,所有文件的處理都交給了 happypack/loader 去處理,使用緊跟其后的 querystring ?id=babel 去告訴 happypack/loader 去選擇哪個(gè) HappyPack 實(shí)例去處理文件。
在 Plugin 配置中,新增了兩個(gè) HappyPack 實(shí)例分別用于告訴 happypack/loader 去如何處理 .js 和 .css 文件。選項(xiàng)中的 id 屬性的值和上面 querystring 中的 ?id=babel 相對應(yīng),選項(xiàng)中的 loaders 屬性和 Loader 配置中一樣。
接入 HappyPack 后,你需要給項(xiàng)目安裝新的依賴:

npm i -D happypack

安裝成功后重新執(zhí)行構(gòu)建,你就會看到以下由 HappyPack 輸出的日志:

Happy[babel]: Version: 4.0.0-beta.5. Threads: 3
Happy[babel]: All set; signaling webpack to proceed.Happy[css]: Version: 4.0.0-beta.5. Threads: 3Happy[css]: All set; signaling webpack to proceed.

說明你的 HappyPack 配置生效了,并且可以得知 HappyPack 分別啟動(dòng)了3個(gè)子進(jìn)程去并行的處理任務(wù)。

在整個(gè) Webpack 構(gòu)建流程中,最耗時(shí)的流程可能就是 Loader 對文件的轉(zhuǎn)換操作了,因?yàn)橐D(zhuǎn)換的文件數(shù)據(jù)巨多,而且這些轉(zhuǎn)換操作都只能一個(gè)個(gè)挨著處理。 HappyPack 的核心原理就是把這部分任務(wù)分解到多個(gè)進(jìn)程去并行處理,從而減少了總的構(gòu)建時(shí)間。

從前面的使用中可以看出所有需要通過 Loader 處理的文件都先交給了 happypack/loader 去處理,收集到了這些文件的處理權(quán)后 HappyPack 就好統(tǒng)一分配了。

每通過 new HappyPack() 實(shí)例化一個(gè) HappyPack 其實(shí)就是告訴 HappyPack 核心調(diào)度器如何通過一系列 Loader 去轉(zhuǎn)換一類文件,并且可以指定如何給這類轉(zhuǎn)換操作分配子進(jìn)程。

核心調(diào)度器的邏輯代碼在主進(jìn)程中,也就是運(yùn)行著 Webpack 的進(jìn)程中,核心調(diào)度器會把一個(gè)個(gè)任務(wù)分配給當(dāng)前空閑的子進(jìn)程,子進(jìn)程處理完畢后把結(jié)果發(fā)送給核心調(diào)度器,它們之間的數(shù)據(jù)交換是通過進(jìn)程間通信 API 實(shí)現(xiàn)的。

核心調(diào)度器收到來自子進(jìn)程處理完畢的結(jié)果后會通知 Webpack 該文件處理完畢。

使用 ParallelUglifyPlugin

在使用 Webpack 構(gòu)建出用于發(fā)布到線上的代碼時(shí),都會有壓縮代碼這一流程。 最常見的 JavaScript 代碼壓縮工具是 UglifyJS,并且 Webpack 也內(nèi)置了它。

用過 UglifyJS 的你一定會發(fā)現(xiàn)在構(gòu)建用于開發(fā)環(huán)境的代碼時(shí)很快就能完成,但在構(gòu)建用于線上的代碼時(shí)構(gòu)建一直卡在一個(gè)時(shí)間點(diǎn)遲遲沒有反應(yīng),其實(shí)卡住的這個(gè)時(shí)候就是在進(jìn)行代碼壓縮。

由于壓縮 JavaScript 代碼需要先把代碼解析成用 Object 抽象表示的 AST 語法樹,再去應(yīng)用各種規(guī)則分析和處理 AST,導(dǎo)致這個(gè)過程計(jì)算量巨大,耗時(shí)非常多。

為什么不把多進(jìn)程并行處理的思想也引入到代碼壓縮中呢?

ParallelUglifyPlugin 就做了這個(gè)事情。 當(dāng) Webpack 有多個(gè) JavaScript 文件需要輸出和壓縮時(shí),原本會使用 UglifyJS 去一個(gè)個(gè)挨著壓縮再輸出, 但是 ParallelUglifyPlugin 則會開啟多個(gè)子進(jìn)程,把對多個(gè)文件的壓縮工作分配給多個(gè)子進(jìn)程去完成,每個(gè)子進(jìn)程其實(shí)還是通過 UglifyJS 去壓縮代碼,但是變成了并行執(zhí)行。 所以 ParallelUglifyPlugin 能更快的完成對多個(gè)文件的壓縮工作。

使用 ParallelUglifyPlugin 也非常簡單,把原來 Webpack 配置文件中內(nèi)置的 UglifyJsPlugin 去掉后,再替換成 ParallelUglifyPlugin,相關(guān)代碼如下:

const path = require('path');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
module.exports = { 
    plugins: [ 
      // 使用 ParallelUglifyPlugin 并行壓縮輸出的 JS 代碼
      new ParallelUglifyPlugin({ 
        // 傳遞給 UglifyJS 的參數(shù)
        uglifyJS: {
         }, 
      }), 
    ],
  };

接入 ParallelUglifyPlugin 后,項(xiàng)目需要安裝新的依賴:

npm i -D webpack-parallel-uglify-plugin

安裝成功后,重新執(zhí)行構(gòu)建你會發(fā)現(xiàn)速度變快了許多。如果設(shè)置 cacheDir 開啟了緩存,在之后的構(gòu)建中會變的更快。

縮小文件搜索范圍

Webpack 啟動(dòng)后會從配置的 Entry 出發(fā),解析出文件中的導(dǎo)入語句,再遞歸的解析。 在遇到導(dǎo)入語句時(shí) Webpack 會做兩件事情:

根據(jù)導(dǎo)入語句去尋找對應(yīng)的要導(dǎo)入的文件。例如 require(‘react') 導(dǎo)入語句對應(yīng)的文件是 ./node_modules/react/react.js,而require(‘./util')導(dǎo)入語句 對應(yīng)的文件是 ./util.js。
根據(jù)找到的要導(dǎo)入文件的后綴,使用配置中的 Loader 去處理文件。例如使用 ES6 開發(fā)的 JavaScript 文件需要使用 babel-loader 去處理。
以上兩件事情雖然對于處理一個(gè)文件非???,但是當(dāng)項(xiàng)目大了以后文件量會變的非常多,這時(shí)候構(gòu)建速度慢的問題就會暴露出來。 雖然以上兩件事情無法避免,但需要盡量減少以上兩件事情的發(fā)生,以提高速度。

接下來一一介紹可以優(yōu)化它們的途徑。

縮小 resolve.modules 的范圍

Webpack的resolve.modules 用于配置 Webpack 去哪些目錄下尋找第三方模塊。

resolve.modules 的默認(rèn)值是 [‘node_modules'],含義是先去當(dāng)前目錄下的 ./node_modules 目錄下去找想找的模塊,如果沒找到就去上一級目錄 ../node_modules 中找,再沒有就去 ../../node_modules 中找,以此類推,這和 Node.js 的模塊尋找機(jī)制很相似。

當(dāng)安裝的第三方模塊都放在項(xiàng)目根目錄下的 ./node_modules 目錄下時(shí),沒有必要按照默認(rèn)的方式去一層層的尋找,可以指明存放第三方模塊的絕對路徑,以減少尋找,配置如下:

module.exports = {
      resolve: {
        // 使用絕對路徑指明第三方模塊存放的位置,以減少搜索步驟
        // 其中 __dirname 表示當(dāng)前工作目錄,也就是項(xiàng)目根目錄
        modules: [path.resolve(__dirname, 'node_modules')]
     },
};

縮小 Loader 的命中范圍

除此之外在使用 Loader 時(shí)可以通過 test 、 include 、 exclude 三個(gè)配置項(xiàng)來命中 Loader 要應(yīng)用規(guī)則的文件。 為了盡可能少的讓文件被 Loader 處理,可以通過 include 去命中只有哪些文件需要被處理。

以采用 ES6 的項(xiàng)目為例,在配置 babel-loader 時(shí),可以這樣:

module.exports = {
 module: {
  rules: [
   {
    // 如果項(xiàng)目源碼中只有 js 文件就不要寫成 /\.jsx?$/,提升正則表達(dá)式性能
    test: /\.js$/,
    // babel-loader 支持緩存轉(zhuǎn)換出的結(jié)果,通過 cacheDirectory 選項(xiàng)開啟
    use: ['babel-loader?cacheDirectory'],
    // 只對項(xiàng)目根目錄下的 src 目錄中的文件采用 babel-loader
    include: path.resolve(__dirname, 'src'),
   },
  ]
 },
};

你可以適當(dāng)?shù)恼{(diào)整項(xiàng)目的目錄結(jié)構(gòu),以方便在配置 Loader 時(shí)通過 include 去縮小命中范圍。

縮小 resolve.extensions 的數(shù)量
在導(dǎo)入語句沒帶文件后綴時(shí),Webpack 會自動(dòng)帶上后綴后去嘗試詢問文件是否存在。 Webpack 配置中的 resolve.extensions 用于配置在嘗試過程中用到的后綴列表,默認(rèn)是:

extensions: ['.js', '.json']

也就是說當(dāng)遇到 require(‘./data') 這樣的導(dǎo)入語句時(shí),Webpack 會先去尋找 ./data.js 文件,如果該文件不存在就去尋找 ./data.json 文件,如果還是找不到就報(bào)錯(cuò)。

如果這個(gè)列表越長,或者正確的后綴在越后面,就會造成嘗試的次數(shù)越多,所以 resolve.extensions 的配置也會影響到構(gòu)建的性能。 在配置 resolve.extensions 時(shí)你需要遵守以下幾點(diǎn),以做到盡可能的優(yōu)化構(gòu)建性能:

后綴嘗試列表要盡可能的小,不要把項(xiàng)目中不可能存在的情況寫到后綴嘗試列表中。
頻率出現(xiàn)最高的文件后綴要優(yōu)先放在最前面,以做到盡快的退出尋找過程。
在源碼中寫導(dǎo)入語句時(shí),要盡可能的帶上后綴,從而可以避免尋找過程。例如在你確定的情況下把 require(‘./data') 寫成 require(‘./data.json')。
相關(guān) Webpack 配置如下:

module.exports = {
 resolve: {
  // 盡可能的減少后綴嘗試的可能性
  extensions: ['js'],
 },
};

縮小 resolve.mainFields 的數(shù)量

Webpack 配置中的 resolve.mainFields 用于配置第三方模塊使用哪個(gè)入口文件。

安裝的第三方模塊中都會有一個(gè) package.json 文件用于描述這個(gè)模塊的屬性,其中有些字段用于描述入口文件在哪里,resolve.mainFields 用于配置采用哪個(gè)字段作為入口文件的描述。

可以存在多個(gè)字段描述入口文件的原因是因?yàn)橛行┠K可以同時(shí)用在多個(gè)環(huán)境中,針對不同的運(yùn)行環(huán)境需要使用不同的代碼。 以 isomorphic-fetchfetch API 為例,它是 的一個(gè)實(shí)現(xiàn),但可同時(shí)用于瀏覽器和 Node.js 環(huán)境。

為了減少搜索步驟,在你明確第三方模塊的入口文件描述字段時(shí),你可以把它設(shè)置的盡量少。 由于大多數(shù)第三方模塊都采用 main 字段去描述入口文件的位置,可以這樣配置 Webpack:

module.exports = {
 resolve: {
  // 只采用 main 字段作為入口文件描述字段,以減少搜索步驟
  mainFields: ['main'],
 },
};

使用本方法優(yōu)化時(shí),你需要考慮到所有運(yùn)行時(shí)依賴的第三方模塊的入口文件描述字段,就算有一個(gè)模塊搞錯(cuò)了都可能會造成構(gòu)建出的代碼無法正常運(yùn)行。

善用現(xiàn)存的文件

通過 module.noParse 忽略文件

Webpack 配置中的 module.noParse 配置項(xiàng)可以讓 Webpack 忽略對部分沒采用模塊化的文件的遞歸解析處理,這樣做的好處是能提高構(gòu)建性能。 原因是一些庫,例如 jQuery 、ChartJS, 它們龐大又沒有采用模塊化標(biāo)準(zhǔn),讓 Webpack 去解析這些文件耗時(shí)又沒有意義。

在上面的 優(yōu)化 resolve.alias 配置 中講到單獨(dú)完整的 react.min.js 文件就沒有采用模塊化,讓我們來通過配置 module.noParse 忽略對 react.min.js 文件的遞歸解析處理, 相關(guān) Webpack 配置如下:

module.exports = {
 module: {
  // 獨(dú)完整的 `react.min.js` 文件就沒有采用模塊化,忽略對 `react.min.js` 文件的遞歸解析處理
  noParse: [/react\.min\.js$/],
 },
};

注意被忽略掉的文件里不應(yīng)該包含 import 、 require 、 define 等模塊化語句,不然會導(dǎo)致構(gòu)建出的代碼中包含無法在瀏覽器環(huán)境下執(zhí)行的模塊化語句。

通過 resolve.alias 映射文件

Webpack 配置中的 resolve.alias 配置項(xiàng)通過別名來把原導(dǎo)入路徑映射成一個(gè)新的導(dǎo)入路徑。

在實(shí)戰(zhàn)項(xiàng)目中經(jīng)常會依賴一些龐大的第三方模塊,以 React 庫為例,庫中包含兩套代碼:

一套是采用 CommonJS 規(guī)范的模塊化代碼,這些文件都放在 lib 目錄下,以 package.json 中指定的入口文件 react.js 為模塊的入口。
一套是把 React 所有相關(guān)的代碼打包好的完整代碼放到一個(gè)單獨(dú)的文件中,這些代碼沒有采用模塊化可以直接執(zhí)行。其中 dist/react.js 是用于開發(fā)環(huán)境,里面包含檢查和警告的代碼。dist/react.min.js 是用于線上環(huán)境,被最小化了。
默認(rèn)情況下 Webpack 會從入口文件 ./node_modules/react/react.js 開始遞歸的解析和處理依賴的幾十個(gè)文件,這會時(shí)一個(gè)耗時(shí)的操作。 通過配置 resolve.alias 可以讓 Webpack 在處理 React 庫時(shí),直接使用單獨(dú)完整的 react.min.js 文件,從而跳過耗時(shí)的遞歸解析操作。

相關(guān) Webpack 配置如下:

module.exports = {
 resolve: {
  // 使用 alias 把導(dǎo)入 react 的語句換成直接使用單獨(dú)完整的 react.min.js 文件,
  // 減少耗時(shí)的遞歸解析操作
  alias: {
   'react': path.resolve(__dirname, './node_modules/react/dist/react.min.js'),
  }
 },
};

除了 React 庫外,大多數(shù)庫發(fā)布到 Npm 倉庫中時(shí)都會包含打包好的完整文件,對于這些庫你也可以對它們配置 alias。

但是對于有些庫使用本優(yōu)化方法后會影響到后面要講的使用 Tree-Shaking 去除無效代碼的優(yōu)化,因?yàn)榇虬玫耐暾募杏胁糠执a你的項(xiàng)目可能永遠(yuǎn)用不上。 一般對整體性比較強(qiáng)的庫采用本方法優(yōu)化,因?yàn)橥暾募械拇a是一個(gè)整體,每一行都是不可或缺的。 但是對于一些工具類的庫,例如 lodash,你的項(xiàng)目可能只用到了其中幾個(gè)工具函數(shù),你就不能使用本方法去優(yōu)化,因?yàn)檫@會導(dǎo)致你的輸出代碼中包含很多永遠(yuǎn)不會執(zhí)行的代碼。

使用 DllPlugin

在介紹 DllPlugin 前先給大家介紹下 DLL。 用過 Windows 系統(tǒng)的人應(yīng)該會經(jīng)常看到以 .dll 為后綴的文件,這些文件稱為動(dòng)態(tài)鏈接庫,在一個(gè)動(dòng)態(tài)鏈接庫中可以包含給其他模塊調(diào)用的函數(shù)和數(shù)據(jù)。

要給 Web 項(xiàng)目構(gòu)建接入動(dòng)態(tài)鏈接庫的思想,需要完成以下事情:

把網(wǎng)頁依賴的基礎(chǔ)模塊抽離出來,打包到一個(gè)個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫中去。一個(gè)動(dòng)態(tài)鏈接庫中可以包含多個(gè)模塊。
當(dāng)需要導(dǎo)入的模塊存在于某個(gè)動(dòng)態(tài)鏈接庫中時(shí),這個(gè)模塊不能再次被打包,而是去動(dòng)態(tài)鏈接庫中獲取。
頁面依賴的所有動(dòng)態(tài)鏈接庫需要被加載。
為什么給 Web 項(xiàng)目構(gòu)建接入動(dòng)態(tài)鏈接庫的思想后,會大大提升構(gòu)建速度呢? 原因在于包含大量復(fù)用模塊的動(dòng)態(tài)鏈接庫只需要編譯一次,在之后的構(gòu)建過程中被動(dòng)態(tài)鏈接庫包含的模塊將不會在重新編譯,而是直接使用動(dòng)態(tài)鏈接庫中的代碼。 由于動(dòng)態(tài)鏈接庫中大多數(shù)包含的是常用的第三方模塊,例如 react、react-dom,只要不升級這些模塊的版本,動(dòng)態(tài)鏈接庫就不用重新編譯。

接入 Webpack

Webpack 已經(jīng)內(nèi)置了對動(dòng)態(tài)鏈接庫的支持,需要通過2個(gè)內(nèi)置的插件接入,它們分別是:

DllPlugin 插件:用于打包出一個(gè)個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫文件。
DllReferencePlugin 插件:用于在主要配置文件中去引入 DllPlugin 插件打包好的動(dòng)態(tài)鏈接庫文件。
下面以基本的 React 項(xiàng)目為例,為其接入 DllPlugin,在開始前先來看下最終構(gòu)建出的目錄結(jié)構(gòu):

├── main.js
├── polyfill.dll.js
├── polyfill.manifest.json
├── react.dll.js
└── react.manifest.json

其中包含兩個(gè)動(dòng)態(tài)鏈接庫文件,分別是:

polyfill.dll.js 里面包含項(xiàng)目所有依賴的 polyfill,例如 Promise、fetch 等 API。
react.dll.js 里面包含 React 的基礎(chǔ)運(yùn)行環(huán)境,也就是 react 和 react-dom 模塊。
以 react.dll.js 文件為例,其文件內(nèi)容大致如下:

var _dll_react = (function(modules) {
 // ... 此處省略 webpackBootstrap 函數(shù)代碼
}([
 function(module, exports, __webpack_require__) {
  // 模塊 ID 為 0 的模塊對應(yīng)的代碼
 }
 // ... 此處省略剩下的模塊對應(yīng)的代碼 
]));

可見一個(gè)動(dòng)態(tài)鏈接庫文件中包含了大量模塊的代碼,這些模塊存放在一個(gè)數(shù)組里,用數(shù)組的索引號作為 ID。 并且還通過 _dll_react 變量把自己暴露在了全局中,也就是可以通過 window._dll_react 可以訪問到它里面包含的模塊。

其中 polyfill.manifest.json 和 react.manifest.json 文件也是由 DllPlugin 生成,用于描述動(dòng)態(tài)鏈接庫文件中包含哪些模塊, 以 react.manifest.json 文件為例,其文件內(nèi)容大致如下:

{
 // 描述該動(dòng)態(tài)鏈接庫文件暴露在全局的變量名稱
 "name": "_dll_react",
 "content": {
  "./node_modules/process/browser.js": {
   "id": 0,
   "meta": {}
  },
  // ... 此處省略部分模塊
 }
}

可見 manifest.json 文件清楚地描述了與其對應(yīng)的 dll.js 文件中包含了哪些模塊,以及每個(gè)模塊的路徑和 ID。

main.js 文件是編譯出來的執(zhí)行入口文件,當(dāng)遇到其依賴的模塊在 dll.js 文件中時(shí),會直接通過 dll.js 文件暴露出的全局變量去獲取打包在 dll.js 文件的模塊。 所以在 index.html 文件中需要把依賴的兩個(gè) dll.js 文件給加載進(jìn)去,index.html 內(nèi)容如下:

<!--導(dǎo)入依賴的動(dòng)態(tài)鏈接庫文件-->
<script src="./dist/polyfill.dll.js"></script>
<script src="./dist/react.dll.js"></script>
<!--導(dǎo)入執(zhí)行入口文件-->
<script src="./dist/main.js"></script>

以上就是所有接入 DllPlugin 后最終編譯出來的代碼,接下來教你如何實(shí)現(xiàn)。

構(gòu)建出動(dòng)態(tài)鏈接庫文件
構(gòu)建輸出的以下這四個(gè)文件

├── polyfill.dll.js
├── polyfill.manifest.json
├── react.dll.js
└── react.manifest.json

和以下這一個(gè)文件

├── main.js

是由兩份不同的構(gòu)建分別輸出的。

與動(dòng)態(tài)鏈接庫相關(guān)的文件需要由一個(gè)獨(dú)立的構(gòu)建輸出,用于給主構(gòu)建使用。新建一個(gè) Webpack 配置文件 webpack_dll.config.js 專門用于構(gòu)建它們,文件內(nèi)容如下:

const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
 
module.exports = {
 // JS 執(zhí)行入口文件
 entry: {
  // 把 React 相關(guān)模塊的放到一個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫
  react: ['react', 'react-dom'],
  // 把項(xiàng)目需要所有的 polyfill 放到一個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫
  polyfill: ['core-js/fn/object/assign', 'core-js/fn/promise', 'whatwg-fetch'],
 },
 output: {
  // 輸出的動(dòng)態(tài)鏈接庫的文件名稱,[name] 代表當(dāng)前動(dòng)態(tài)鏈接庫的名稱,
  // 也就是 entry 中配置的 react 和 polyfill
  filename: '[name].dll.js',
  // 輸出的文件都放到 dist 目錄下
  path: path.resolve(__dirname, 'dist'),
  // 存放動(dòng)態(tài)鏈接庫的全局變量名稱,例如對應(yīng) react 來說就是 _dll_react
  // 之所以在前面加上 _dll_ 是為了防止全局變量沖突
  library: '_dll_[name]',
 },
 plugins: [
  // 接入 DllPlugin
  new DllPlugin({
   // 動(dòng)態(tài)鏈接庫的全局變量名稱,需要和 output.library 中保持一致
   // 該字段的值也就是輸出的 manifest.json 文件 中 name 字段的值
   // 例如 react.manifest.json 中就有 "name": "_dll_react"
   name: '_dll_[name]',
   // 描述動(dòng)態(tài)鏈接庫的 manifest.json 文件輸出時(shí)的文件名稱
   path: path.join(__dirname, 'dist', '[name].manifest.json'),
  }),
 ],
};

使用動(dòng)態(tài)鏈接庫文件

構(gòu)建出的動(dòng)態(tài)鏈接庫文件用于在其它地方使用,在這里也就是給執(zhí)行入口使用。

用于輸出 main.js 的主 Webpack 配置文件內(nèi)容如下:

const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
 
module.exports = {
 plugins: [
  // 告訴 Webpack 使用了哪些動(dòng)態(tài)鏈接庫
  new DllReferencePlugin({
   // 描述 react 動(dòng)態(tài)鏈接庫的文件內(nèi)容
   manifest: require('./dist/react.manifest.json'),
  }),
  new DllReferencePlugin({
   // 描述 polyfill 動(dòng)態(tài)鏈接庫的文件內(nèi)容
   manifest: require('./dist/polyfill.manifest.json'),
  }),
 ],
 devtool: 'source-map'
};

注意:在 webpack_dll.config.js 文件中,DllPlugin 中的 name 參數(shù)必須和 output.library 中保持一致。 原因在于 DllPlugin 中的 name 參數(shù)會影響輸出的 manifest.json 文件中 name 字段的值, 而在 webpack.config.js 文件中 DllReferencePlugin 會去 manifest.json 文件讀取 name 字段的值, 把值的內(nèi)容作為在從全局變量中獲取動(dòng)態(tài)鏈接庫中內(nèi)容時(shí)的全局變量名。

執(zhí)行構(gòu)建

在修改好以上兩個(gè) Webpack 配置文件后,需要重新執(zhí)行構(gòu)建。 重新執(zhí)行構(gòu)建時(shí)要注意的是需要先把動(dòng)態(tài)鏈接庫相關(guān)的文件編譯出來,因?yàn)橹?Webpack 配置文件中定義的 DllReferencePlugin 依賴這些文件。

執(zhí)行構(gòu)建時(shí)流程如下:

如果動(dòng)態(tài)鏈接庫相關(guān)的文件還沒有編譯出來,就需要先把它們編譯出來。方法是執(zhí)行 webpack –config webpack_dll.config.js 命令。

在確保動(dòng)態(tài)鏈接庫存在的前提下,才能正常的編譯出入口執(zhí)行文件。方法是執(zhí)行 webpack 命令。這時(shí)你會發(fā)現(xiàn)構(gòu)建速度有了非常大的提升。

相信給你的項(xiàng)目加上以上優(yōu)化方法后,構(gòu)建速度會大大提高,趕快去試試把!

標(biāo)簽:葫蘆島 南陽 白城 撫州 邵陽 泉州 岳陽 南陽

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《加速Webpack構(gòu)建技巧總結(jié)》,本文關(guān)鍵詞  加速,Webpack,構(gòu)建,技巧,總結(jié),;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《加速Webpack構(gòu)建技巧總結(jié)》相關(guān)的同類信息!
  • 本頁收集關(guān)于加速Webpack構(gòu)建技巧總結(jié)的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章