標籤:

webpack 配置中的路徑

resolve.alias

resolve.alias 用於給模塊路徑指定別名。

為什麼要給模塊路徑取別名呢?

假設在我們的源碼中有如下 import 語句:

import BaseModel from ../../../../common/BaseModel;nnexport default class ProductModel extends BaseModel {nn // some code heren n}n

那麼每次引入 BaseModel 的時候,很可能都會面臨著寫很長一堆 ../../../../ 的問題,而且如果沒有編輯器的智能提示,很容易少寫(或者多寫)一層 ../

此時就可以在 webpack 配置中為 BaseModel 指定一個別名:

{n // some other configsn n resolve: {n alias: {n common: require(path).resolve(__dirname, ../src/common)n }n }n n // some other configsn} n

這樣一來,引入 BaseModel 的代碼就變成下面這樣了:

import BaseModel from common/BaseModel; n

另外一種場景,就是去掉路徑中的無意義的一層(站在使用者角度來說無意義)。比如安裝了 vue 模塊之後,如果不做任何配置,引入 vue 的代碼看起來是這樣的:

import Vue from vue/dist/vue.esm.js;n

看起來多多少少會覺得彆扭,而且還不好調整成不同的版本(開發時用 vue.esm.js ,發布的時候用 vue.runtime.js )。

此時在 webpack 中加上不同環境的別名:

{n // some other configsn n resolve: {n alias: {n vue$: process.env.NODE_ENV === productionn ? vue/dist/vue.runtime.js : vue/dist/vue.esm.jsn }n }n n // some other configsn}n

看起來就優雅很多了。

那麼 alias 的原理是怎麼樣的呢?

配置了 alias 之後,在 webpack 解析引入(通過 import 或者 require )的模塊的時候,會先將源碼中的模塊路徑中匹配 alias 里 key 的部分替換成 value 部分,再做查找。

比如源碼中有如下引入語句:

import Test1 from xyz/file;n

alias 中有如下配置:

{n // some other configsn n resolve: {n alias: {n xyz: ./dirn }n }n n // some other configsn}n

在解析路徑的時候,會先將 xyz 替換成 ./dir ,那麼之前的 import 語句就相當於:

import Test1 from ./dir/file.js; n

然後 webpack 再基於 ./dir/file.js 去查找需要引入的模塊。

當然,也可以配置絕對路徑:

{n // some other configsn n resolve: {n alias: {n xyz: require(path).resolve(__dirname, ../dir)n }n }n n // some other configsn}n

依然按照之前先替換後解析的流程執行。

另外,alias 還有一種特殊的語法:key 的末尾帶一個 $ 字元,表示精確匹配。

假設有下面 alias 配置:

{n // some other configsn n resolve: {n alias: {n xyz$: xyz/dirn }n }n n // some other configsn}n

對於:

import xyz/file.js; n

這種 import 語句,就無法匹配上這條 alias 規則。

而:

import xyz; n

才能匹配上。

更多 alias 的匹配示例,參考官網文檔。

resolveLoader.modules

可以通過 resolveLoader.modules 配置在哪些目錄下查找 loader ,默認是在 node_modules 目錄下查找。

那麼問題就來了,這個默認的 node_modules 指的是哪裡的 node_modules 目錄呢?換句話說,這裡的 node_modules 目錄對應的絕對路徑是怎麼構造的?

webpack 會以當前進程目錄( process.cwd() )開始,逐層往上查找 node_modules 目錄,如果查到根目錄,還沒找到,就拋出錯誤。這與 Node 查找 node_modules 目錄的行為是一致的,只不過 Node 是從當前模塊所在目錄開始查找的。

對於其他的相對目錄配置,查找邏輯與默認的 node_modules 一樣

對於絕對路徑,就直接找這個路徑對應的目錄了。

權威說明,可參考官網文檔。

找到 resolveLoader.modules 的具體目錄之後,就按照配置的順序去查找 loader 了。

假設有如下配置:

{n // some other configsn n resolveLoader: {n modules: [loaders1, loaders2]n }n n // some other configsn}n

如果當前進程目錄是 /a/b/c ,現在要查找 babel-loader ,就會按照如下順序查找:

/a/b/c/loaders1/babel-loader/...n/a/b/c/loaders2/babel-loader/...nn/a/b/loaders1/babel-loader/...n/a/b/loaders2/babel-loader/...nn/a/loaders1/babel-loader/...n/a/loaders2/babel-loader/...nn/loaders1/babel-loader/...n/loaders2/babel-loader/...n

註:上述示例省略號後面的內容根據其他配置確定,具體參看官網文檔,此處不贅述。

Rule.include 、 Rule.exclude 等路徑配置

Rule 中的 testincludeexclude 的值都是 Condition 實例。

Condition 實例可以使下面的某一種值:

  • 一個字元串:輸入值必須以該字元串開始。
  • 一個正則表達式。
  • 一個由 Condition 實例組成的數組。
  • 一個對象:必須匹配所有屬性,每一個屬性的行為都是預先定義好的(屬性 key 只能是 andor 或者 not )。

對於 Rule.test ,值只能是一個正則表達式或者一個正則表達式數組。

對於 Rule.include ,值只能是一個字元串或者一個字元串數組。

Rule.exclude 的值和 Rule.include 一樣。

更詳細的描述,參考官網文檔。

所以,Rule.includeRule.exclude 配置都會使用絕對路徑。

entry

entry 中配置的相對路徑,是相對於 process.cwd() 去查找的。

output.path

必須配置成一個絕對路徑。

babelrc 中的 pluginspresets 路徑

babelrc 中 plugins presets 配置的相對路徑是相對於待轉換文件解析的。

比如在轉換 /a/b/c/d.js 模塊的時候,查找 babel-plugin-veui 的順序是:

/a/b/c/node_modules/babel-plugin-veui/...n/a/b/node_modules/babel-plugin-veui/...n/a/node_modules/babel-plugin-veui/...n/node_modules/babel-plugin-veui/...n

presets 的解析邏輯與 plugins 一致。

推薦閱讀:

重溫 Webpack, Babel 和 React
【譯】webpack 小札: 充分利用 CommonsChunkPlugin()
Webpack 3 的新功能:Scope Hoisting
webpack如何全局引入jquery和插件?

TAG:webpack |