5

I'm trying to create a simple web app with material-components-vue and vue-cli with webpack, however, I found out that I cannot import stylesheets from node_modules without a preceding ~.

I have tried several webpack/vue-cli configs, and ended up with a config in vue.config.js passing loader options.

My vue.config.js looks like this:

module.exports = {
    css: {
      loaderOptions: {
        sass: {
          includePaths: [
              './node_modules', //here I include node_modules
            ]
        },
      }
    }
  }

So I expect to be able to import stuff like so:

@import 'normalize/normalize'

(assuming I have a directory called normalize in my node_modules which contains a file normalize.scss)

However, webpack throws an error, saying it cannot find the module.
But, this does work:

@import '~normalize/normalize'

This wouldn't be a problem if all @imports were written by me, but because I use a third-party module which has @imports inside them, webpack fails to compile.

EDIT 1:

As @Styx asked to

Share more configs, please

and

show the output of vue inspect --rule scss, and the whole file with this problematic import

Here it is:

My problematic file is pretty empty:

<template>
  <div id="app">
    <m-button>Hello</m-button>
  </div>
</template>

<script>
import Vue from 'vue'
import Button from 'material-components-vue/dist/button'
Vue.use(Button)

export default {
  name: 'App',
  components: {
}
</script>

<style lang="scss">
@import "~material-components-vue/dist/button/styles"; //this works
@import "material-components-vue/dist/button/styles"; //but this does not
</style>

My output from vue inspect --rule scss is located here

All other configs are as generated by vue init webpack <name>

EDIT 2: Exact steps to reproduce this issue:

  1. Initialize a vue-webpack app:
vue init webpack .
  1. Vue build: Runtime + Compiler (Default)
  2. Vue-router: no
  3. Package manager: npm

  4. Then, install sass-loader

npm i -D sass-loader node-sass
  1. Create a file vue.config.js and populate it with the following:
module.exports = {
    css: {
      loaderOptions: {
        sass: {
          includePaths: [
              './node_modules', //here I include node_modules
            ]
        },
      }
    }
  }
  1. After that, install a module containing scss/sass (E.g. for material-components-web, npm i material-components-web)

  2. Then, create an import to a stylesheet located in node_modules, like so:

@import '@material/button/mdc-button'; //mdc-button comes with material-components-web
  1. Finally, start the dev server:
npm run dev
  1. It will throw the following error:
 ERROR  Failed to compile with 1 errors                                                                        11:36:35 AM

 error  in ./src/App.vue

Module build failed: 
@import '@material/button/mdc-button';
^
      File to import not found or unreadable: @material/button/mdc-button.
      in /home/maxim/projects/holiday.js/stackoverflow/src/App.vue (line 18, column 1)

 @ ./node_modules/vue-style-loader!./node_modules/css-loader?{"sourceMap":true}!./node_modules/vue-loader/lib/style-compil
er?{"vue":true,"id":"data-v-7ba5bd90","scoped":false,"hasInlineConfig":false}!./node_modules/sass-loader/lib/loader.js?{"s
ourceMap":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue 4:14-359 13:3-17:5 14:22-367
 @ ./src/App.vue
 @ ./src/main.js
 @ multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server ./src/main.js

By the way, in the first example I wanted to import material-components-vue/dist/foo/styles, but here I import @material/foo.

ummw
  • 165
  • 2
  • 6

1 Answers1

2

In this configuration your vue.config.js is ignored. This file is used by @vue/cli-service, but you're using webpack-dev-server instead. Thus, your sass-loader doesn't receive this includePaths option.

You can either use modern vue create <app-name> command, or if you want to modify existing project:

  1. Open build/utils.js file.

  2. Find return ... in exports.cssLoaders function:

    return {
      ...
      sass: generateLoaders('sass', { indentedSyntax: true }),
      scss: generateLoaders('sass'),
      ...
    }
    
  3. Modify it like this:

    const includePaths = [path.resolve(__dirname, '..', 'node_modules')];
    return {
      ...
      sass: generateLoaders('sass', { indentedSyntax: true, includePaths }),
      scss: generateLoaders('sass', { includePaths }),
      ...
    }
    
  4. Remove unused vue.config.js file.

Styx
  • 9,863
  • 8
  • 43
  • 53
  • Hi. This helped me a lot already, but I have a follow-up question: I am under the impression that once I set includePaths as you did, my main.js cannot find a style file that is not in node_modules (typically in src/assets). Do you know if it is possible to include multiple paths with this method? Thanks – petosorus Jul 21 '20 at 13:47
  • @petosorus yes, it’s possible: `includePaths` in an array of paths, you can add as many items as you need there. However, these paths don’t disable normal path resolution, so you’ll still be able to use normal imports as usual. – Styx Jul 21 '20 at 17:28