Tilde ~ in SCSS @use statement no longer resolving to node_modules as of Angular 13
Asked Answered
L

4

34

After upgrading an Angular 12 project to Angular 13 I encountered an issue where SCSS was no longer to locate a shared style sheet in a library. It appears that that Tilde (~) no longer resolves to node_modules.

Broken: @use '~my-angular-lib' as lib;

Works: @use '../node_modules/my-angular-lib' as lib;

I noticed that angular material just directly refences '@angular/material' as of Angular 13 but I can't figure out how to get that to work with my library. It seems kind of hacky to use a relative path to node_modules every time.

What is the current best method of refencing a style sheet in node_modules, or what am I missing to where ~ no longer points to node_modules?

Liu answered 23/11, 2021 at 14:31 Comment(0)
P
22

Angular has been deprecating the use of ~ for Sass @use and @import statements for a while.

Officially, as of Angular version 13 the usage of tilde imports won't be supported anymore.

Here about the why this is working without tilde

Premer answered 27/11, 2021 at 15:53 Comment(6)
Is now the use of @use "node_modules/..."; the only alternative?Codification
It's not clear then, what should I use instead of `import "~@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css" to reference 3rd party css in my Angular library?Medawar
FYI, If you're using ~@your-library, then @your-library will work just fine ;)Duplet
@RaphaëlBalet out of curiosity. How come it works without the tilde?Loyce
@Loyce I honestly don't now. SorryDuplet
@RaphaëlBalet in the mean time, I do. See: webpack.js.org/loaders/sass-loader/#resolving-import-at-rulesLoyce
K
32

I encountered the same problem and found the solution:

  1. Open angular.json file;

  2. In every app configuration set:

     "stylePreprocessorOptions": {
       "includePaths": [
         "./node_modules"
       ]
     }  
    
  3. remove ~ in every import;

Kenaz answered 28/6, 2022 at 19:33 Comment(4)
Important to note WHERE TO INSERT in angular.json: projects.PROJECT-NAME.architect.build.optionsMattah
This is the true working solutionContrary
@Contrary working, yes, but not ideal. Took me longer than I would've liked to find this solution :/ I love Angular but they sure love to break things on every new version...Marci
Yay!! Works very well!Divulge
P
22

Angular has been deprecating the use of ~ for Sass @use and @import statements for a while.

Officially, as of Angular version 13 the usage of tilde imports won't be supported anymore.

Here about the why this is working without tilde

Premer answered 27/11, 2021 at 15:53 Comment(6)
Is now the use of @use "node_modules/..."; the only alternative?Codification
It's not clear then, what should I use instead of `import "~@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css" to reference 3rd party css in my Angular library?Medawar
FYI, If you're using ~@your-library, then @your-library will work just fine ;)Duplet
@RaphaëlBalet out of curiosity. How come it works without the tilde?Loyce
@Loyce I honestly don't now. SorryDuplet
@RaphaëlBalet in the mean time, I do. See: webpack.js.org/loaders/sass-loader/#resolving-import-at-rulesLoyce
S
5

To use @use 'my-angular-lib' as lib; you need to make sure to export the relevant files in your angular libraries package.json and ng-package.json files (see https://github.com/ng-packagr/ng-packagr/blob/master/docs/copy-assets.md).

Here my configuration for example:

// package.json
  ...,
  "exports": {
    ".": {
      "sass": "./src/lib/_index.scss"
    }
  },
  ...
// ng-package.json
  ...,
  "assets": [
    "./src/lib/_index.scss",
    "./**/*-theme.scss"
  ],
  ...

All my theme related component files have the suffix -theme and I have one scss file (_index.scss) that contains only one @mixin to @include theme specific component styles. For example:

// src/lib/_index.scss
@use './some/some-component-theme' as *;
@mixin lib-theme($theme) {
  @include some-component-theme($theme);
}

Hint: Sometimes I had to manually remove the .angular/cache folder when working with local libraries. So try this if something odd happens during the build process.

Slag answered 7/2, 2022 at 13:54 Comment(2)
This still leaves you with only a mixin, but doesn't do anything. How do you tell scss to pack this mixin in the bundle?Kirchhoff
@Pieterjan: I don't follow you. For me the mixin is packed in the lib-bundle that I push to npm and I can use it in the main projects theme.scss with @use 'lib' as *; and @include lib-theme($theme).Slag
C
2

Just omit the ~ from the import statement. It works!!

Resolving import at-rules - references

Webpack provides an advanced mechanism to resolve files.

The sass-loader uses Sass's custom importer feature to pass all queries to the Webpack resolving engine. Thus you can import your Sass modules from node_modules.

@import "bootstrap";

Using ~ is deprecated and can be removed from your code (we recommend it), but we still support it for historical reasons. Why can you remove it? The loader will first try to resolve @import as a relative path. If it cannot be resolved, then the loader will try to resolve @import inside node_modules.

Prepending module paths with a ~ tells webpack to search through node_modules.

@import "~bootstrap";

It's important to prepend it with only ~, because ~/ resolves to the home directory. Webpack needs to distinguish between bootstrap and ~bootstrap because CSS and Sass files have no special syntax for importing relative files. Writing @import "style.scss" is the same as @import "./style.scss";

Coel answered 21/6, 2023 at 5:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.