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 |