Search code examples
vue.jswebpackdata-bindingaxiosvuex

Vue bind style dynamic backgroundImage with parameter using asset


I'm trying to bind background images dynamically but there seems to be trouble compiling the assets. What's weird is that it works but no at the same time. vue_dynamic_image_err_compile

I've tried various solutions from SO and nothing get rids of the compilation error (which still compile based on the image above):

How The Project is Set Up

Laravel Sanctum as the backend, Vue SPA for the frontend and utilising Axios for communications.

Topic.vue Component

<div
    v-for="topic in topics"
    :key="topic.id"
    class="col-12 col-sm-6 col-lg-3 mb-4 d-flex justify-content-center"
>
    <div
        class="card-topic d-flex align-items-end"
        :style="inlineBgImage(topic.src)"
    >
        <div class="card-topic__button py-3 text-center w-100">
            <a href class="card-topic__link">{{ topic.title }}</a>
        </div>
    </div>
</div>

Script in Topic.vue

<script>
import { mapState } from 'vuex'

export default {
    computed: {
        ...mapState('topic', ['topics']),
    },
    created() {
        this.$store.dispatch('topic/fetchTopics')
    },
    methods: {
        inlineBgImage(src) {
            let bgImage = require('@/assets' + src)

            return {
                backgroundImage: `url("${bgImage}")`,
            }
        },
    },
}
</script>

In the inlineBgImage(src) methods, the background-image is successfully applied if the require is hardcoded i.e. let bgImage = require('@/assets/img/topic/myself.jpg'). Once I used the src value, it broked but still works(Failed to compile. page appear)

Assets

Below is the asset folder structure

enter image description here

All SCSS files are imported to app.scss which are then imported to main.js

_variables.scss

enter image description here

The "undefined variable" does exist

app.scss

This is how I import the _variable.scss file in app.scss; @import 'variables.scss';. The import comes first before other files. enter image description here

I've also tried:

  • @import 'variables';
  • @import '_variables';
  • @import '_variables.scss';

It still gives out errors.

Error Details in Terminal

I want to reiterate that these errors does not appear if I hardcode the bgImage e.g. require('@/assets/img/topic/myself.jpg'). I don't understand how these changes affect the compiler.

ERROR  Failed to compile with 6 errors                                                                                                  12:37:58 PM
 error  in ./src/assets/scss/card.scss

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined variable.
   ╷
16 │     background-color: $dark-blue;
   │                       ^^^^^^^^^^
   ╵
  src\assets\scss\card.scss 16:23  root stylesheet

 @ ./src/assets/scss/card.scss 4:14-233 14:3-18:5 15:22-241
 @ ./src sync ^\.\/assets.*$
 @ ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue
 @ ./src/router/index.js
 @ ./src/main.js
 @ multi (webpack)-dev-server/client?http://192.168.100.14:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.js

 error  in ./src/assets/scss/search.scss

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined variable.
   ╷
27 │     color: $blue;
   │            ^^^^^
   ╵
  src\assets\scss\search.scss 27:12  root stylesheet

 @ ./src/assets/scss/search.scss 4:14-235 14:3-18:5 15:22-243
 @ ./src sync ^\.\/assets.*$
 @ ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue
 @ ./src/router/index.js
 @ ./src/main.js
 @ multi (webpack)-dev-server/client?http://192.168.100.14:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.js

 error  in ./src/assets/scss/image.scss

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined variable.
   ╷
33 │     color: $white;
   │            ^^^^^^
   ╵
  src\assets\scss\image.scss 33:12  root stylesheet

 @ ./src/assets/scss/image.scss 4:14-234 14:3-18:5 15:22-242
 @ ./src sync ^\.\/assets.*$
 @ ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue
 @ ./src/router/index.js
 @ ./src/main.js
 @ multi (webpack)-dev-server/client?http://192.168.100.14:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.js

 error  in ./src/assets/scss/button.scss

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined variable.
  ╷
2 │     color: $light-blue;
  │            ^^^^^^^^^^^
  ╵
  src\assets\scss\button.scss 2:12  root stylesheet

 @ ./src/assets/scss/button.scss 4:14-235 14:3-18:5 15:22-243
 @ ./src sync ^\.\/assets.*$
 @ ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue
 @ ./src/router/index.js
 @ ./src/main.js
 @ multi (webpack)-dev-server/client?http://192.168.100.14:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.js

 error  in ./src/assets/scss/header.scss

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined variable.
  ╷
4 │     background-color: $dark-blue;
  │                       ^^^^^^^^^^
  ╵
  src\assets\scss\header.scss 4:23  root stylesheet

 @ ./src/assets/scss/header.scss 4:14-235 14:3-18:5 15:22-243
 @ ./src sync ^\.\/assets.*$
 @ ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue
 @ ./src/router/index.js
 @ ./src/main.js
 @ multi (webpack)-dev-server/client?http://192.168.100.14:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.js

 error  in ./src/assets/scss/nav.scss

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined variable.
  ╷
6 │     color: $light-blue;
  │            ^^^^^^^^^^^
  ╵
  src\assets\scss\nav.scss 6:12  root stylesheet

 @ ./src/assets/scss/nav.scss 4:14-232 14:3-18:5 15:22-240
 @ ./src sync ^\.\/assets.*$
 @ ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue?vue&type=script&lang=js&
 @ ./src/views/Topic.vue
 @ ./src/router/index.js
 @ ./src/main.js
 @ multi (webpack)-dev-server/client?http://192.168.100.14:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.js

Other Details

The topic.src from v-for="topic in topics" will yield a String, for e.g. /img/topic/myself.jpg.


Solution

  • inlineBgImage(src) {
        let fileExt = src.substring(src.lastIndexOf('.'))
    
        src = src.replace('/img/', '')
        src = src.replace(fileExt, '')
    
        let bgImage = require('@/assets/img/' + src + fileExt)
    
        return {
            backgroundImage: `url("${bgImage}")`,
        }
    }
    

    Kudos to skirtle for giving a solution at forum.vuejs.org. As skirtle mentioned, Webpack handles expression and fixed string parameter differently. I did change the solution a bit in case future files have different file extension. You see skirtle original answer and explanation there.