引入
在運用前端主流框架(react,vue,angular)開發過程中,引入一個模組或檔案路徑,是如何解析到目標檔案的?是按照什麼樣的規則和順序查詢到的?這個問題乍一看是簡單,尤其在小型專案中,模組和檔案並不多的情況下。但遇到一些比較複雜的專案,模組和檔案路徑的引入需要謹慎小心,這就需要深入地理解一下webpack的程式碼路徑解析規則了。
路徑
首先,綜合一下在專案中配置路徑的三種形式
- 相對路徑
相對路徑是相對於當前目錄的路徑
import {button} from '../component/button'
複製程式碼
- 絕對路徑
絕對路徑直接指明瞭檔案的具體位置,直接可以查詢到(不建議使用)
import {button} from '/home/me/file'
複製程式碼
- 模組名
直接引入模組名,會查詢當前檔案目錄,父級目錄直至根目錄下的 node_modules(預設) 資料夾,看是否有對應名稱的模組。
import React from 'react'
import "module/lib/file";
複製程式碼
注意:預設的node_modules可以根據webpack配置的
resolve.modules
進行更改
注意:查詢中會根據webpack配置的
resolve.extensions
自動補全副檔名
注意:查詢中會根據wepack配置的
resolve.alias
替換掉別名
路徑解析
根據上述規則解析路徑後,解析器將路徑指向檔案或者資料夾(目錄)
-
如果是檔案,直接載入
-
如果是資料夾,查詢裡面是否有package.json檔案
1)如果有,預設按照裡面的main欄位的檔名查詢檔案 (可以通過
resolve.mainFields
配置更改)2)如果沒有,預設查詢index.js檔案(可以通過
resolve.mainFiles
配置更改)
resolve配置
瞭解上述的路徑形式和最終的解析規則後,根據我的一些標識,大致上也能夠看出webpack路徑配置的發揮空間了。
webpack解析程式碼路徑的核心模組是
enhanced-resolve
模組
webpack解析匹配程式碼路徑的配置在
resolve
裡面
接下來將著重對resolve中alias,extensions,modules,mainFields,mainFiles屬性做單獨詳細的介紹。
resolve.alias
alias,顧名思義,是指路徑的別名。簡單點說,就是用一個簡單的別名來替換一個常用的或者複雜的檔案路徑。
原理:先替換,後解析。在引入模組時,先將模組路徑中匹配alias中的key替換成對應的value,再做查詢。
注意一下幾點:
- 替換掉的路徑可以是相對路徑,也可以是絕對路徑。
resolve: {
alias: {
'@': path.resolve(__dirname, 'components'),
// 這裡使用 path.resolve 和 __dirname 來獲取絕對路徑
// import '@/Button.js' 等同於 import '[專案絕對路徑]/components/Button.js'
x: './src/components' // 相對路徑
}
}
複製程式碼
2.這裡的匹配是模糊匹配,不是精確匹配。即路徑中攜帶別名即可匹配
3.注意精確匹配的用法。在key的末尾帶一個$字元
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js',
'x$': 'module/dir'
// Import 'x/file.js' // 這裡不能匹配
}
}
複製程式碼
resolve.extensions
extensions中指定了webpack可以識別的副檔名。
注意一下幾點:
- 副檔名匹配的先後順序。從左到右依次匹配。比如下例中,引入import {Button} from './component/button',優先匹配的是button.js,如果沒有button.js,會匹配button.vue,依次往下。
- extensions中沒有的字尾,是不會自動補全的。比如下例中沒有css的副檔名,如果想引入import {Button} from './style/button',是匹配不到button.css檔案的
resolve: {
extensions: ['js', 'vue', 'json']
}
複製程式碼
resolve.modules
查詢宣告依賴名的模組,預設搜尋node_modules目錄。一般我們不修改這個配置。
resolve: {
modules: ['node_modules']
},
複製程式碼
resolve.mainFields
在引用模組時,指明使用package.json中哪個欄位指定的檔案,預設是“main”
resolve: {
// 配置 target === "web" 或者 target === "webworker" 時 mainFields 預設值是:
mainFields: ['browser', 'module', 'main'],
// target 的值為其他時,mainFields 預設值為:
mainFields: ["module", "main"],
}
複製程式碼
因為通常情況下,模組的 package 都不會宣告 browser 或 module 欄位,所以便是使用 main 了。
resolve.mainFiles
在目錄中沒有package.json時,指明使用該目錄中哪個檔案,預設是index.js
resolve: {
mainFiles: ['index'], // 可以新增其他預設使用的檔名
}
複製程式碼
最後
resolve除了上面介紹的幾個屬性外,還有其他一些屬性,有興趣的筒子們可以再深入研究一下。希望我這篇文章對還不太清楚webpack程式碼路徑的童鞋有一定的指引作用~~