The `/deep/` selector is not working using sass-loader in my VueJS application
Asked Answered
S

2

8

In my Vue 2.6.10 webpack application I am trying to add SASS as our team wants to migrate our legacy application from LESS to SCSS. In my package.json I have installed these to my devDependencies per these docs:

  • sass (v.1.32.8)
  • sass-loader (v10.1.1)

Then installed node-sass (v5.0.0) to my dependencies.

My node version is: v15.4.0. According to these docs this is the correct version for node-sass v5+.

In my Vue components I am trying to use the /deep/, ::v-deep, or >>> selectors. I threw together a working playground where I have a ParentComp.vue target a ChildComp.vue's inner styles using /deep/ like this:

<style lang="scss" scoped>
  .parent-container {
    & /deep/ .child-comp {
      background-color: tomato;
      color: white;
    }
  }
</style>

Yay! It works great in my playground using the same versions of things that I have control over in that playground.

In my application when I try this exact same setup I get this compile error:

./src/components/MenuBarComp.vue (./node_modules/css-loader/dist/cjs.js?
{"sourceMap":true}!./node_modules/vue-loader/lib/style-compiler?
{"optionsId":"0","vue":true,"id":"data-v-4630c6ac","scoped":true,"sourceMap":true}!
./node_modules/sass-loader/dist/cjs.js?
{"additionalData":"/n          @import /"@/styles/_variables.scss/";/n        ","sourceMap":true}!
./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/components/MenuBarComp.vue)


Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: expected selector.
   ╷
77 │   & /deep/ .child-test{
   │     ^
   ╵
  src/components/MenuBarComp.vue 77:5  root stylesheet

According to many other suggestions which I have tried, I should try using ::v-deep or >>>. When I try to use these selectors it compiles fine and no longer throws an exception, but nothing happens. No CSS is actually rendered like .parent[data-23423423] .child {}. But then I see other articles about how this is not supported in SCSS.

So then I go back to trying to figure out what could cause this error and I have tried dozens of things over the course of several days to try and fix this issue like:

  • downgrading node-sass / sass / sass-loader versions to other versions to try and get things to work
  • npm rebuild node-sass --force
  • rimrafing node_modules
  • Clearing entire npm cache and many other things

I already have several pre-existing CSS related packages in my package.json:

  • css-loader (v.3.1.0)
  • less (v3.0.4)
  • less-loader (v4.1.0)
  • mini-css-extract-plugin (v0.6.0)
  • optimize-css-assets-webpack-plugin (v5.0.3)
  • postcss-import (v11.0.0)
  • postcss-loader (v2.0.8)
  • postcss-url (v7.2.1)
  • vue-style-loader (v3.0.1)

Finally here is how my loaders are setup in webpack:

  function generateLoaders(loader, loaderOptions) {
    const loaders = options.usePostCSS
      ? [cssLoader, postcssLoader]
      : [cssLoader];

    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 [MiniCssExtractPlugin.loader].concat(loaders);
    } else {
      return ['vue-style-loader'].concat(loaders);
    }
  }

  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
  return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    sass: generateLoaders('sass'),
    scss: generateLoaders('sass', {
      additionalData: `
          @import "@/styles/_variables.scss";
        `,
    }),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus'),
  };
};

How can I get the /deep/ selector to work?

Singletary answered 2/5, 2021 at 12:49 Comment(0)
S
5

This is because /deep/ is not supported by sass. You need to explicitly set your sass-loader to use node-sass like this:

loader: 'sass-loader', options: { implementation: require('node-sass')

sass-loader has a note on their page that says:

Beware the situation when node-sass and sass were installed! By default the sass-loader prefers sass. In order to avoid this situation you can use the implementation option.

The implementation options either accepts sass (Dart Sass) or node-sass as a module.

So your specific code would end up being as sass-loader uses:

scss: generateLoaders('sass', {
  implementation: require('node-sass'),
  additionalData: `
      @import "@/styles/_variables.scss";
    `,
}),
Singletary answered 2/5, 2021 at 13:27 Comment(2)
Well. Vuetify uses /deep/, and recommends to use sass instead of node-sass... dependency hellFair
This post save me... In my case I found /deep/ issues in Angular 7 project. This post guide me that I have Dart-sass install on my global node_modules which make sass-loader to use dart-sass instead of node-sass.Morman
A
2

Most of the new angular builds face the same issue due to angular-build version mismatch. There we can use as below,

:host ::ng-deep instead of /deep/

Audette answered 7/9, 2022 at 6:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.