11.webpack中的幾個路徑配置
一、相對路徑和絕對路徑
- 相對路徑
相對路徑是指以當前的檔案作為起點,相較於當前目錄的位置而被指向並且加以引用的檔案資源。
- /表示當前檔案所在目錄的根目錄
- ./表示當前檔案所在目錄
- ../表示當前檔案所在目錄的上一級目錄
- 絕對路徑
絕對路徑是指在當前檔案的電腦硬碟上真正存在的路徑,必須準確,起點是系統的根目錄也就是各個盤的碟符。
比如:C:\Users\克林辣舞\Desktop\kelinlawu這就是一個絕對路徑
二、entry入口路徑配置
-
功能: 用於指定webpack在打包的時候依據哪個檔案當做打包的入口。
-
預設值: ./src/index.js
-
注意:enrty屬性的值其相對的路徑不是webpack.config.js檔案所在路徑,而是專案的根路徑
假設有下面這樣一個專案目錄:
|---config
|---webpack.config.js
|
|---src
|---main.js
在webpack.config.js中的配置是這樣的:
module.exports = {
entry:"../src/main.js"
}
按照常理來說,webpack.config.js檔案中按照相對路徑去讀取入口檔案也就是src目錄下的main.js檔案,那麼entry是應該寫成上述這種相對路徑:'../src/main.js',代表去webpack.config.js檔案的上一級目錄中查詢src資料夾下的main.js檔案當做入口檔案,這一切看起來都是正常的,但是在執行npm run build的時候卻會報錯,報錯的內容是:
Module not found: Error: Can't resolve '../src/main.js' in 'C:\Users\克林辣舞\Desktop\webpack\webpack-demo - 副本'
意思是說在"C:\Users\克林辣舞\Desktop\webpack\webpack-demo - 副本"此目錄的上一級目錄中沒有找到src資料夾中的main.js。這說明了一個問題:那就是不管webpack.config.js配置檔案放在什麼目錄下,其中entry屬性的值都是以當前專案的根路徑來進行配置的,所以正確的配置方法應該是:
module.exports = { entry:"./src/main.js" // 也可以配置為/src/main.js /代表當前檔案所在的根路徑,和./是一個意思 }
以上配置代表webpack在打包的時候尋找專案的根路徑下的src資料夾中的main.js檔案當做入口檔案進行打包,執行npm run build之後打包成功,說明這種配置是正確的。
- webpack.config.js配置檔案路徑影響指令碼配置
這裡有一個注意的地方就是webpack.config.js配置檔案一般情況下是放置在專案的根目錄下的,此時在package.json中配置指令碼的時候是不需要指定webpack.config.js檔案的路徑的:
"scripts": {
"build": "webpack ",
"serve": "webpack serve --open",
}
而如果我們手動建立了一個config資料夾,將webpack.config.js配置檔案放在了這個資料夾中,此時必須要藉助於--config引數指定webpack.config.js配置檔案的存放路徑:
"scripts": {
"build": "webpack --config ./config/webpack.config.js",
"serve": "webpack serve --config ./config/webpack.config.js --open",
}
三、output出口若干路徑配置
filename
- 功能:用於指定webpack打包之後輸出的主檔案的名稱,該檔案將會寫入到path選項指定的目錄下
- 預設值:'./dist/main.js'
- 注意
filename的值必須是一個相對路徑,而不能是一個絕對路徑,以下寫法都被認為是有效的路徑:
- bundle.js
- ./js/bundle.js
但是以下寫法被認為是無效的路徑: - /js/bundle.js
path
- 功能:用於指定webpack打包之後所有生成的檔案存放的目錄
- 預設值:./dist資料夾,代表會將所有打包之後的檔案存放在當前專案根目錄下的dist資料夾中
- 注意:path屬性的值是一個絕對路徑,它是通過path.resolve方法來生成的一個絕對路徑
假設有下面這樣一個專案目錄,其根目錄是:"C:\Users\克林辣舞\Desktop\webpack\webpack-demo - 副本"
|---config
|---webpack.config.js
|
|---src
|---main.js
在webpack.config.js中有如下配置:
module.exports = {
output: {
filename: "js/bundle.js",
path: path.resolve(__dirname, "../build"),
},
}
這裡的path的值經過path.resolve方法處理之後將會得到一個絕對路徑:"C:\Users\克林辣舞\Desktop\webpack\webpack-demo - 副本\build",也就是說webpack在對此專案打包之後會將所有打包的檔案放入當前專案的根目錄下的build資料夾下,而在build資料夾中的js資料夾中存放著專案打包後的主檔案bundle.js。
publicPath
-
功能:publicPath用於對webpack打包之後得到的靜態資源前面進行一個路徑的拼接
-
預設值:"" 空字串
為什麼在開發的時候需要配置publicPath為"/"?
當我們在本地基於webpack dev server啟動了一個本地服務之後,此時瀏覽器就會基於WDS提供的靜態服務去獲取載入所需的資源,比如index.html檔案。瀏覽器在解析html的時候遇到link標籤和script標籤的時候又會去請求css、js等靜態資源,比如遇到一個script資源去獲取js檔案:
<script defer="" src="/js/bundle.js"></script>
瀏覽器在解析到script標籤中包含一個src屬性的時候便知道這是一個外部js指令碼,要基於src屬性所指向資源的路徑去獲取js資源,而瀏覽器客戶端在獲取資源的時候可以基於不同的協議去獲取,比如http協議、或者是file協議。
由於瀏覽器當前載入的index.html就是瀏覽器從WDS提供的靜態伺服器上獲取的,所以瀏覽器就會基於當前頁面的協議+域名,然後在後面依次拼接上output.publicPath和src屬性指定的資源路徑去本地伺服器獲取資源,所以瀏覽器的請求地址其實是:
http://localhost:8080 + output.publicPath + js/bundle.js
如果output.publicPath的值沒有配置那就是預設值為空串,拼接之後的路徑就是:"http://localhost:8080js/bundle.js",很顯然這種url路徑埠號和路徑沒有用/分隔開,所以大多數瀏覽器會預設在兩者之間加一個/以避免資源載入失敗,因此最終拼接完成的請求地址是:
http://localhost:8080/js/bundle.js
由於WDS已經將我們打包後的資源放在了本地伺服器上,所以在開發環境下瀏覽器會正確的基於這個地址拿到js資源並載入,頁面就會正常載入。
然而為什麼諸如Vue CLI等這種官方腳手架的webpack.config.js會將output.publicPath的值配置為一個"/"呢?這是為了避免有的瀏覽器不會預設在域名和路徑之間加/,最終導致請求路徑拼接錯誤導致頁面載入失敗,為了保證在所有瀏覽器中都可以正確獲取到資源,所以會在這裡顯式的配置output.publicPath的值為"/"。
為什麼在打包的時候需要配置publicPath值為"./"
如果我們在npm run build的時候也配置publicPath的值為/,然後我們直接在本地載入打包後dist資料夾中的index.html的時候,此時瀏覽器在解析html檔案中的script標籤中的src值去獲取資源的時候是無法獲取的,還是以上面的例子來說明:
<script defer="" src="/js/bundle.js"></script>
當瀏覽器基於src的屬性去獲取js檔案的時候,由於此時index.html檔案是在本地開啟的,所以此時瀏覽器其實是基於file協議去載入資源的,其請求地址是:
file:///C:/js/bundle.js
因為瀏覽器在解析路徑:"/js/bundle.js"的時候會將最前面的/解析為本地檔案的根路徑也就是碟符C:,很明顯在C盤的根目錄下是沒有js/bundle.js檔案的,因此會找不到資源載入失敗。
而如果我們在打包前將publicPath的值設定為"./",那麼瀏覽器在解析路徑:"./js/bundle.js"的時候會將其解析為相對當前index.html同一目錄下的js/bundle.js,此時瀏覽器的請求路徑就變成了:
file:///C:/Users/克林辣舞/Desktop/webpack/webpack-demo - 副本/build/js/bundle.js
很明顯基於上面這個路徑去本地獲取資源是可以成功獲取的,因此如果我們想將打包後的資源在本地開啟後也正常載入的話就需要將output.publicPath的值設定為"./"
devServer
四、devServer中的若干路徑配置
publicPath(webpack4中配置,V5版本已經沒有此屬性)
- 功能:指定本地服務在執行的時候獲取打包後資源所在的資料夾路徑
- 預設值:'/' 也就是直接訪問埠即可訪問其中的資源http://localhost:8080
- 注意:devServer.publicPath很少主動配置
在devServer的配置屬性中也有一個publicPath屬性,該屬性的主要作用就是指定專案在瀏覽器中開啟之後預設去本地伺服器上的那個資料夾中獲取打包之後的資源,如果不配置devServer.publicPath那麼就讀取預設值'/',此時獲取資源的路徑就是:
http://localhost:8080/ 代表直接去當前伺服器的根目錄下獲取打包之後的資源即可
如果將devServer.publicPath的值配置為:'/project',那麼此時獲取資源的路徑是:
http://localhost:8080/project 代表直接去當前伺服器的project目錄下獲取打包之後的資源
官方建議:devServer.publicPath的值應該始終和output.publicPath的保持一致,否則會導致資源獲取失敗。
contentBase(webpack4中配置,V5版本已經沒有此屬性)
如果我們使用webpack來打包資源前在index.html中引入了某些第三方的靜態資源,而這些靜態資源並不會成為webpack依賴圖中的一員所以也就不會被最終打包到dist目錄下,但是在WDS啟動本地服務之後瀏覽器載入打包之後的index.html的時候,還是會按照打包前的路徑去引入這些第三方靜態資源,此時就會出錯。
打包前的index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>webpack module</title>
/* 引入第三方靜態資源 等於是直接讀取的本地檔案*/
<script src="./vender/vender.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
WDS服務起來之後的index.html
此時等於基於http協議去本地伺服器獲取這個檔案:http://localhost:8080/vender/vender.js,由於此檔案並不在打包的dist資料夾中,所以本地伺服器會找不到這個資源。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>webpack module</title>
/* 等於是基於http協議去本地伺服器獲取這個檔案:http://localhost:8080/vender/vender.js */
<script src="./vender/vender.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
所以我們需要告訴WDS的本地伺服器,應該如何去載入這種沒有包含在打包依賴中的第三方靜態資源:
在webpack4中,我們需要配置devServer.contentBase如下,告訴webpack要將第三方靜態資源放在vender資料夾下進行讀取:
devServer:{
hot:true,
contentBase:path.resolve(__dirname,"./vender") // 絕對路徑
}
在webpack5中,我們需要配置static中的directory和publicPath如下:
devServer:{
hot:true,
static:{
directory:path.resolve(__dirname,"./vender"),
publicPath:"/vender",
watch:true // 當靜態資原始檔變化的時候也重新重新整理瀏覽器
}
}