顯微鏡下的webpack4:路徑操作
對於打包工具來說,最簡單也是最複雜的操作莫過於路徑的安排了,原本都在src
下的資源,想要打包到dist
目錄下,但是打包出來的檔案路徑甚不如人意。明明想要分門別類地放置檔案檔案,然後卻像大雜燴一樣js
,html
,css
甚至圖片都混在了一起。雖然打包之後雲心沒什麼問題,但是這是要逼死強迫症患者啊。
所以這篇文章就是講解如何明明白白安排各資源的路徑,無關webpack效能,無關各類騷操作,只是基礎的路徑操作。
傳統的網站一般會將資料夾分為三類,styles
,scripts
,images
,看到這個三個資料夾就會倍感親切,有種老朋友的感覺。如果這個時候css檔案出現在了scripts中,或者更images資料夾出現在scripts中,估計寫這個網站的前端會被大家吐槽了。但是如果是webpack打包之後發生這種事,毫不驚奇,習以為常,佛系打包。每次打包都是一個驚喜,如果配置不對,打包出來的檔案可能會和你玩捉迷藏。為此我整理了下webpack打包中可能會出現的路徑問題,如下方大綱所示,如果有夥伴們遇到過此類問題可以按需查詢。
大綱:
- js路徑問題
- css路徑問題
- html路徑問題
- 圖片路徑問題(important)
- js中的圖片引用路徑
- css中的圖片引用路徑
- html中的圖片引用路徑
webpack打包流程
webpack打包流程簡單來說就是把所有的資源都變成js的chunk模組,然後再對chunk們進行操作,最後再根據配置分門別類輸出。
為了能夠深入瞭解我們的檔案打包去哪兒了,我建了一個比較變態的檔案目錄。
JS生成路徑
JS在這個過程中是最好控制的,根據配置的entry和output既可以輕鬆控制來龍去脈。而這兩個配置在官方文件中也解釋地相當詳細。
像下方這樣的配置,應該比較常用,就是一個html,一個場景一個entry,然後output的時候按照entry名字生成相對應的檔案。
entry:{
"index":path.resolve(__dirname,"src/scripts/index/index.js"),
"list":path.resolve(__dirname,"src/scripts/list/list.js"),
},
output:{
path:path.resolve(__dirname,"dist"),
filename:"[name].js"
},
這裡需要注意:
- output.path是專案的路徑,也就是之後的css,圖片等打包會按著這個path為相對路徑來生成檔案。
- output.filename不僅僅可以命名,如果你想要js放在特定目錄下可以在這裡配置,就像這樣
filename:"scripts/[name].js"
CSS生成路徑
CSS的引用,就比CSS複雜一些,不是直接HTML引用,而是import "../../styles/index/index.css"
像這樣匯入,或者require
到JS之中,這樣webpack才會去打包CSS到新目錄下。不過呢原生的CSS,JS是不認識的,所以這個時候需要loader幫我們編譯CSS才能匯入JS之中。
CSS的loader們
css-loader很顯然就是將CSS編譯成JS認識的語法。
style-loader最主要乾的事情就是將JS中編譯的CSS程式碼插入DOM之中,使之生效。
mini-css-extract-plugin,這個外掛最主要的目的就是將每個JS(chunk)中的CSS程式碼剝離出來,分別打包到各自命名的CSS檔案之中。(注:ExtractTextPlugin只適用於webpack3及以下。),有關CSS檔案生成路徑的問題,我們主要就是用這個外掛來實現,而這個外掛不僅要在loader的時候參與編譯CSS,還需要在打包的時候發揮作用,將CSS打包到相應的資料夾之中。
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports={
...
//loader
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
"css-loader"
]
}
]
,
},
plugins: [
//css打包
new MiniCssExtractPlugin({
filename: "styles/[name].css"
})
]
}
上述程式碼給出了MiniCssExtractPlugin這個外掛的用法。它主要的生成配置是在filename:"styles/[name].css"
,這否覺得似成相識,和webpack的output.filename的配置一樣,可以將css打包至styles資料夾之下。
HTML生成路徑
HTML的打包編譯就比較特殊,一般使用html-webpack-plugin
外掛,通過編寫模版來配置生成html檔案。這個外掛的功能很強大,不過這裡只提及生成路徑的配置。
const HtmlWebpackPlugin = require('html-webpack-plugin');
我是這樣配置html,匯入模版,然後生成檔案,我給filename一個絕對路徑,這樣就不用擔心檔案會生成到什麼奇怪的地方了。當然直接filename: 'index.html'
給一個檔名也是可以的,這樣就會按照webpack中output配置的path,即專案目錄為物件的相對路徑。這裡的chunks: ["index"]
使之html中包含的獨立,否則會將所有的資源全部潛入當前的html中。
new HtmlWebpackPlugin({
filename: path.join(__dirname,'/dist/index.html'),
template: path.join(__dirname,'/src/templates/index.html'),
chunks: ["index"]
})
圖片生成路徑
這一塊應該是最相對最複雜的一塊了,不過分別分析之後也不會太負責。
images in JS
這一部分是最簡單的了,因為從JS中獲取資源最直接,不用編譯多道工序。
說到匯入檔案的地址,我們最常用的是file-loader
這個loader。在outputPath
之中配置檔案的生成地址。這裡我們配置了images/
,也就是dist/images
之下。useRelativePath
這個選項看似人畜無害,但是配置的時候需謹慎不然多次呼叫這個loader的話,就會發生dist/images/images
的情況。
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
useRelativePath:false,
outputPath: 'images/',
name: '[name].[ext]'
}
}
]
},
JS想要匯入圖片,也很簡單直接import或者require+圖片地址,即可,與CSS的呼叫一致。
images in CSS
在CSS中我們經常會用到圖片,比如background這個屬性,那麼在CSS中我們怎麼打包圖片,並且改變CSS中圖片的地址呢?因為我們CSS是被import到JS之中的,所以和JS一樣的處理方式,file-loader會幫助我們處理好圖片的問題的。不過CSS中圖片的引用地址是個問題啊。
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
}
這個時候就可以利用loader中publicPath這個屬性,這個屬性不參與編譯,只在最後打包的時候替換路徑。這裡CSS中圖片的路徑是image/xxx.jpg
,如果我們加上這個../
,那麼就變成../image/xxx.jpg
。通過這樣來控制CSS中圖片的問題,如果想改成CDN地址也是可以。
images in HTML
這一部分是最令人頭疼的file-loader
不處理html中的img標籤,這裡我們會利用html-loader
來處理圖片的問題,如下方配置:
{
test: /\.html$/,
use: [ {
loader: 'html-loader',
options: {
publicPath:"./",
attrs: ['img:src']
}
}],
}
這樣我們就會將html中的圖片檔案完美的打包出來啦。不過這個外掛沒有publicPath的配置,這裡的地址需要依靠output.publicPath。如果output.publicPath為空,那麼打包出來的檔案地址就是images/xxx.jpg
。如果配置了output.publicPath="./"
,那麼打包出來的就是./images/xxx.jpg
。
總結
打包路徑說複雜各種相對路徑確實容易搞暈,所以這個時候需要保持清醒的頭腦。該用相對路徑的用相對。不需要的就用絕對路徑。有些外掛還是很人性化地有publicPath
這個選項,還可以手動控制下。
本文所用到的loader,plugin一覽
plugin/loader | usage |
---|---|
用於管理JS中匯入的資源或者CSS中引用的資源路徑。 | |
用於管理HTML,提取管理引用資源,如img中的src,還可以對html進行優化,如去除所有的註釋壓縮等。 | |
用於提取CSS,並進行分別打包,雖然有mini,但是意思不是壓縮CSS,如需壓縮還需要其他的外掛配置。 | |
一個強大的html管理外掛,可以用於生成html,可以配置模板,靈活的配置chunk。 |