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 中的 test 、 include 、 exclude 的值都是 Condition 實例。
Condition 實例可以使下面的某一種值:
- 一個字元串:輸入值必須以該字元串開始。
- 一個正則表達式。
- 一個由
Condition實例組成的數組。 - 一個對象:必須匹配所有屬性,每一個屬性的行為都是預先定義好的(屬性 key 只能是
and、or或者not)。
對於 Rule.test ,值只能是一個正則表達式或者一個正則表達式數組。
對於 Rule.include ,值只能是一個字元串或者一個字元串數組。
Rule.exclude 的值和 Rule.include 一樣。
更詳細的描述,參考官網文檔。
所以,Rule.include 和 Rule.exclude 配置都會使用絕對路徑。
entry
entry 中配置的相對路徑,是相對於 process.cwd() 去查找的。
output.path
必須配置成一個絕對路徑。
babelrc 中的 plugins 和 presets 路徑
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 |
