webpack:sass-loader, scss中使用url加載圖片報NotFound的三個解決方法

問題描述:

使用vue-cli搭建好vue項目結構後,我在Home.scss中使用background-image: url('../../images/home_banner.jpeg');加載一個背景圖片,沒想到報錯:javascript

This relative module was not found:

* ../../images/home_banner.jpeg in ./node_modules/_css-loader@0.28.11@css-loader?{"sourceM ap":false}!./node_modules/_vue-loader@13.7.3@vue-loader/lib/style-compiler?{"vue":true,"id ":"data-v-5a90ec03","scoped":false,"hasInlineConfig":false}!./node_modules/_sass-loader@7.
1.0@sass-loader/lib/loader.js?{"sourceMap":false}!./node_modules/_vue-loader@13.7.3@vue-lo
ader/lib/selector.js?type=styles&index=0!./src/pages/Home.vue複製代碼

那這是爲何呢?雖然這是sass-loader的一個已知的問題,仍是要把解決過程記錄下來,豐富本身也造福後來人。css


版本描述:

"sass-loader": "^7.1.0",
"vue": "^2.5.2",
"webpack": "^3.6.0"複製代碼

代碼結構:

Home.vuehtml

<template>
  <div class="home">
    <PageHeader></PageHeader>
    <div class="img-wrap">
      <img src="../assets/images/home_banner.jpeg">
    </div>
  </div>
</template>

<script>
import PageHeader from '../components/PageHeader'

export default {
  data () {
    return {}
  },
  components: {
    'PageHeader': PageHeader
  }
}
</script>

<style lang="scss" scoped>
@import "../assets/scss/pages/Home.scss"
</style>

複製代碼

Home.scss
vue

div.img-wrap{
  position: absolute;
  width: 100%;
  height: 100%;
  background-image: url('../../images/home_banner.jpeg');
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center 75%;
}
複製代碼

src/java

.
├── App.vue
├── assets
│   ├── images
│   │   ├── home_banner.jpeg
│   │   └── user_default_grey.png
│   └── scss
│       ├── components
│       │   └── PageHeader.scss
│       ├── pages
│       │   └── Home.scss
│       └── _variables.scss
├── components
│   ├── PageFooter.vue
│   └── PageHeader.vue
├── main.js
├── pages
│   ├── Admin.vue
│   └── Home.vue
├── router
│   └── index.js

複製代碼


思考思路:

1. 一開始走錯了方向,老是以爲本身的路徑寫的有問題;是由於我己對webpack怎麼處理靜態資源不清楚,見參考1;node

2. 因爲我在Home.vue中,直接在img 的src使用相對路徑引用圖片,也沒問題;因此,我就想應該是在scss中使用url有啥問題,最後各類搜索,發現這是個已知的問題,sass-loader的url問題,在官方文檔中有描述,見參考2;webpack


解決方法:

1. 逃避型:

不使用單獨的scss文件,scss的內容寫在Home.vue的style中,驗證可用;git

<style lang="scss" scoped>
div.img-wrap{
  position: absolute;
  width: 100%;
  height: 100%;
  background-image: url('../assets/images/home_banner.jpeg');
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center 75%;
}
</style>
複製代碼

2. 間接型:

不在scss文件中設置background-image,而是在vue中設置,方法以下:github

<template>
  <div class="home">
    <PageHeader></PageHeader>
    <div class="img-wrap" :style="{backgroundImage: 'url('+imageUrl+')'}"> 
    </div>
  </div>
</template>

<script>
import PageHeader from '../components/PageHeader'

export default {
  data () {
    return {
      imageUrl: require('../assets/images/home_banner.jpeg')
    }
  },
  components: {
    'PageHeader': PageHeader
  }
}
</script>
複製代碼

3. 解決型

使用官方文檔中推薦的方法,使用resolve-url-loader來解決sass-loader缺乏url rewriting的功能。web

設置以下:(注意sourceMap須要設置爲true)

//將resolve-url-loader置於css-loader與sass-loader之間
//resolve-url-loader以前的loader都須要source-maps
//source-maps required for loaders preceding resolve-url-loader (regardless of devtool).
rules: [
  {
    test: /\.scss$/,
    use: [
      ...
      {
        loader: 'css-loader',
        options: {...}
      }, {
        loader: 'resolve-url-loader',
        options: {...}
      }, {
        loader: 'sass-loader',
        options: {
          sourceMap: true,
          sourceMapContents: false
        }
      }
    ]
  },
  ...
]
複製代碼

參照上述設置,在vue工程中的修改以下:

/config/index.js
dev中
cssSourceMap設置爲true

/build/utils.js
// generate loader string to be used with extract text plugin
  function generateLoaders (loader, loaderOptions) {
    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

    if (loader === 'sass') {//增長resolve-url-loader
      loaders.push({
        loader: 'resolve-url-loader',
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }

    if (loader) {
      loaders.push({
        loader: loader + '-loader',
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }

    // Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }
  }複製代碼

這樣之後,咱們就能夠愉快的在scss文件中使用url了。


參考:

1. webpack處理靜態資源

2. sass-loader的url問題

相關文章
相關標籤/搜索