Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage SCSS stylesheets across a monorepo with different libraries sharing variables?

I have an angular monorepo set up via Nrwl and am using Angular Material's theming, which uses SASS.

I want the SCSS source files to import at the project level where I'll override default color variables for theming.

The problem I'm running into is that I want to import SCSS source files into other apps/libraries within my monorepo, and to projects outside of this monorepo.

I can write my imports like:

@import "../other-lib/style.scss"; 

...which will work for anything inside of the monorepo.

Or I can write it like this:

@import "~@my-organization/other-lib/style.scss"; 

...which won't work inside of my monorepo, AFAIK.

How do I get it to work in both contexts?

It's setup something like the diagram below.

enter image description here

like image 566
Kevin Beal Avatar asked May 19 '18 18:05

Kevin Beal


1 Answers

I think I might have something here, this is the solution I've adopted after some back 'n forth with the NRWL team.

I create an NX workspace by first creating a project with the angular CLI, and then adding the extensions, like so:

  • ng new myproject (cd into myproject root)
  • ng add @nrwl/workspace

In addition, as of today (July 10, 2019) I've reported a bug that, even though the workspace is already an angular type and the @nrwl install recognizes that and installs @nrwl/angular, it does not correctly configure the default schematics collection, which means that "ng" commands will not run without appending "@nrwl/angular:" before the command (e.g. "ng @nrwl/angular:g module mymod"). So you have to run the install (select scss and whatever e2e runner you want):

  • ng add @nrwl/angular

It'll tell you @nrwl/angular is already installed, but will alter the config files to recognize the angular as the default schematic collection, and your ng commands will run as expected again.

That's that for the workspace. Now create a lib:

  • ng g lib scss --directory=stylesheets

This will put a lib named scss in libs->stylesheets. In the "lib" directory of that library, dump all your scss files. We will assume you put a file "variables.scss" in that lib directory.

What this does is a couple of things:

  • When you created the library, a "paths" entry is added to your repo config. This allows you to use assets in the library by using that path instead of a long relative import. Note that just adding this entry and trying to import scss files into other scss files without the library wrapper, does not work. Evidently, you need that library to get that path to resolve.

If you look, you'll see the "paths" entry is something like this:

"@nameofrepo-nameoflib"

In order to use the scss assets in the library, in angular.json, you have to manually (not ideal but there it is) add the below fragment to the "build.options" section of EACH AND EVERY PROJECT YOU WANT TO USE IT IN.

So yes, if you have ten projects, each will have a project entry in angular.json, each of those will have a build.options block (typically ending with "scripts []", at least in my vanilla install), and you have to add this to each of those options sections (this info is out there, but I wanted to confirm, this is straight from the NRWL team):

"stylePreprocessorOptions": {     "includePaths": ["libs/stylesheets/scss/src/lib"] }, "extractCss": true 

Now, say you've created an app, and added the above config to the entry in angular.json:

ng g app myapp

And that within this app you created a feature module and component:

(cd into apps/myapp/src)

ng g module myfeature ng g component myfeature

That will create the module and component folder and assets, etc.

NOTE: As of same date as above, there's an issue that creating a component directly this way will create a .css file, even though .scss is the selected type for the project. Make sure you rename that file and change the component's pointer to it.

Within myfeature.component.scss, you would import "variables.scss" from your lib this way:

@import "variables"

Note there is no "~" (that resolves to node_modules). And, if you have subdirectories in the "lib" directory (e.g. utils), just path to it as you'd expect:

@import "utils/somefile"

Again...you MUST configure the preproccesor options as indicated in EACH project entry in angular.json!

Another gotcha: these paths may or may not appear to resolve in your IDE. Strangely, it seems some do and some don't. Not exactly sure of the pattern here, but keep in mind that your IDE may show an error where there technically isn't one.

This is working nicely for my projects.

like image 147
Tim Consolazio Avatar answered Sep 16 '22 14:09

Tim Consolazio