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內聯到html文檔中,這是背景圖片的路徑是相對于html文檔目錄,所以是正確的。

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',
        ],
      },
    ],
  },

參考文獻

posted @ 2019-06-17 12:40 wonyun 閱讀(...) 評論(...) 編輯 收藏
四川金7乐历史开奖号码查询