Closed tcoz closed 5 years ago
You could also evaluate option to share .scss
assets with shared ui library. I've created a sample PR some time ago in related repo, maybe that could be an option too:
https://github.com/nrwl/workshop-nx-starter/pull/4
This was my preferred option, but I wasn't exactly sure how to implement (I'm definitely not an scss master). I'll check out your example, grazie mille.
Hi @tcoz!
We usually like to recommend to create a library specifically to handle the styles.
You usually already have a UI library (containing only presentational components) that are shared between your apps and used by multiple feature libraries. You can create a library next to this one, handling only the styles. For example:
libs/common/ui/my-ui-library1
libs/common/ui/my-styles-library
Inside the library you can have all your relevant .scss
files that will be used by other libraries / apps.
Then, concerning the import
, you could do it in two ways, like you exposed.
The first one is the deep imports ../../etc/etc/variables.scss
.
The second one is to use the stylePreprocessorOptions
like you mentioned. With this option you will be able to write only import "variables";
which is neat. To achieve that you will need to setup the stylePreprocessorOptions
for every apps that need those styles. You can do it by updating the angular.json
file, here an example:
"projects": {
"shop-client": {
"root": "apps/my-app",
"sourceRoot": "apps/my-app/src",
"projectType": "application",
"prefix": "app",
"schematics": {},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/apps/my-app",
"deployUrl": "static/",
"index": "apps/my-app/src/index.html",
"main": "apps/my-app/src/main.ts",
"polyfills": "apps/my-app/src/polyfills.ts",
"tsConfig": "apps/my-app/tsconfig.app.json",
"stylePreprocessorOptions": {
"includePaths": [
"libs/common/ui/my-styles-library/src/lib"
]
},
"extractCss": true
},
Closing the issue for now.
@bcabanes Want to thank you for the responsiveness, this is exactly the way I was heading, two things though:
"Inside the library you can have all your relevant .scss files that will be used by other libraries / apps."
How exactly do I do that? I'm assuming I don't just drop them in, is there some config or something?
@tcoz No there is no configuration for it since this library will not contain anything JavaScript related (unless you want to test your styles with components).
The way you arrange your scss
files is up to you, or more precisely the architecture / code organisation of your styles (think BEM, Atomic design, SMACSS etc...).
The only configuration needed is if you want to use the import "variables";
version, your will need to configure the stylePreprocessorOptions
property for the app that needs it.
Yep I tried the preprocessor option again, it's not working here.
My setup very vanilla:
"stylePreprocessorOptions": {
"includePaths": [
"libs/sasslib/src/lib"
]
},
"extractCss": true
In myapp.component.scss:
@import "~font-icons/variables";
Shows as unresolved, doesn't compile. Tried a variety of combinations, no go.
This is the solution I'd really like to get working, but even in the most straightforward way it doesn't seem to take. I figure I'm missing something obvious. This will all take with an "ng serve myapp"? No other build step or anything?
@tcoz Okay i will reopen the ticket, but we will need a repo where we can reproduce the error. This is very tied to the setup and the configuration of your workspace.
Alright, will create a git repo tomorrow. I'm definitely not doing anything fancy, the workspace has three small apps in it and nothing else, latest and greatest CLI and NX installed via the "add nx extensions to existing cli workspace" docs.
Repo posted (link at bottom), steps:
Angular CLI 8.0.4 node v10.15.3
(cd into preprocessor, all commands now run from workspace root unless otherwise indicated)
Even though it is an angular project that I added the Nrwl extensions to (as opposed to creating a straight nx workspace with no project type), and the @nrwl/angular package is installed, the "ng" commands won't run without appending "@nrwl/angular:" unless you do this:
(Select Jest and Cypress from prompts, Cypress download/install takes a bit, it is not already installed)
Now the default schematics/collection is properly configured and the ng commands will run as expected. I filed an issue on this a while back, but would be surprised if it's related, figured I'd point it out though.
Moving on:
Select SASS, no routing. NOTE: a warning appears the @nrwl/workspace package is now installed as both a dependency and dev dependency.
App serves on 4200 as expected. I CD into apps/subdir/testapp/src, and create a module and component:
I import the feature module into the app.module of testapp, remove the default kruft from app.component template, and add the selector for myfeature. I serve it (ng serve subdir-testapp), all is well.
NOTE: (There's another issue file on this), even though testapp was created with SASS selected, the feature module "myfeature" component is created with a .css file, not an .scss one. I rename the file to "myfeature.component.scss" and change myfeature.component.ts to point at the scss file (instead of the configured css one). In angular.json, the project configuration does indicate style is scss, and the correct "styles" .scss file is indicated:
"subdir-testapp": {
"projectType": "application",
"schematics": {
"@nrwl/workspace:component": {
"style": "scss"
}
},
....
"styles": ["apps/subdir/testapp/src/styles.scss"],
CD back to the workspace root, create the library:
ng g lib sasslib
Selected nothing for directory (puts sasslib in lib directory), and SASS from style selections. All is well.
I put a file "variables.scss", which contains a bunch of variables but no other imports, into the lib directory of that library.
Configure the preprocessor options for subdir-testapp in angular.json:
"options": {
"outputPath": "dist/apps/subdir/testapp",
"index": "apps/subdir/testapp/src/index.html",
"main": "apps/subdir/testapp/src/main.ts",
"polyfills": "apps/subdir/testapp/src/polyfills.ts",
"tsConfig": "apps/subdir/testapp/tsconfig.app.json",
"aot": false,
"assets": [
"apps/subdir/testapp/src/favicon.ico",
"apps/subdir/testapp/src/assets"
],
"styles": ["apps/subdir/testapp/src/styles.scss"],
"scripts": [],
"stylePreprocessorOptions": {
"includePaths": [
"libs/sasslib/src/lib"
]
},
"extractCss": true
},
Do an "ng serve subdir-testapp" everything is fine, no console errors etc.
Go to myfeature.component.scss, add this line:
@import "~variables"
The import does not resolve (WebStorm), and the app does not compile:
ERROR in ./src/myfeature/myfeature.component.scss
Module build failed (from /Users/Consolazio/Documents/GitHub/preprocessor/node_modules/sass-loader/lib/loader.js):
@import "~variables";
^
Can't find stylesheet to import.
╷
1 │ @import "~variables";
│ ^^^^^^^^^^^^
╵
stdin 1:9 root stylesheet
in /Users/Consolazio/Documents/GitHub/preprocessor/apps/subdir/testapp/src/myfeature/myfeature.component.scss (line 1, column 9)
It also doesn't work in testapp/src/styles.scss.
As far as I can tell, based on your direction, this should work very straightforwardly. I suspect I'm missing something obvious but at this point (I've been told more than once, "there's nothing to configure or import it should just work") I'm at a loss. I'm tinkering with it now, will be watching the thread carefully (I really need to get this working for a large project).
REPRO REPO (public):
Changing @import "~variables";
by @import "variables";
makes it working. Sorry for not pointing it before, my bad.
The syntax @import "~variables";
makes the builder (Webpack) looking into the node_modules
resolutions, which will fail because the style library is not part of the node_modules
dependencies.
The use of stylePreprocessorOptions
option is used to tell the builder (Webpack) to include the path provided in its path resolutions. It will look to your files as if they were in the same directory (sort of). This is why, you don't need the ~
.
This is comprehensible. Since we are configuring a custom property of a builder in a custom file. The IDE can't make any assumption about that change. This import cannot be resolved because it is looking to resolve it in the same folder of the import.
The only way to use the IDE resolution is to use the deep import ../../../libs/my-styles/path-to-file
.
Right, I figured that, the previous post indicated the "~". I thought maybe it added it to the path resolutions or some such. I also figured the IDE might not understand the implied path, that's fine.
Checking it out now.
(After checking in repro) so far so good, the app compiles. Rolling over to the larger repo to make the change and see if all is well...
@tcoz I created a PR with the change if it can be useful.
Everything seems to be working in the larger project now, nice tidy style libraries, thanks for the help here.
How would one go about fixing the dependency graph in this situation?
How would one go about fixing the dependency graph in this situation?
In your nx.json
you will find a section for your application i.e. webapp
assuming your lib with the styling is called styling
you can set:
"projects": {
"webapp": {
"tags": [],
"implicitDependencies": ["styling"]
},
}
Hi @tcoz!
We usually like to recommend to create a library specifically to handle the styles.
You usually already have a UI library (containing only presentational components) that are shared between your apps and used by multiple feature libraries. You can create a library next to this one, handling only the styles. For example:
libs/common/ui/my-ui-library1 libs/common/ui/my-styles-library
Inside the library you can have all your relevant
.scss
files that will be used by other libraries / apps.Then, concerning the
import
, you could do it in two ways, like you exposed.
- The first one is the deep imports
../../etc/etc/variables.scss
.- The second one is to use the
stylePreprocessorOptions
like you mentioned. With this option you will be able to write onlyimport "variables";
which is neat. To achieve that you will need to setup thestylePreprocessorOptions
for every apps that need those styles. You can do it by updating theangular.json
file, here an example:"projects": { "shop-client": { "root": "apps/my-app", "sourceRoot": "apps/my-app/src", "projectType": "application", "prefix": "app", "schematics": {}, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/apps/my-app", "deployUrl": "static/", "index": "apps/my-app/src/index.html", "main": "apps/my-app/src/main.ts", "polyfills": "apps/my-app/src/polyfills.ts", "tsConfig": "apps/my-app/tsconfig.app.json", "stylePreprocessorOptions": { "includePaths": [ "libs/common/ui/my-styles-library/src/lib" ] }, "extractCss": true },
hey @bcabanes , I was wondering how would this work in a project without angular, e.g. a NX-next.js react based series of apps? I've been stuck with this for 3 days now trying to find a solution for this exact same problem and only have workspace.json
where adding
"stylePreprocessorOptions": { "includePaths": [ "libs/common/ui/my-styles-library/src/lib" ]
doesn't work.
I was wondering if you have any ideas with this or know a guy who created a style library
Hi @JanineLourens did you have any luck creating this structure? I was heading the same way and came across this thread. On my current tests, I was only able to achieve this import with deep imports. So far I couldn't make it work with the include paths.
On thing to note is that the includePaths
works for Apps. But if a library is consuming the other library, it doesn't work. Even if adding the path to ng-package.json
like the following:
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../../dist/libs/shared/ui-components",
"lib": {
"entryFile": "src/index.ts",
"styleIncludePaths": ["/libs/shared/smacss/src"]
}
}
I would also be interested in any proposed solutions/examples. I am currently working through this myself.
My scenario is a shared styles library, which also imports bootstrap.
This all works beautifully, except when I want to use a mixin such as theme-color-level
within a specific component. I can reimport bootstrap but then I'd also need to import all my variable overrides each time (which currently would be a deep import as mentioned).
The proposed solution using the "stylePreprocessorOptions" option did not work for me as shown above.
However, if I include .scss in the filename when components are importing a file (@import "variables.scss"
instead of @import "variables"
), it does work.
I have not determined why yet. If anyone can enlighten me, please do.
Hi @JanineLourens did you have any luck creating this structure? I was heading the same way and came across this thread. On my current tests, I was only able to achieve this import with deep imports. So far I couldn't make it work with the include paths.
On thing to note is that the
includePaths
works for Apps. But if a library is consuming the other library, it doesn't work. Even if adding the path tong-package.json
like the following:{ "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", "dest": "../../../dist/libs/shared/ui-components", "lib": { "entryFile": "src/index.ts", "styleIncludePaths": ["/libs/shared/smacss/src"] } }
I ran into the same issue as @fbaba-nibtravel in a Nrwl workspace.
I want to import a scss file from libs/shared/styles
in lib/shared/ui
. stylePreprocessorOptions
is not available in the shared-ui lib builder ("@nrwl/angular:package"
), and adding styleIncludePaths
to shared-styles lib's ng-package.json
throws the following error when building shared-ui
lib:
ERROR: Configuration doesn't match the required schema.
Data path ".lib" should NOT have additional properties (styleInlcludePaths).
So I just found this thread.
Am I crazy but is just having a root level folder for styles reasonable?
So
my-nx-app
apps
libs
styles
My style imports now look like:
@import "styles/variables";
h1 {
background-color: $color;
}
No big long imports .. styles variables kinda feel like a top-level concern for me, I am not picking up any real code smells, am I missing something?
You can still seem to import styles from node-modules into this top level folder, something like:
@import "~@angular/material/theming";
$typographyConfig: mat-typography-config();
$color: blue
So yeah I feel like this bypasses some of the above-mentioned issues and is a reasonable overall solution. Let me know what you think.
@vespertilian I think you lose a bit of control on the affected checks if you put the styles outside the libs folder. I don't think your styles/
folder will show up on the affected graph, so any changes to those files may not cause apps to re-build.
@adgoncal great point.
Hi all, I was able to sorta make it work. But I haven't done much tests on it so I thought you guys may want to give it a go.
On package.json
"dependencies": {
...
"@yourWorkspace/styles": "file:libs/shared/ui/styles/src",
...
},
This creates a sort of symlink of the style package.
With that I was able to do @import "~@yourWorkspace/styles/components/autocomplete";
within the libs.
I'll repeat, need more tests around it.
i use: @import '~libs/style/src/lib/variables'
Hi all, I was able to sorta make it work. But I haven't done much tests on it so I thought you guys may want to give it a go.
On
package.json
"dependencies": { ... "@yourWorkspace/styles": "file:libs/shared/ui/styles/src", ... },
This creates a sort of symlink of the style package. With that I was able to do
@import "~@yourWorkspace/styles/components/autocomplete";
within the libs.I'll repeat, need more tests around it.
So far, IMHO, this seems to be the only way that works for both apps and libs, and it is just clean.
stylePreprocessorOptions
does not work in libs, only apps. And even though stylePreprocessorOptions
works for apps, it doesn't allow you to create path aliases, so, in your imports, you end up referencing "global" files that may not be clear at a glance where they are coming from (the app? libraries?).
The package.json symlink approach allows you to alias your styles paths as "virtual" libraries. You still keep their code in their owning library, where they belong (let's say @corp/lib
), but you can import their styles with @import "~@corp/lib-styles/..."
from all across the monorepo, even from withing @corp/lib
itself, without the need to create another real library.
Neat, @fbaba-nibtravel 🙌
Hi all, I was able to sorta make it work. But I haven't done much tests on it so I thought you guys may want to give it a go. On
package.json
"dependencies": { ... "@yourWorkspace/styles": "file:libs/shared/ui/styles/src", ... },
This creates a sort of symlink of the style package. With that I was able to do
@import "~@yourWorkspace/styles/components/autocomplete";
within the libs. I'll repeat, need more tests around it.So far, IMHO, this seems to be the only way that works for both apps and libs, and it is just clean.
stylePreprocessorOptions
does not work in libs, only apps. And even thoughstylePreprocessorOptions
works for apps, it doesn't allow you to create path aliases, so, in your imports, you end up referencing "global" files that may not be clear at a glance where they are coming from (the app? libraries?).The package.json symlink approach allows you to alias your styles paths as "virtual" libraries. You still keep their code in their owning library, where they belong (let's say
@corp/lib
), but you can import their styles with@import "~@corp/lib-styles/..."
from all across the monorepo, even from withing@corp/lib
itself, without the need to create another real library.Neat, @fbaba-nibtravel 🙌
The only issue I'm having at the moment is that sometimes the HMR doesn't account for changes on the css and not sure why, but I do have to rebuild so it reflects the current changes on the css. Usually is fine tho.
Its nice to see this being addressed im using 10.4.4 nrwl nx
this is the main breadNbutter standing feature of nx sharing libraries across enterprise of all code to save corporations
im dealing with a pre-generated project monorepo this is my second day being blocked I updated migrated and that failed with various errors
after attempting to import interface class files in code
I keep getting this
ESLint: Libraries cannot be imported by a relative or absolute path, and must begin with a npm scope(@nrwl/nx/enforce-module-boundaries)
this issue is a ten headed dragon and hasnt been solved for the public yet
Im happy to put any effort in testing but Im still flattened
this was building...
import IRouter from '../../../libs/isomorphic/src/lib/server/IRouter';
import IHitcount from '../../../libs/isomorphic/src/lib/IHitcount';
all i want to do is import
npm said to do this
import { IHitcount } from '../../../libs/isomorphic/src/lib/IHitcount'
import { IRouter } from '../../../libs/isomorphic/src/lib/server/IRouter'
when this SHOULD be able to articulate this
import { IHitcount } from '@workspace/isomorphic/src/lib/IHitcount'
import { IRouter } from '@workpsace/isomorphic/src/lib/server/IRouter'
can someone set me on a path and I will validate
Im working on this fulltime ?
thank you
FYI from my perspective as of yesterday and I just started using Nx 3 weeks ago
after opening up all tsconfig files to find everything
> nx run e2-ask:build
chunk {main} main.js, main.js.map (main) 633 bytes [initial] [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 688 bytes [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.15 kB [entry] [rendered]
chunk {styles} styles.css, styles.css.map (styles) 535 kB [initial] [rendered]
Date: 2020-11-28T23:57:20.753Z - Hash: 0b315edbfa2f7ce72b80 - Time: 36163ms
ERROR in Module build failed (from /Users/meanstack/new/NX/energy/node_modules/sass-loader/dist/cjs.js):
SassError: Can't find stylesheet to import.
╷
1 │ @import "styles-variables";
│ ^^^^^^^^^^^^^^^^^^
╵
/Users/meanstack/new/NX/energy/apps/e2-ask/src/app/biz/landing.component.scss 1:9 root stylesheet
> NX CLOUD See run details at https://nx.app/runs/s2WUybZhnQN
@nhhockeyplayer, I have the impression you're mixing a couple of issues as if they are one.
Firstly, regarding the ESLint and NX Enforce Boundaries. For ESLint IDE to understand the workspace path, they should be properly formed within tsconfig.json
on similar to:
{
...
path: {
"@workspace/lib": "libs/lib1/src/index.ts"
}
}
This should be defined on the root tsconfig on which all tsconfig.lib.json
are extending.
In addition, your rules about the boundaries should be defined within nx.json
{
"projects": {
"app": {
"tags": ["scope:app"]
},
"lib1: {
"tags": ["scope:shared", "type:ui"]
}
}
Finally, on your .eslintrc.json
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2015,
"sourceType": "module",
"project": "./tsconfig.*?.json"
},
"ignorePatterns": [],
"plugins": ["@typescript-eslint", "@nrwl/nx"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint"
],
"rules": {
...
"@nrwl/nx/enforce-module-boundaries": [
"error",
{
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{
"sourceTag": "scope:app",
"onlyDependOnLibsWithTags": ["scope:app", "scope:shared"]
},
{
"sourceTag": "scope:shared",
"onlyDependOnLibsWithTags": ["scope:shared"]
},
{
"sourceTag": "type:ui",
"onlyDependOnLibsWithTags": ["type:ui", "type:util"]
},
]
}
]
}
}
As for the scss import, it's not ESlint throwing this. With the trick I've previously shared, it creates a sort of symbolic link to the node_modules
folder so your import should be something like @import '~/@workspace/styles/style_variables'
;
Actually this is what the IDE liked
@import '~@workspace/scss/lib/styles-variables';
where my lib is named scss
now Im trying to figure out how to get the cross-app cross-lib bidirectional imports to play the IDE is barking about those too
I appreciate the help my build is almost there
Im wetting my pants over this framework its very elite
actually I spoke too soon
the IDE was happy doing the code completion thing until to form
@import '~@workspace/scss/lib/styles-variables';
and the red highlight went away
but when I
nx build project
, the build fails on that line
so Im still shaking this out
will have an update
I updated my lint files having two hasnt hurt anythiing
eslintrc.json
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2015,
"sourceType": "module",
"project": "./tsconfig.*?.json"
},
"ignorePatterns": [],
"plugins": ["@typescript-eslint", "@nrwl/nx"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint"
],
"rules": {
"@nrwl/nx/enforce-module-boundaries": [
"error",
{
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{
"sourceTag": "scope:app",
"onlyDependOnLibsWithTags": ["scope:app", "scope:shared"]
},
{
"sourceTag": "scope:shared",
"onlyDependOnLibsWithTags": ["scope:shared"]
},
{
"sourceTag": "type:ui",
"onlyDependOnLibsWithTags": ["type:ui", "type:util"]
}
]
}
]
}
}
AND. tslint.json
{
"rulesDirectory": [
"node_modules/@nrwl/workspace/src/tslint",
"node_modules/codelyzer"
],
"linterOptions": {
"exclude": [
"**/*"
]
},
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"deprecation": {
"severity": "warn"
},
"forin": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"interface-over-type-literal": true,
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"prefer-const": true,
"radix": true,
"triple-equals": [
true,
"allow-null-check"
],
"unified-signatures": true,
"variable-name": false,
"@nrwl/nx/enforce-module-boundaries": [
"error",
{
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{
"sourceTag": "scope:app",
"onlyDependOnLibsWithTags": [
"scope:app",
"scope:shared"
]
},
{
"sourceTag": "scope:shared",
"onlyDependOnLibsWithTags": [
"scope:shared"
]
},
{
"sourceTag": "type:ui",
"onlyDependOnLibsWithTags": [
"type:ui",
"type:util"
]
}
]
}
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true
}
}
@nhhockeyplayer, if you do have tslint and eslint enabled on VSCode, you might be getting compilation issues from both. It's recommended to use only one of them.
So my point was, the import shouldn't be an ESLint issue. If you run ESLint on the solution, you should not get those errors.
As for the compilation issue, you are importing like this:
@import '~@workspace/scss/lib/styles-variables';
Assuming you used my trick above, this should work. You can manually go to node_modules
folder and see if your styles are within the expected folder. You might need to run yarn
or npm install
to place the files in there. This import is basically saying: within node_modules
folder, find @workspace/scss/lib/styles-variables.scss
file.
Hi @tcoz!
We usually like to recommend to create a library specifically to handle the styles.
You usually already have a UI library (containing only presentational components) that are shared between your apps and used by multiple feature libraries. You can create a library next to this one, handling only the styles. For example:
libs/common/ui/my-ui-library1 libs/common/ui/my-styles-library
Inside the library you can have all your relevant
.scss
files that will be used by other libraries / apps.Then, concerning the
import
, you could do it in two ways, like you exposed.
- The first one is the deep imports
../../etc/etc/variables.scss
.- The second one is to use the
stylePreprocessorOptions
like you mentioned. With this option you will be able to write onlyimport "variables";
which is neat. To achieve that you will need to setup thestylePreprocessorOptions
for every apps that need those styles. You can do it by updating theangular.json
file, here an example:"projects": { "shop-client": { "root": "apps/my-app", "sourceRoot": "apps/my-app/src", "projectType": "application", "prefix": "app", "schematics": {}, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/apps/my-app", "deployUrl": "static/", "index": "apps/my-app/src/index.html", "main": "apps/my-app/src/main.ts", "polyfills": "apps/my-app/src/polyfills.ts", "tsConfig": "apps/my-app/tsconfig.app.json", "stylePreprocessorOptions": { "includePaths": [ "libs/common/ui/my-styles-library/src/lib" ] }, "extractCss": true },
it it doesn't work work when using custom webpack (tailwind)
Hi all, I was able to sorta make it work. But I haven't done much tests on it so I thought you guys may want to give it a go.
On
package.json
"dependencies": { ... "@yourWorkspace/styles": "file:libs/shared/ui/styles/src", ... },
This creates a sort of symlink of the style package. With that I was able to do
@import "~@yourWorkspace/styles/components/autocomplete";
within the libs.I'll repeat, need more tests around it.
Unfortunately I can't get it work. When I run npm install
I get the error npm ERR! Could not install from "libs/utils/shared/styles/src" as it does not contain a package.json file.
. Which makes sense, there is no package.json
on the provided path.
If I put the path to the lib root libs/utils/shared/styles
then I get npm ERR! Invalid name: "@generate-cms/utils/shared/styles"
.
Any ideas?
Here is the screen shot sou you can see the folder structure:
I appreciate the help
making it work will be if it works on production like github pages
Im trying now without success
somewhere something wants to insert a "./assets/icon.png"
instead of the angular standard "assets/icon.png" whereby environment.ts gets swapped to change the appRootPrefix to all assets
for production
Im seeing this during my build and Im not coding anything like this
background: url("./assets/icon.png");
when my actual scss code is this
background: url('assets/icon.png');
and I know this wont pass on a production host and this seems deeper than making libraries accessible in nx workspaces
Im securing my workspace.json right now
NonErrorEmittedError: (Emitted value instead of an instance of Error) CssSyntaxError: /Users/me/new/NX/energy/libs/feature/src/lib/splash/splash.component.scss:28:20: Can't resolve './assets/icon.png' in '/Users/me/new/NX/energy/libs/feature/src/lib/splash'
26 | padding: 0;
27 | margin: 0;
> 28 | background: url("./assets/icon.png");
the problem is the app root prefix is being omitted for assets used inside Nx libraries
and it should be adhering to standard angular convention for dev and production
which requires some jimmying in workspace.json for output property on assets
Im not seeing an avenue as of yet
manually referencing a path somehow might work for dev
but I need production now
as of now... this is not possible
I created the npm library locally usinf 'file:/...' for the Nx assets library in my monorepo
"dependencies": {
"@energy/shared-assets": "file:libs/shared-assets/src",
that successfully compiles and builds with this reference in my source code *.scss
background: url('~@energy/shared-assets/assets/vignette-light.png');
I built prod and deployed to github pages production host and as you can see my assets DIR continues to fail to be animated properly
https://nhhockeyplayer.github.io/assets/vignette-light.png
Im sure a local dev build ill work somehow
but for production all bets are off
so what performs this animating or appending of the app root prefix ? the configuration within workspace.json
so it looks like I need to specify the assets glob and hardwire the output to do the append of the app root prefix myself
I would have liked this to be automated somehow, but we've been left with enough rope to hang ourselves...happy hanging
but it works now all of the above applies I noted less a few sporadic png files missed in the bundles
and the solution lies in the workspace.json where we hardwire the production app root prefix manually
{
"input": "libs/shared-assets/src/assets",
"glob": "**/*",
"output": "energy/assets/"
},
if this is intended please validate
I see further up this thread a couple of people have tried styleIncludePaths
and it didn't work for them. But, it does for me. This is the official method for supporting distributed scss folders. Here's the help page. Here's how I got there:
ng generate @nrwl/angular:library
schematic used to create both the styles lib and the consuming UI lib.--buildable --publishable
styleIncludePaths
to the ng-package.json
file. Note the use of relative path (../
) instead of absolute described by others above (this may be the reason for my success){
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../../dist/libs/shared/ui-xxxxxxxx",
"lib": {
"entryFile": "src/index.ts",
"styleIncludePaths": ["../ui-styles/scss"]
}
}
I've done this in multiple repos all with the same success, from Nx 10.x +
Hope that helps
@tomwhite007 Thanks for sharing your progress!
I managed to build the library in isolation following the same steps but I can't build an app that depends on this library. Isn't it likely that when building the app the compiler can't resolve styles relative to the library?
Scenario:
my-app
app depends on my-components
librarymy-components
wants to import styles like @import 'colors'
colors.scss
is located in ui-styles
librarynx build my-components
works
nx build my-app
fails
Hello @aalencar
I've checked, and can confirm this should have no impact on your app build.
I have two publishable libs that consume a 'ui-styles'
lib via styleIncludePaths
, and both of those libs are directly imported (as well as being published for external projects) via their aliases into two apps within the same Nx Workspace. And both of those apps build successfully.
I strongly suspect your build issue is not related to styleIncludePaths
if your implementation is the same as mine.
Additional note:
styleIncludePaths
will not help an app apply styles in a publishable lib if it is directly imported within the same Nx Workspace. To apply styles to your lib, you must still use something like:
"stylePreprocessorOptions": {
"includePaths": ["libs/shared/ui-styles/scss"]
},
in your angular.json
file for your app project node. Then the styles will be applied to the lib in the build.
To put it another way, styleIncludePaths
is only used by the 'publish to npm' build, not the app build process.
I prefer deploying the lib to node_modules by specifying a package.json entry using the file protocol
all imports thereafter work like a breeze
But this is now a show stopper
I cannot use the file protocol anymore due to changes in the frameworks
therefore my build broken now. And I do not want a package.json living inside my library within my libs folder for any given library monorepo is suppose to only have one package.json at the root dir not beneath as it will ruin the build and confuse compilers
new build error on angular 12 nrwl 12
Could not install from "libs/shared-assets/src/lib" as it does not contain a package.json file.
does anyone know if a workaround?
the includePaths solution feels too detached
@nhhockeyplayer, you probably need to change your paradigm.
To apply styles from your lib to your app build, you must use something like:
"stylePreprocessorOptions":
{ "includePaths": ["libs/shared/ui-styles/scss"] },
...in your angular.json
file for your app project node. Then the styles will be extracted from the folder to your app build.
No need for npm file protocol.
The styleIncludePaths
in the ng-package.json
config is only for published lib builds to include an external bit of sccs (and it is ignored by apps).
Hi all, I was able to sorta make it work. But I haven't done much tests on it so I thought you guys may want to give it a go.
On
package.json
"dependencies": { ... "@yourWorkspace/styles": "file:libs/shared/ui/styles/src", ... },
This creates a sort of symlink of the style package. With that I was able to do
@import "~@yourWorkspace/styles/components/autocomplete";
within the libs.I'll repeat, need more tests around it.
Works like a charm, thanks!
Note: npm i
is required to create the symlink in your node_modules folder
For those asking about how to do this with react apps, in next.config.js
add:
sassOptions: {
includePaths: [path.join(__dirname, 'path_to_scss_folder')]
}
and then you just import directly like: @import 'variables';
I see further up this thread a couple of people have tried
styleIncludePaths
and it didn't work for them. But, it does for me. This is the official method for supporting distributed scss folders. Here's the help page. Here's how I got there:
- Nx Workspace v10.x, and later upgraded to v11.x
ng generate @nrwl/angular:library
schematic used to create both the styles lib and the consuming UI lib.- The UI lib was scaffolded with extra options:
--buildable --publishable
- I added
styleIncludePaths
to theng-package.json
file. Note the use of relative path (../
) instead of absolute described by others above (this may be the reason for my success){ "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", "dest": "../../../dist/libs/shared/ui-xxxxxxxx", "lib": { "entryFile": "src/index.ts", "styleIncludePaths": ["../ui-styles/scss"] } }
I've done this in multiple repos all with the same success, from Nx 10.x +
Hope that helps
Using Angular 14 setup with nx 15.
The solution for my issue (being "building a buildable nx library with a path alias scss import") was adding the styleIncludePaths line to ng-package.json of a library that the build is failing for (where ../styles is the path to the library with style definitions, where alias "begins":
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../../dist/libs/shared/ui",
"lib": {
"entryFile": "src/index.ts",
"styleIncludePaths": ["../styles"]
}
}```
Hello, we are looking at how to migrate several of our repo's to NX.
In this sense, we have a style library (SCSS) shared between two Angular applications and one React. It contains direct SCSS code (variable, mixing, ...), compiled CSS and assets.
I'm quite surprised that there are no official plugins to do this, because this case seems to me common.
The idea is to be able to :
nx graph
nx affected
publishable
/buildable
flagsIf it wasn't planned, would someone have some ideas to bring me to achieve this kind of result?
Thanks.
Repo posted (link at bottom), steps:
Angular CLI 8.0.4 node v10.15.3
- ng new preprocessor
(cd into preprocessor, all commands now run from workspace root unless otherwise indicated)
- ng add @nrwl/workspace
Even though it is an angular project that I added the Nrwl extensions to (as opposed to creating a straight nx workspace with no project type), and the @nrwl/angular package is installed, the "ng" commands won't run without appending "@nrwl/angular:" unless you do this:
- ng add @nrwl/angular
(Select Jest and Cypress from prompts, Cypress download/install takes a bit, it is not already installed)
Now the default schematics/collection is properly configured and the ng commands will run as expected. I filed an issue on this a while back, but would be surprised if it's related, figured I'd point it out though.
Moving on:
- ng g app testapp --directory=subdir
Select SASS, no routing. NOTE: a warning appears the @nrwl/workspace package is now installed as both a dependency and dev dependency.
- ng serve subdir-testapp
App serves on 4200 as expected. I CD into apps/subdir/testapp/src, and create a module and component:
- ng g module myfeature
- ng g component myfeature
I import the feature module into the app.module of testapp, remove the default kruft from app.component template, and add the selector for myfeature. I serve it (ng serve subdir-testapp), all is well.
NOTE: (There's another issue file on this), even though testapp was created with SASS selected, the feature module "myfeature" component is created with a .css file, not an .scss one. I rename the file to "myfeature.component.scss" and change myfeature.component.ts to point at the scss file (instead of the configured css one). In angular.json, the project configuration does indicate style is scss, and the correct "styles" .scss file is indicated:
"subdir-testapp": { "projectType": "application", "schematics": { "@nrwl/workspace:component": { "style": "scss" } }, .... "styles": ["apps/subdir/testapp/src/styles.scss"],
CD back to the workspace root, create the library:
- ng g lib sasslib
Selected nothing for directory (puts sasslib in lib directory), and SASS from style selections. All is well.
I put a file "variables.scss", which contains a bunch of variables but no other imports, into the lib directory of that library.
Configure the preprocessor options for subdir-testapp in angular.json:
"options": { "outputPath": "dist/apps/subdir/testapp", "index": "apps/subdir/testapp/src/index.html", "main": "apps/subdir/testapp/src/main.ts", "polyfills": "apps/subdir/testapp/src/polyfills.ts", "tsConfig": "apps/subdir/testapp/tsconfig.app.json", "aot": false, "assets": [ "apps/subdir/testapp/src/favicon.ico", "apps/subdir/testapp/src/assets" ], "styles": ["apps/subdir/testapp/src/styles.scss"], "scripts": [], "stylePreprocessorOptions": { "includePaths": [ "libs/sasslib/src/lib" ] }, "extractCss": true },
Do an "ng serve subdir-testapp" everything is fine, no console errors etc.
Go to myfeature.component.scss, add this line:
@import "~variables"
The import does not resolve (WebStorm), and the app does not compile:
ERROR in ./src/myfeature/myfeature.component.scss Module build failed (from /Users/Consolazio/Documents/GitHub/preprocessor/node_modules/sass-loader/lib/loader.js): @import "~variables"; ^ Can't find stylesheet to import. ╷ 1 │ @import "~variables"; │ ^^^^^^^^^^^^ ╵ stdin 1:9 root stylesheet in /Users/Consolazio/Documents/GitHub/preprocessor/apps/subdir/testapp/src/myfeature/myfeature.component.scss (line 1, column 9)
It also doesn't work in testapp/src/styles.scss.
As far as I can tell, based on your direction, this should work very straightforwardly. I suspect I'm missing something obvious but at this point (I've been told more than once, "there's nothing to configure or import it should just work") I'm at a loss. I'm tinkering with it now, will be watching the thread carefully (I really need to get this working for a large project).
REPRO REPO (public):
I you use webpack, you can add alias for variables and use import like that
I've done some looking around on this one, apologies if an answer is published and I missed it.
The issue: there doesn't appear to be an established best practice for working with .scss files and so on in an NX workspace.
It seems you can put them all in a directory somewhere and just do the usual long-winded imports "../../../etc/etc/variables.scss".
I'm digging into the stylePreprocessorOptions.includePaths, which as far as I know is the standard way of going about it, but I'm not having any luck, and it also seems like even if it worked, you'd have to add the frag to every project in the angular.json by hand. Not horrible but not ideal.
That's all guessing though. What's the established practice used by the NRWL team?
Thanks for any info here, I'm working with a team on adopting the extensions, want to make sure I get this one right.