angular-cli icon indicating copy to clipboard operation
angular-cli copied to clipboard

Workspace library scss import

Open csisy opened this issue 2 years ago • 9 comments

🚀 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

  1. Changing the default dist output of the library to the node_modules and the automatically removed @ symbol is added to the path (in short dist/my-company/my-lib -> node_modules/@my-company/my-lib) resolves the scss import problem. The tsconfig.json must be adjusted as well. If this is the desired solution, then it should be the default generated with the CLI.
  2. 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 additional paths and this should be an operation that the generation (through the CLI) does automatically. Or at least extend the documentation.

csisy avatar Jul 13 '22 09:07 csisy

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 the includePaths paths in the application browser builder. See: https://angular.io/guide/workspace-config#style-preprocessor-options

alan-agius4 avatar Jul 13 '22 11:07 alan-agius4

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 the package.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 the includePaths 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.

csisy avatar Jul 14 '22 08:07 csisy

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.

alan-agius4 avatar Jul 14 '22 13:07 alan-agius4

I'm also trying to have workspace imports for my Angular library. However I don't get whats missing in the config.

image

ng-package.json

"assets": ["styles/*"]
image image

image

btxtiger avatar Nov 29 '22 11:11 btxtiger

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?

monkeycatdog avatar Feb 20 '23 18:02 monkeycatdog

Shouldn't an Angular library recognize a .scss file and compile it into css the way an app does?

BenRacicot avatar Mar 09 '23 22:03 BenRacicot

🦆 been here, done that..

janpauldahlke avatar Jul 26 '23 06:07 janpauldahlke

Any news?

adnanomerovic avatar Nov 23 '23 19:11 adnanomerovic

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. image

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.

btxtiger avatar Nov 26 '23 22:11 btxtiger