As in Material Component Web's example, I want to be able to import SCSS from my node_modules
like this:
@import '@material/elevation/mdc-elevation';
However, I'm getting this error message when trying to run the webpack build:
File to import not found or unreadable: @material/elevation/mdc-elevation.
@import './~/@material/elevation/mdc-elevation.scss';
doesn't work either.
I'm pretty sure the issue is somewhere in my webpack config, but I can't figure out where.
What did they do in Material Components Web's Vue.js example in order to make it work?
Here's my npm-debug.log in case you need it. And here's the corresponding Git repository: sk22/spg-tinf-sem03/proj01
Thanks in advance!
Edit: I want to be able to import the scss files, not the compiled css.
Got it.
here's a part of my webpack 2 config's
module.rules
:So what did I do wrong? My
options
object was placed in the rule directly, not the loader.The old webpack config rule looked like this:
See the difference? Instead of the 'sass-loader' string, I extended it to an object, containing the
loader
name and theoptions
object, because theoptions
only apply to thesass-loader
.(You could also drop the path.resolve and only write 'node_modules', but it might be safer to leave it.)
Check out this documentation page for further information. https://webpack.js.org/configuration/module/#rule-use
Without that loader, you must prefix each import with a
~
, which webpack converts to thenode_modules
folder, at least with my previous configuration. But this will break 3rd party SCSS frameworks like Material Components Web, because they use@import
statements without a leading~
themselves, for example here.Inside .vue files
This will not work in .vue files, as
vue-loader
just uses sass-loader without any options by default. So if you want that to work, you probably need to make use of vue-loader's own options, as described in its documentation.(I'm unable to get it to work for some reason I don't know...)
EDIT: Webpack has a section on sass-loader now: https://webpack.js.org/loaders/sass-loader/ also mentioning includepaths.
I had the same issue with @material and Vue. I managed to resolve the problem without adjusting the
use
property directly.Solution
Step 1: First create a default Vue 2.1 project using the CLI. Your file structure will have a
./build
directory.Step 2: Open the file 'utils' you will see a
cssLoaders()
function which returns an object/map for the languagesvue-loader
supports.You will see both
sass
andscss
in that map.Step 3: Change the values of
sass
andscss
to:Step 4: Go to the .vue file you're using and change the
lang
attribute in your<style>
element to eithersass
orscss
.Step 5: After you've done that go to the terminal/console and install
sass-loader
with:npm install sass-loader node-sass webpack --save-dev
Step 6: Then run
npm run dev
and it should work.Why does this work?
Libraries
I dug around a bit and it turns out sass-loader uses node-sass which has some options such as
includePaths
one mentioned by @22samuelk. IncludePaths tells node-sass or rather the underlying library LibSass to include sass files from that directory/path.Vue
Sass-loader options
By default Vue expects your assets to be in your projects
src/assets
folder (correct me if I'm wrong). You can however use~
to indicat you want to start at your projects root which would look like `~/node_modules/@material/smth/mdc-smth.scss.Now if you want your sass-loader to use something other than those options you need to explicitly tell them.
Hence
path.resolve(__dirname, '../node_modules'
since theutils
file is in./build
and you need to use an absolute path forsass-loader
to understand where to look.Vue-loader config
This is not really specific to the question but the vue-loader config defined in
vue-loader.conf.js
works as follows:It uses the map returned by
cssLoaders()
to build the loaders expected by webpack. The returned map ({key:value}
) is then used by providingkey
as a file extension used intest:
for a loader object. Thevalue
is used as the loader object. Which would like like this:Where
key
is the file extention. In this case that would be eithersass
orscss
. And//ld//
is the loader you which to use. Which is shown in Step 3 as'sass'
.Hopefully this clears up some stuff. Took me a while because I just started using Vue.