以前在使用webpack3構建基於less預處理的項目時,在對指定的元素使用background-image: url(xxx)
來設置背景圖片時,本地開發是ok的,可是在項目編譯產出後背景圖片就找不到;目前用webpack4開發項目時,一樣遇到相似的問題;因此就藉此機會探討一下產生問題的緣由。css
項目webpack有關css的配置僞碼以下:html
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大小就打包輸出文件。vue
此時在咱們的index.less
文件中設置body的背景圖片以下:webpack
body { background-image: url('./img/bg.png'); }
此時本地開發能夠看到背景圖片,而編譯產出css的文件,背景圖片地址不能正確加載,經過測試發現是圖片路徑出現問題,以下圖:
git
從產出的css文件內容來看,body元素的background-image的圖片url相對地址是webpack配置產出圖片路徑,可是頁面實際展現時卻發現圖片路徑爲:/xx/../dist/static/static/img/bg_ebdbe98.png。github
爲何會背景圖片路徑會多了一個static
前綴?查詢資料發現:web
css文件中設置的background-image的url相對地址是相對於當前css文件目錄來獲得的less
由於,項目中設置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
內聯到html文檔中,這是背景圖片的路徑是相對於html文檔目錄,因此是正確的。url
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文件,兩者環境都會出現問題;
在知道問題產生緣由後,也就知道該如何解決問題了。最佳的解決方法以下:
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"。
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', ], }, ], },