這次帶給大家Webpack怎麼優化設定檔,Webpack優化設定檔的注意事項有哪些,下面就是實戰案例,一起來看一下。
Webpack 啟動後會從設定的 Entry 出發,解析出檔案中的導入語句,再遞歸的解析。
在遇到導入語句時 Webpack 會做兩件事:
1.根據導入語句去尋找對應的要導入的檔案。例如 require('react') 導入語句對應的檔案是 ./node_modules/react/react.js , require('./util') 對應的檔案是 ./util.js 。
2.根據找到的要導入檔案的後綴,使用設定中的 Loader 去處理檔案。例如使用 ES6 開發的 JavaScript 檔案就需要使用 babel-loader 去處理。
以上兩件事雖然對於處理一個文件非常快,但是當專案大了以後文件量會變的非常多,這時候構建速度慢的問題就會暴露出來。
雖然以上兩件事情無法避免,但需要盡量減少以上兩件事情的發生,以提高速度。
接下來一一介紹可以優化它們的途徑。
最佳化 loader 設定
# 由於 Loader 對檔案的轉換操作很耗時,需要讓盡可能少的檔案被 Loader 處理。
在 2-3 Module 中介紹過在使用 Loader 時可以透過 test 、 include 、 exclude 三個設定項來命中 Loader 要套用規則的檔案。
為了盡可能少的讓檔案被 Loader 處理,可以透過 include 去命中只有哪些檔案需要被處理。
以採用 ES6 的專案為例,在設定 babel-loader 時,可以這樣:
module.exports = { module: { rules: [ { // 如果项目源码中只有 js 文件就不要写成 /\.jsx?$/,提升正则表达式性能 test: /\.js$/, // babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启 use: ['babel-loader?cacheDirectory'], // 只对项目根目录下的 src 目录中的文件采用 babel-loader include: path.resolve(dirname, 'src'), }, ] }, };
你可以適當的調整專案的目錄結構,以便在配置 Loader 時透過 include 去縮小命中範圍。
優化 resolve.modules 設定
在 2-4 Resolve 中介紹過 resolve.modules 用於配置 Webpack 去哪些目錄下尋找第三方模組。
resolve.modules 的預設值是 ['node_modules']
,意思是先去目前目錄下的./node_modules 目錄下去找想找的模組,如果沒找到就去上一級目錄../ node_modules 中找,再也沒有就去../../node_modules 中找,以此類推,這和Node.js 的模組尋找機制很相似。
當安裝的第三方模組都放在專案根目錄下的./node_modules 目錄下時,沒有必要按照預設的方式去一層層的尋找,可以指明存放第三方模組的絕對路徑,以減少尋找,配置如下:
module.exports = { resolve: { // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤 // 其中 dirname 表示当前工作目录,也就是项目根目录 modules: [path.resolve(dirname, 'node_modules')] }, };
優化 resolve.mainFields 設定
# 在 2-4 Resolve 中介紹過 resolve.mainFields 用於設定第三方模組使用哪個入口檔案。
安裝的第三方模組中都會有一個 package.json 檔案用於描述這個模組的屬性,其中有些欄位用於描述入口檔案在哪裡, resolve.mainFields 用於配置採用哪個欄位作為入口檔案的描述。
可以存在多個欄位來描述入口檔案的原因是因為有些模組可以同時用在多個環境中,準對不同的運作環境需要使用不同的程式碼。
以 isomorphic-fetch 為例,它是 fetch API 的實現,但可同時用於瀏覽器和 Node.js 環境。
它的 package.json 中就有2個入口檔案描述欄位:
{ "browser": "fetch-npm-browserify.js", "main": "fetch-npm-node.js" }
isomorphic-fetch 在不同的運行環境下使用不同的程式碼是因為 fetch API 的實作機制不一樣,在瀏覽器中透過原生的 fetch 或 XMLHttpRequest 實現,在 Node.js 中透過 http 模組實現。
resolve.mainFields 的預設值和目前的 target 配置有關係,對應關係如下:
當 target 為 web 或 webworker 時,值為 ["browser", "module", "main"]
以 target 等于 web 为例,Webpack 会先采用第三方模块中的 browser 字段去寻找模块的入口文件,如果不存在就采用 module 字段,以此类推。
为了减少搜索步骤,在你明确第三方模块的入口文件描述字段时,你可以把它设置的尽量少。
由于大多数第三方模块都采用 main 字段去描述入口文件的位置,可以这样配置 Webpack:
module.exports = { resolve: { // 只采用 main 字段作为入口文件描述字段,以减少搜索步骤 mainFields: ['main'], }, };
使用本方法优化时,你需要考虑到所有运行时依赖的第三方模块的入口文件描述字段,就算有一个模块搞错了都可能会造成构建出的代码无法正常运行。
优化 resolve.alias 配置
在 2-4 Resolve 中介绍过 resolve.alias 配置项通过别名来把原导入路径映射成一个新的导入路径。
在实战项目中经常会依赖一些庞大的第三方模块,以 React 库为例,安装到 node_modules 目录下的 React 库的目录结构如下:
├── dist
│ ├── react.js
│ └── react.min.js
├── lib
│ ... 还有几十个文件被忽略
│ ├── LinkedStateMixin.js
│ ├── createClass.js
│ └── React.js
├── package.json
└── react.js
可以看到发布出去的 React 库中包含两套代码:
一套是采用 CommonJS 规范的模块化代码,这些文件都放在 lib 目录下,以 package.json 中指定的入口文件 react.js 为模块的入口。
默认情况下 Webpack 会从入口文件 ./node_modules/react/react.js 开始递归的解析和处理依赖的几十个文件,这会时一个耗时的操作。
通过配置 resolve.alias 可以让 Webpack 在处理 React 库时,直接使用单独完整的 react.min.js 文件,从而跳过耗时的递归解析操作。
相关 Webpack 配置如下:
module.exports = { resolve: { // 使用 alias 把导入 react 的语句换成直接使用单独完整的 react.min.js 文件, // 减少耗时的递归解析操作 alias: { 'react': path.resolve(dirname, './node_modules/react/dist/react.min.js'), } }, };
除了 React 库外,大多数库发布到 Npm 仓库中时都会包含打包好的完整文件,对于这些库你也可以对它们配置 alias。
但是对于有些库使用本优化方法后会影响到后面要讲的 使用 Tree-Shaking 去除无效代码 的优化,因为打包好的完整文件中有部分代码你的项目可能永远用不上。
一般对整体性比较强的库采用本方法优化,因为完整文件中的代码是一个整体,每一行都是不可或缺的。
但是对于一些工具类的库,例如 lodash ,你的项目可能只用到了其中几个工具函数,你就不能使用本方法去优化,因为这会导致你的输出代码中包含很多永远不会执行的代码。
优化 resolve.extensions 配置
在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试询问文件是否存在。
在 2-4 Resolve 中介绍过 resolve.extensions 用于配置在尝试过程中用到的后缀列表,默认是:
extensions: ['.js', '.json']
也就是说当遇到 require('./data') 这样的导入语句时,Webpack 会先去寻找 ./data.js 文件,如果该文件不存在就去寻找 ./data.json 文件,如果还是找不到就报错。
如果这个列表越长,或者正确的后缀在越后面,就会造成尝试的次数越多,所以 resolve.extensions 的配置也会影响到构建的性能。
在配置 resolve.extensions 时你需要遵守以下几点,以做到尽可能的优化构建性能:
后缀尝试列表要尽可能的小,不要把项目中不可能存在的情况写到后缀尝试列表中。
相关 Webpack 配置如下:
module.exports = { resolve: { // 尽可能的减少后缀尝试的可能性 extensions: ['js'], }, };
优化 module.noParse 配置
在 2-3 Module 中介绍过 module.noParse 配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析处理,这样做的好处是能提高构建性能。
原因是一些库,例如 jQuery 、ChartJS, 它们庞大又没有采用模块化标准,让 Webpack 去解析这些文件耗时又没有意义。
在上面的 优化 resolve.alias 配置 中讲到单独完整的 react.min.js 文件就没有采用模块化,让我们来通过配置 module.noParse 忽略对 react.min.js 文件的递归解析处理,
相关 Webpack 配置如下:
const path = require('path'); module.exports = { module: { // 独完整的 `react.min.js` 文件就没有采用模块化,忽略对 `react.min.js` 文件的递归解析处理 noParse: [/react\.min\.js$/], }, };
注意被忽略掉的文件里不应该包含 import 、 require 、 define 等模块化语句,不然会导致构建出的代码中包含无法在浏览器环境下执行的模块化语句。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上是Webpack怎麼優化設定檔的詳細內容。更多資訊請關注PHP中文網其他相關文章!