Webpack 啟動后會從配置的 Entry 出發(fā),解析出文件中的導(dǎo)入語句,再遞歸的解析。
在遇到導(dǎo)入語句時 Webpack 會做兩件事情:
1.根據(jù)導(dǎo)入語句去尋找對應(yīng)的要導(dǎo)入的文件。例如 require('react') 導(dǎo)入語句對應(yīng)的文件是 ./node_modules/react/react.js , require('./util') 對應(yīng)的文件是 ./util.js 。
2.根據(jù)找到的要導(dǎo)入文件的后綴,使用配置中的 Loader 去處理文件。例如使用 ES6 開發(fā)的 JavaScript 文件需要使用 babel-loader 去處理。
以上兩件事情雖然對于處理一個文件非??欤钱?dāng)項目大了以后文件量會變的非常多,這時候構(gòu)建速度慢的問題就會暴露出來。
雖然以上兩件事情無法避免,但需要盡量減少以上兩件事情的發(fā)生,以提高速度。
接下來一一介紹可以優(yōu)化它們的途徑。
優(yōu)化 loader 配置
由于 Loader 對文件的轉(zhuǎn)換操作很耗時,需要讓盡可能少的文件被 Loader 處理。
在 2-3 Module 中介紹過在使用 Loader 時可以通過 test 、 include 、 exclude 三個配置項來命中 Loader 要應(yīng)用規(guī)則的文件。
為了盡可能少的讓文件被 Loader 處理,可以通過 include 去命中只有哪些文件需要被處理。
以采用 ES6 的項目為例,在配置 babel-loader 時,可以這樣:
module.exports = { module: {  rules: [   {    // 如果項目源碼中只有 js 文件就不要寫成 //.jsx?$/,提升正則表達式性能    test: //.js$/,    // babel-loader 支持緩存轉(zhuǎn)換出的結(jié)果,通過 cacheDirectory 選項開啟    use: ['babel-loader?cacheDirectory'],    // 只對項目根目錄下的 src 目錄中的文件采用 babel-loader    include: path.resolve(__dirname, 'src'),   },  ] },};你可以適當(dāng)?shù)恼{(diào)整項目的目錄結(jié)構(gòu),以方便在配置 Loader 時通過 include 去縮小命中范圍。
優(yōu)化 resolve.modules 配置
在 2-4 Resolve 中介紹過 resolve.modules 用于配置 Webpack 去哪些目錄下尋找第三方模塊。
resolve.modules 的默認值是 ['node_modules'] ,含義是先去當(dāng)前目錄下的 ./node_modules 目錄下去找想找的模塊,如果沒找到就去上一級目錄 ../node_modules 中找,再沒有就去 ../../node_modules 中找,以此類推,這和 Node.js 的模塊尋找機制很相似。
當(dāng)安裝的第三方模塊都放在項目根目錄下的 ./node_modules 目錄下時,沒有必要按照默認的方式去一層層的尋找,可以指明存放第三方模塊的絕對路徑,以減少尋找,配置如下:
module.exports = { resolve: {  // 使用絕對路徑指明第三方模塊存放的位置,以減少搜索步驟  // 其中 __dirname 表示當(dāng)前工作目錄,也就是項目根目錄  modules: [path.resolve(__dirname, 'node_modules')] },};優(yōu)化 resolve.mainFields 配置
在 2-4 Resolve 中介紹過 resolve.mainFields 用于配置第三方模塊使用哪個入口文件。
安裝的第三方模塊中都會有一個 package.json 文件用于描述這個模塊的屬性,其中有些字段用于描述入口文件在哪里, resolve.mainFields 用于配置采用哪個字段作為入口文件的描述。
可以存在多個字段描述入口文件的原因是因為有些模塊可以同時用在多個環(huán)境中,準對不同的運行環(huán)境需要使用不同的代碼。
以 isomorphic-fetch 為例,它是 fetch API 的一個實現(xiàn),但可同時用于瀏覽器和 Node.js 環(huán)境。
它的 package.json 中就有2個入口文件描述字段:
{ "browser": "fetch-npm-browserify.js", "main": "fetch-npm-node.js"}isomorphic-fetch 在不同的運行環(huán)境下使用不同的代碼是因為 fetch API 的實現(xiàn)機制不一樣,在瀏覽器中通過原生的 fetch 或者 XMLHttpRequest 實現(xiàn),在 Node.js 中通過 http 模塊實現(xiàn)。
resolve.mainFields 的默認值和當(dāng)前的 target 配置有關(guān)系,對應(yīng)關(guān)系如下:
以 target 等于 web 為例,Webpack 會先采用第三方模塊中的 browser 字段去尋找模塊的入口文件,如果不存在就采用 module 字段,以此類推。
為了減少搜索步驟,在你明確第三方模塊的入口文件描述字段時,你可以把它設(shè)置的盡量少。
由于大多數(shù)第三方模塊都采用 main 字段去描述入口文件的位置,可以這樣配置 Webpack:
module.exports = { resolve: {  // 只采用 main 字段作為入口文件描述字段,以減少搜索步驟  mainFields: ['main'], },};使用本方法優(yōu)化時,你需要考慮到所有運行時依賴的第三方模塊的入口文件描述字段,就算有一個模塊搞錯了都可能會造成構(gòu)建出的代碼無法正常運行。
優(yōu)化 resolve.alias 配置
在 2-4 Resolve 中介紹過 resolve.alias 配置項通過別名來把原導(dǎo)入路徑映射成一個新的導(dǎo)入路徑。
在實戰(zhàn)項目中經(jīng)常會依賴一些龐大的第三方模塊,以 React 庫為例,安裝到 node_modules 目錄下的 React 庫的目錄結(jié)構(gòu)如下:
├── dist
│   ├── react.js
│   └── react.min.js
├── lib
│   ... 還有幾十個文件被忽略
│   ├── LinkedStateMixin.js
│   ├── createClass.js
│   └── React.js
├── package.json
└── react.js
可以看到發(fā)布出去的 React 庫中包含兩套代碼:
默認情況下 Webpack 會從入口文件 ./node_modules/react/react.js 開始遞歸的解析和處理依賴的幾十個文件,這會時一個耗時的操作。
通過配置 resolve.alias 可以讓 Webpack 在處理 React 庫時,直接使用單獨完整的 react.min.js 文件,從而跳過耗時的遞歸解析操作。
相關(guān) Webpack 配置如下:
module.exports = { resolve: {  // 使用 alias 把導(dǎo)入 react 的語句換成直接使用單獨完整的 react.min.js 文件,  // 減少耗時的遞歸解析操作  alias: {   'react': path.resolve(__dirname, './node_modules/react/dist/react.min.js'),  } },};除了 React 庫外,大多數(shù)庫發(fā)布到 Npm 倉庫中時都會包含打包好的完整文件,對于這些庫你也可以對它們配置 alias。
但是對于有些庫使用本優(yōu)化方法后會影響到后面要講的 使用 Tree-Shaking 去除無效代碼 的優(yōu)化,因為打包好的完整文件中有部分代碼你的項目可能永遠用不上。
一般對整體性比較強的庫采用本方法優(yōu)化,因為完整文件中的代碼是一個整體,每一行都是不可或缺的。
但是對于一些工具類的庫,例如 lodash ,你的項目可能只用到了其中幾個工具函數(shù),你就不能使用本方法去優(yōu)化,因為這會導(dǎo)致你的輸出代碼中包含很多永遠不會執(zhí)行的代碼。
優(yōu)化 resolve.extensions 配置
在導(dǎo)入語句沒帶文件后綴時,Webpack 會自動帶上后綴后去嘗試詢問文件是否存在。
在 2-4 Resolve 中介紹過 resolve.extensions 用于配置在嘗試過程中用到的后綴列表,默認是:
extensions: ['.js', '.json']
也就是說當(dāng)遇到 require('./data') 這樣的導(dǎo)入語句時,Webpack 會先去尋找 ./data.js 文件,如果該文件不存在就去尋找 ./data.json 文件,如果還是找不到就報錯。
如果這個列表越長,或者正確的后綴在越后面,就會造成嘗試的次數(shù)越多,所以 resolve.extensions 的配置也會影響到構(gòu)建的性能。
在配置 resolve.extensions 時你需要遵守以下幾點,以做到盡可能的優(yōu)化構(gòu)建性能:
相關(guān) Webpack 配置如下:
module.exports = { resolve: {  // 盡可能的減少后綴嘗試的可能性  extensions: ['js'], },};優(yōu)化 module.noParse 配置
在 2-3 Module 中介紹過 module.noParse 配置項可以讓 Webpack 忽略對部分沒采用模塊化的文件的遞歸解析處理,這樣做的好處是能提高構(gòu)建性能。
原因是一些庫,例如 jQuery 、ChartJS, 它們龐大又沒有采用模塊化標準,讓 Webpack 去解析這些文件耗時又沒有意義。
在上面的 優(yōu)化 resolve.alias 配置 中講到單獨完整的 react.min.js 文件就沒有采用模塊化,讓我們來通過配置 module.noParse 忽略對 react.min.js 文件的遞歸解析處理,
相關(guān) Webpack 配置如下:
const path = require('path');module.exports = { module: {  // 獨完整的 `react.min.js` 文件就沒有采用模塊化,忽略對 `react.min.js` 文件的遞歸解析處理  noParse: [/react/.min/.js$/], },};注意被忽略掉的文件里不應(yīng)該包含 import 、 require 、 define 等模塊化語句,不然會導(dǎo)致構(gòu)建出的代碼中包含無法在瀏覽器環(huán)境下執(zhí)行的模塊化語句。
總結(jié)
以上所述是小編給大家介紹的Webpack優(yōu)化配置縮小文件搜索范圍,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對武林網(wǎng)網(wǎng)站的支持!
新聞熱點
疑難解答