webpack生成的css檔案background-image url圖片無法載入
之前在使用webpack3構建基於less預處理的專案時,在對指定的元素使用background-image: url(xxx)
來設定背景圖片時,本地開發是ok的,但是在專案編譯產出後背景圖片就找不到;目前用webpack4開發專案時,同樣遇到類似的問題;所以就藉此機會探討一下產生問題的原因。
問題產生原因
webpack3專案場景復現
專案webpack有關css的配置偽碼如下:
output: { // 專案編譯輸出路徑 path: path.resolve(__dirname, 'dist') } // 圖片的loader的配置如下: { test: /\.(gif|png|jpe?g)(\?\S*)?$/, loader: 'url-loader', options: { limit: 3000, name: path.join('static', env === 'development' ? 'img/[name].[ext]' : 'img/[name]_[hash:7].[ext]') } } // 樣式檔案打包產出的檔案配置如下: if (env === 'produdtion') { webpackCfg.plugins.push( new ExtractTextPlugin({ filename: 'static/index_[contenthash:7].css', disable: false, allChunks: true }) ) }
上面配置的css在生產環境用extract-text-webpack-plugin
來產出css樣式檔案,開發環境通過style-loader
將css內容內聯到html文件中;而圖片是大於指定的limit大小就打包輸出檔案。
此時在我們的index.less
檔案中設定body的背景圖片如下:
body {
background-image: url('./img/bg.png');
}
此時本地開發可以看到背景圖片,而編譯產出css的檔案,背景圖片地址不能正確載入,通過測試發現是圖片路徑出現問題,如下圖:
從產出的css檔案內容來看,body元素的background-image的圖片url相對地址是webpack配置產出圖片路徑,但是頁面實際展示時卻發現圖片路徑為:/xx/../dist/static/static/img/bg_ebdbe98.png。
為什麼會背景圖片路徑會多了一個static
字首?查詢資料發現:
css檔案中設定的background-image的url相對地址是相對於當前css檔案目錄來得到的
因為,專案中設定css的產出路徑為dist/static/index_[contenthash:7].css
,而url中經webpack處理後的url相對地址為static/img/bg_[hash:7].png
; 這樣根據上述規則,圖片實際載入地址為即dist/static/static/img/bg_[hash:7].png
,導致會在圖片路徑字首多加了個static目錄。
而為啥本地開發環境沒有出現問題,這是因為本地開發環境產出的css樣式內容通過style-loader
webpack4專案場景復現
webpack4專案與webpack3專案不同的地方是,webpack4專案中使用mini-css-extract-plugin
外掛來處理css樣式產出,其改善extract-text-webpack-plugin
中的一些問題,其中比較重要的一點是可以使用css的熱載入功能。專案中有關css抽出的配置如下:
plugins: [
new MiniCssExtractPlugin({
filename: env === 'production' ? 'static/index.[contenthash:7].css' : 'static/index.css'
})
],
module: {
rules: [{
test: /\.less$/,
use: [
{loader: MiniCssExtractPlugin.loader},
{loader: 'css-loader', options: {...} },
{loader: 'less-loader', options: {...} }
}]
}
webpack4專案在開發環境和生產環境都使用mini-css-extract-plugin
外掛,所以專案都會產出css檔案,二者環境都會出現問題;
解決方法
在知道問題產生原因後,也就知道該如何解決問題了。最佳的解決方法如下:
- webpack3在
extract-text-webpack-plugin
的extract方法中單獨配置css檔案的publicPath
若沒有在extract-text-webpack-plugin
配置css的publicPath,則會使用webpack.output.publicPath中值;一旦配置值則css中路徑就會相對於新配置的publicPath值。但是這個值配置也是需要注意的。例如,上面檔案產出目錄:
dist
│ index.html
└───static
│ │ index.js
│ │ index.css
│ └─img
│ │ bg.png
圖片的地址為static/img/bg.png,而在index.css中引入了該圖片地址,所以圖片的相對地址是相對於該css檔案的目錄,及最終載入的圖片地址為static/static/img/bg.png,從而導致錯誤。此時正確的配置extract-text-webpack-plugin如下:
ExtractTextPlugin.extract({
fallback: 'style-loader',
use: loaders,
publicPath: '../'
});
這樣,publicPath: '../'配置則是從當前index.css檔案的父目錄來查詢圖片。
最終url的路徑變成 "../static/img/bg.png"。
- webpack4在
mini-css-extract-plugin
的loader中配置publicPath
webpack4也是配置publicPath,只不過配置方式稍有不同,如下:
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
hmr: process.env.NODE_ENV === 'development',
},
},
'css-loader',
],
},
],
},
參考文獻
- 生成的css檔案中background url()圖片路徑問題
- css中background背景屬性及背景圖片路徑問題