angular-cli
angular-cli copied to clipboard
Workspace library scss import
🚀 Feature request
Command (mark with an x
)
- [ ] new
- [x] build
- [ ] serve
- [ ] test
- [ ] e2e
- [x] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] extract-i18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc
Description
With a workspace architecture, the exported stylesheets cannot be imported using package name. Given a library (lib
) and a project (app
) in an angular workspace. The library properly copies an scss file to the dist
folder (which is the default output folder) and adds it to the exports
section of the package.json
. However, the consuming app cannot @import
or @use
the exported scss file.
Given the following files:
- dist/my-company/my-lib/assets/_theme.scss
- projects/app/src/styles.scss
And the following export in the package.json
of the library:
"exports": {
"./theme": {
"sass": "./assets/_theme.scss"
}
},
And the default settings that the Angular CLI generates (with ng new library
and so on...),
Describe the solution you'd like
With the settings mentioned above, importing an exported scss file should work out of the box (currently it does not compile with the error SassError: Can't find stylesheet to import.
).
// styles.scss
@use "@my-company/my-lib/theme" as myTheme;
Describe alternatives you've considered
- Changing the default
dist
output of the library to thenode_modules
and the automatically removed@
symbol is added to the path (in shortdist/my-company/my-lib
->node_modules/@my-company/my-lib
) resolves the scss import problem. Thetsconfig.json
must be adjusted as well. If this is the desired solution, then it should be the default generated with the CLI. - Create an NPM Link to the dist directory (which has its own pros and cons). If this is the desired solution, then the
tsconfig.json
does not need to define additionalpaths
and this should be an operation that the generation (through the CLI) does automatically. Or at least extend the documentation.
The sass actually doesn't actually support package exports, so the exports cannot be used to rename/shorten the paths of stylesheets, as such in the above case the _theme.scss
need to be placed parallel to the package.json
.
You will also need to do a couple of other steps;
- Change the library dist from
my-company/my-lib
to@my-company/my-lib
. (We could probably handle this out-of-the-box). - add
dist
to theincludePaths
paths in the application browser builder. See: https://angular.io/guide/workspace-config#style-preprocessor-options
Thank you for the fast reply.
The sass actually doesn't actually support package exports, so the exports cannot be used to rename/shorten the paths of stylesheets, as such in the above case the
_theme.scss
need to be placed parallel to thepackage.json
.
According to my testing it actually works - but only if the library is located under node_modules
. Excerts:
The compiled library files (copied into node_modules
)
// node_modules/@mycomp/mylib/package.json
"name": "@mycomp/mylib",
"exports": {
"./theme": {
"sass": "./assets/_theme.scss"
},
"./package.json": {
"default": "./package.json"
},
...
}
// node_modules/@mycomp/mylib/assets/_theme.scss
@mixin theme() {
body {
background-color: gray;
}
}
The source stylesheet file of the sandbox app:
// projects/sandbox/src/styles.scss
@use "@mycomp/mylib/theme" as t;
@include t.theme();
And after a successful compilation, the destination contains the expected css:
// dist/sandbox/styles.<hash>.css
body{background-color:gray}
May I misunderstand something? It only works if the library is located under node_modules
.
You will also need to do a couple of other steps;
- Change the library dist from
my-company/my-lib
to@my-company/my-lib
. (We could probably handle this out-of-the-box).- add
dist
to theincludePaths
paths in the application browser builder. See: https://angular.io/guide/workspace-config#style-preprocessor-options
Forgot to mention that in the OP that I've tried these steps, but now I've done it again, and the result is the same. As you've stated, the "aliasing" does not work in this case, so
@use "@mycomp/mylib/theme" as t; // does not work
@use "@mycomp/mylib/assets/theme" as t; // does work
However, I can't seem to figure out why the two cases (node_modules
vs dist
) differs. I.e. why the above works if the library is placed under the node_modules
folder (a.k.a. the library is installed through npm
). It might not be an angular-related bug at all.
According to my testing it actually works - but only if the library is located under node_modules
This works because Webpack sass-loader has it's own resolver but when using Sass directly this doesn't work. I don't suggest to rely on this behaviour though.
I'm also trying to have workspace imports for my Angular library. However I don't get whats missing in the config.

ng-package.json
"assets": ["styles/*"]


I'm trying to use https://github.com/LuisGazcon/sass-alias with @angular-builders/custom-webpack
but it doesn't work with angular material and other imports.
module.exports = (config, options, targetOptions) => {
base(config, options, targetOptions);
config.module.rules.push({
test: /^.*\.(sass|scss)$/,
use: [
{
loader: 'sass-loader',
options: {
sassOptions: {
importer: create({
'@work/snakes': path.join(process.cwd(), 'libs/work/snakes/src'),
}),
},
},
},
],
});
return config;
};
do you guys have the ability to make it extensible?
Shouldn't an Angular library recognize a .scss file and compile it into css the way an app does?
🦆 been here, done that..
Any news?
I found out for Angular Libraries, you have to manually add an export entrypoint for the styles in the library's package.json
So in projects/lib/package.json
, add:
"exports": {
"./styles/": "./styles/",
}
The ./styles/
path on the right side, must exist in your dist folder. If you have a theme
folder, rename it to theme.
This way you should be able to import the library styles via npm module namespace, like:
@import "mat-icon-button-sizes/styles/mat-icon-button-sizes";
@import "mat-icon-button-sizes/styles/mat-icon-button-size.mixin";
It will also work, if you map a single file directly to the root:
"exports": {
"./style.scss": "./styles/mat-icon-button-sizes.scss"
},
However it might not show up properly in your IDE, but it will build without issues.
My solution was, to add another build cmd to add a css version to the root, which also enables compatibility to css users.
"build:css": "node-sass projects/mat-icon-button-sizes/styles/mat-icon-button-sizes.scss dist/mat-icon-button-sizes/style.css",
"build:lib": "ng build mat-icon-button-sizes && npm run build:css",
and accordingly in projects/lib/package.json
"exports": {
"./styles/": "./styles/",
"./style.css": "./style.css"
},
In the end, you could add any extra build script, that modifies your dist build to fix the implicit path mapping.