阅读 929

webpack:sass-loader, scss中使用url加载图片报NotFound的三个解决方法

问题描述:

使用vue-cli搭建好vue项目结构后,我在Home.scss中使用background-image: url('../../images/home_banner.jpeg');加载一个背景图片,没想到报错:

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的一个已知的问题,还是要把解决过程记录下来,丰富自己也造福后来人。


版本描述:

"sass-loader": "^7.1.0",
"vue": "^2.5.2",
"webpack": "^3.6.0"复制代码

代码结构:

Home.vue

<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

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/

.
├── 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;

2. 由于我在Home.vue中,直接在img 的src使用相对路径引用图片,也没问题;所以,我就想应该是在scss中使用url有啥问题,最后各种搜索,发现这是个已知的问题,sass-loader的url问题,在官方文档中有描述,见参考2;


解决方法:

1. 逃避型:

不使用单独的scss文件,scss的内容写在Home.vue的style中,验证可用;

<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中设置,方法如下:

<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的功能。

设置如下:(注意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问题


关注下面的标签,发现更多相似文章
评论