Tiny Angular application projects in Nx workspaces

I’m excited to have just published this step-by-step explanation of how to extract assets, styles, and environments workspace libraries in an Nx monorepo.

Hit me with any questions or suggestions for improvements :grinning:

1 Like

Hi @LayZee thank you for the great article, it is super timely for a project I am working on.

Just want to let you know, I discovered when I tried the assets config, it seemed to work just fine on Mac but it did not work on ng serve command on Windows. I used the slightly modified assets config:

            "assets": [
              {
                "glob": "favicon.ico",
                "input": "libs/angular/assets/src",
                "output": ""
              },
              {
                "glob": "**/*",
                "input": "libs/angular/assets/src/assets",
                "output": "assets"
              }
            ],

For an Angular project. When I ran ng serve, I got:

> ng serve desktop-app-renderer
Schema validation failed with the following errors:    
  Data path ".assets[0]" should have required property 
'output'.
  Data path ".assets[0]" should be string.
  Data path ".assets[0]" should match exactly one schema in oneOf.

After I changed the line "output": "" to "output": "./" the error went away. (Note: only for ng serve command, ng build command was also okay. Also, I am using @angular-builders/custom-webpack.)

Hi @LayZee,

First of all thanks for this great article, it’s really comprehensive.

I followed the guideline to setup a sample workspace based on you article and I have an error in this section: https://indepth.dev/tiny-angular-application-projects-in-nx-workspaces/#set-up-an-entry-point-stylesheet
When I moved style.scss to under shared-styles/lib/_global.scss and reference it from app and index.scss.
I get the following error during build:

I’m not able to find out what is the problem.
Do you have any idea?

Thanks in advance!

1 Like

Ok I found the problem.
I’m running on windows and probably using file commands like mv causes character coding issues.
So after I deleted _global.scss and index.scss files and recreated them they work.

1 Like

Hi @joesimon,

Thank you for your feedback. It’s difficult to use cross-platform commands, but I try. I’m also on Windows, but I use PowerShell. If that doesn’t work, let me know :slight_smile:

Hi,

First of all, thanks for an article, it’s really great :wink:

I have been struggling with similar approach since some time, I have a few questions about you approach:

  • I would like to include StoreDevTools only in dev mode - how to do it? If you import it basing on environment variables it still will be included in bundle. The best way is to have a different import file for dev/prod and import StoreDevTools only in that dev file, but how to do it and do not touch dependency boundaries (where should we have to have such file, in environment lib or in data-access lib? or maybe somewhere else?)?
  • I would like to extract whole shared directory as an npm module (not separate modules [data-access, environment, etc] but as one big npm module with submodules). How to do so?
1 Like

Thanks for your questions, @nb0dy

I would like to include StoreDevTools only in dev mode - how to do it? If you import it basing on environment variables it still will be included in bundle. The best way is to have a different import file for dev/prod and import StoreDevTools only in that dev file, but how to do it and do not touch dependency boundaries (where should we have to have such file, in environment lib or in data-access lib? or maybe somewhere else?)?

In the production build, Angular CLI is supposed to tree-shake away Angular modules and other dependencies that are imported based on the environment.production property. I haven’t verified that this is still the case when using an environments workspace library. I’m not sure whether Angular adds a special Terser setting for environment.production or whether it’s just because of tree-shaking in general as a simple object is statically analyzable.

So using environment.production to conditionally import the NgRx Store DevTools is the way to go.

I would like to extract whole shared directory as an npm module (not separate modules [data-access, environment, etc] but as one big npm module with submodules). How to do so?

First of all, I don’t understand why. But if this is what you want, you might be better off with other monorepo tools such as Lerna, Yarn workspace, or NPM workspaces.

If you still insist on doing this with Nx, you need to carefully look into the examples of ng-packagr.

Hi @LayZee ,

Thanks for fast replay.

Dead code elimination doesn’t work in all cases, f.e. it won’t work for (I checked that):

const modules = [];

if (environment.production) {
  modules.push(StoreDevtoolsModule.instrument());
}

@NgModule({
  imports: [...modules],
})
export class CoreModule {}

In that case StoreDevTools module will be included. But I’m not sure about (I haven’t checked that):

  imports: [
    environment.production ? StoreDevtoolsModule.instrument() : undefined
  ],
})
export class CoreModule {}

Here you have a few articles about different approach to such problem:
https://netbasal.com/environment-based-dead-code-elimination-in-angular-54eec1f92a65

The question about publishing modules to npm is wider, f.e. I would like to:

  • run all tests for shared directory;
  • run all storybooks in shared (or any other grouping directory)
  • run any command for grouping directory

so the real question is: how to do operations on grouping directories? As far as I know it’s hard currently - I think you have to add a new (fake) project (f.e. shared) to be able to do it, or i am wrong?


ps
the case for moving all modules to npm: we have few applications. Those applications share code (~90%), but we can’t have them in one repository because we lack of enough number of unit tests to be able release all applications at once (we have to be able to release them independently, one at a time and the monorepo approach doesn’t allow that). F.e if shared code has changed, then we have to have application A with module v1.2.0 and application B with module v1.1.0

Netanel Basal is saying that the example you ask about does remove the module import in production builds.
https://netbasal.com/environment-based-dead-code-elimination-in-angular-54eec1f92a65

Here’s how to run all stories in a single Storybook project https://youtu.be/c323HOuFKkA

Unfortunately, it is not currently possible to add a filter based on tags to the run many Nx CLI command, but you can vote for it here https://github.com/nrwl/nx/issues/2675

It shouldn’t be too hard to implement a Node.js script for doing this yourself though.