對於打包工具來說,最簡單也是最復雜的操作莫過於路徑的安排了,原本都在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"
,這樣就會在dist目錄下生成一個scripts的目錄,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 |
---|---|
file-loader | 用於管理JS中導入的資源或者CSS中引用的資源路徑。 |
html-loader | 用於管理HTML,提取管理引用資源,如img中的src,還可以對html進行優化,如去除所有的注釋壓縮等。 |
mini-css-extract-plugin | 用於提取CSS,並進行分別打包,雖然有mini,但是意思不是壓縮CSS,如需壓縮還需要其他的插件配置。 |
html-webpack-plugin | 一個強大的html管理插件,可以用於生成html,可以配置模板,靈活的配置chunk。 |