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了。
参考:
转载自:https://juejin.cn/post/6844903866677329928