36

Since angular 13, using a tilde (~) to import SCSS files from the node_modules

close.component.scss

:host ::ng-deep {
    // Configuration
    @import "~bootstrap/scss/functions";
    @import "~bootstrap/scss/variables";
    @import "~bootstrap/scss/mixins";

    // Layout & components
    @import "~bootstrap/scss/close";
}

results in the following warning after running ng build:

Warning: 'C:\repos\...\src\lib\components\close\close.component.scss' imports '~bootstrap/scss/close' with a tilde. Usage of '~' in imports is deprecated.

Changing this and removing the tilde is easy. But VS Code doesn't find the file anymore when ctrl clicking the scss-path. It thinks it's located at

C:\repos\...\src\lib\components\close\bootstrap\scss\close

I've already tried this change but it changes nothing.

Does anyone know how to fix this?

Edit

For those wondering why we need :host ::ng-deep around the @import statements, it scopes the styles within to the component. A good example here is the bs-list-group and bs-list-group-item which I use like this:

<bs-list-group>
    <bs-list-group-item>Cras justo odio</bs-list-group-item>
    <bs-list-group-item>Dapibus ac facilisis in</bs-list-group-item>
    <bs-list-group-item>Morbi leo risus</bs-list-group-item>
    <bs-list-group-item>Porta ac consectetur ac</bs-list-group-item>
    <bs-list-group-item>Vestibulum at eros</bs-list-group-item>
</bs-list-group>

The following scss imports in list-group.component.scss

// Configuration
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";

// Layout & components
@import "~bootstrap/scss/list-group";

Result in the following

Bootstrap listview with scoped styles

On the other hand:

:host ::ng-deep {
    // Configuration
    @import "~bootstrap/scss/functions";
    @import "~bootstrap/scss/variables";
    @import "~bootstrap/scss/mixins";

    // Layout & components
    @import "~bootstrap/scss/list-group";
}

Where ng-deep removes the component scopes, and :host is replaced with the attribute angular applies on the BsListViewComponent (in this case [_nghost-bkg-c64]). This lets the styles work for the entire BsListviewComponent, since the scopes were removed from the css selectors.

Bootstrap listview with stripped scopes

This actually DOES work...

Pieterjan
  • 2,738
  • 4
  • 28
  • 55
  • Why are your imports in a selector ? – MGX Sep 26 '22 at 11:59
  • Because I'm using angular, this scss file is for a component and thus angular scopes these styles to the component. `.example` would become `*[_ngcontent-wcc-c60] .example` after the build. Adding `::ng-deep` removes these scopes right-hand side of it. This way, I'm able to make the bootstrap styles flow over multiple cooperating angular components – Pieterjan Sep 26 '22 at 12:03
  • But angular material seems to do this [totally different](https://github.com/angular/components/blob/main/src/material/checkbox/checkbox.scss)... – Pieterjan Sep 26 '22 at 12:09
  • This is wrong. Imports go to the head of the file, NOT inside the selectors. –  Sep 26 '22 at 12:09
  • @E.Maggini is right, and you're wrong about `this scss file is for a component and thus angular scopes these styles to the component` : imports are juste imports, they do not add content to your CSS file (it's `@include` that does that). Imports should go at the top of your code. Not that it resolves your issue, but I wanted to point it out ... – MGX Sep 26 '22 at 12:34
  • See updated question – Pieterjan Sep 26 '22 at 13:52

2 Answers2

45
  1. In angular.json file

  2. Add this below build -> options:

"stylePreprocessorOptions": {
   // other options...
   "includePaths": [
     "./node_modules"
   ]
 }  
  1. Remove ~ in every import

Take this warning with a grain of salt: It might be better to explicitly use the node_modules/ prefix instead, especially if more than one person is working on this project.

Valerij Dobler
  • 1,848
  • 15
  • 25
irwin
  • 451
  • 3
  • 4
  • 19
    In my project I did not already have a `stylePreprocessorOptions` setting and I did not understand where to put it. After looking a bit, this should go into `build` -> `options` section, in my case I put it directly under the `"styles"` entry. – Guss Nov 08 '22 at 09:14
  • 2
    Yes, it should directly go under `build > options`. Reference: https://angular.io/guide/workspace-config#style-preprocessor-options – Rhythm Ruparelia Nov 17 '22 at 07:37
  • 2
    If you don't want to add all node modules, you can add individual paths, e.g. for `~swiper/scss`, `~swiper/scss/autoplay`, etc., just remove `"./node_modules"` and add `"./node_modules/swiper"`. Add an entry for each package you want to include. – wraiford Dec 07 '22 at 15:07
  • when I do this (after removing the tilde from `@import '~@angular/material/theming';`), I get "Cannot find mixin 'mat-elevation'" on a line like this: `@include mat-elevation(8);` – Cee McSharpface Dec 13 '22 at 14:17
  • 1
    This still doesn't allow me to ctrl+click on the path – Pieterjan Feb 17 '23 at 15:06
8

You have to replace with the path to the css, something like :

@import node_modules/bootstrap/scss/mixins'  

Before to do that, I recommande you to go on the bootstrap file that you want to import and get the relative path to the file.

The in your scss file replace the ~ path with the relative path.

Becarful to not include .scss file inside the path.

user1075296
  • 581
  • 3
  • 10
  • 2
    Thanks for the reply. This compiles fine too, but it still doesn't allow me to ctrl+click the paths (`@import "node_modules/bootstrap/scss/functions";`) – Pieterjan Sep 26 '22 at 13:17