DEV Community

Cover image for Angular Workspace 🏭
Suman Kumar
Suman Kumar

Posted on • Edited on

Angular Workspace 🏭

If you want to manage multiple Angular Sub-Projects in one Main Project then Angular Workspace (a.k.a Mono-repo Pattern) is what you are looking for.

What's the use ? πŸ€”

You can create multiple projects that share the same workspace instead of having one workspace for each project, that would mean having one node_modules folder across projects.

How individual Angular Projects are different from Angular Workspace with Sub-Projects


What are we going to accomplish❓❓

What are we going to accomplish at the end of this blog ?

An important note before we proceed any further, each Angular Application is an individual / independent SPA.

That means admin-app / ticketing-app should be build & deployed as separate applications. In local, ng serve admin-app / ng serve ticketing-app should be used.


Pre-Requisites

  • NodeJS
  • Angular CLI
  • Typescript

⏳ Let's get our hands dirty code


Creating an empty workspace

Create an Angular application with NO scaffolded files.



ng new main-app --create-application=false


Enter fullscreen mode Exit fullscreen mode

main-app serves as a place holder for other Sub-Projects, without any actual code in it.

What value did --create-application=false add ?

Image description

If ng new main-app is used, the src folder contains the source code for default app. And angular.json contains a property called defaultProject to customize our default project.


Creating application(s)

Creating 2 independent Angular application's within the main-app workspace



ng generate application admin-app --routing=false --style=scss


Enter fullscreen mode Exit fullscreen mode


ng generate application ticketing-app --routing=false --style=scss


Enter fullscreen mode Exit fullscreen mode

Creating library

Creating new library within the main-app workspace :



ng generate library logging-lib


Enter fullscreen mode Exit fullscreen mode

Use ng generate --help to know what other option(s) are available.


All application(s) and libraries created inside the workspace will be added under projects folder, by default. Which can be overridden during the creation process :



ng generate application ticketing-app --project-root=custom-proj-root


Enter fullscreen mode Exit fullscreen mode

Below are the changes added to main-app workspace :

Image description

  1. angular.json file will have 3 project definition(s)
    • admin-app & ticketing-app with "projectType" as application
    • logging-lib with "projectType" as library
  2. Main workspace package.json will have new devDependency added ng-packagr
  3. tsconfig.json will have new entry paths, pointing to dist or build destination of library .

When we import an entity (component / service) from library, here it is logging-lib, inside applications like admin-app or ticketing-app, Angular will look up for requested imports within the application dir if not found then will look into build destination mapped to paths in tsconfig.json



{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "logging-lib": [
        "dist/logging-lib"
      ]
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

With the help of Angular CLI we have added a workspace, a library & 2 Single Page application(s)


Now lets take a look at some important files under projects/logging-lib



main-app
β”œβ”€β”€ projects/
β”‚   └── logging-lib/
β”‚       β”œβ”€β”€ src/
β”‚       β”‚   β”œβ”€β”€ lib/                     # (1)
β”‚       β”‚   β”‚   β”œβ”€β”€ logging-lib.component.ts
β”‚       β”‚   β”‚   β”œβ”€β”€ logging-lib.module.ts
β”‚       β”‚   β”‚   └── logging-lib.service.ts
β”‚       β”‚   └── public-api.ts            # (2)
β”‚       β”œβ”€β”€ ng-package.json              # (3)
β”‚       └── package.json                 # (4)
β”œβ”€β”€ angular.json
β”œβ”€β”€ package.json
└── tsconfig.json


Enter fullscreen mode Exit fullscreen mode

Now let's go into details of some files:

  • Library Code (1)
    This folders contains the code of the library, currently a module, component and service. This is the main and only entry point of our library right now.

  • Public API (2)
    The file contains the public API of the library. It exports all members that should be available to the outside world. That's the Angular Module, component and service inside the src/lib/ folder.

  • ng-package.json (3)
    The file contains the configuration for ng-packagr. It specifies the path of the build output and the entry file which points to public-api.ts.

  • package.json (4)
    This is the package.json of your library (not to be confused with the package.json of our Angular workspace in the root folder). Here you specify the name, version and dependencies of your library.


Our objective is to create library & use it across application(s)

As the name indicates we shall create a simple logger service & try to use it across application(s)

New library structure after cleaning up :



main-app
β”œβ”€β”€ projects/
β”‚   └── logging-lib/
β”‚       β”œβ”€β”€ src/
β”‚       β”‚   β”œβ”€β”€ lib/                     
β”‚       β”‚   β”‚   β”œβ”€β”€ logger.service.ts
β”‚       β”‚   β”‚   └── logging-lib.module.ts
β”‚       β”‚   └── public-api.ts
β”‚       β”œβ”€β”€ ng-package.json
β”‚       └── package.json
β”œβ”€β”€ angular.json
β”œβ”€β”€ package.json
└── tsconfig.json


Enter fullscreen mode Exit fullscreen mode


// File Name : logger.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class LoggerService {

  constructor() { }

  log(value: string) {
    console.log(`Logging from Logger Service`);
    console.log(value);
  }
}



Enter fullscreen mode Exit fullscreen mode


// File Name : public-api.ts
/*
 * Public API Surface of logging-lib
 */

export * from './lib/logger-service';
export * from './lib/logging-lib.module';



Enter fullscreen mode Exit fullscreen mode

Lets build logging-lib project, using below command :



ng build logging-lib --watch



Enter fullscreen mode Exit fullscreen mode

If the build is through without any errors, we can use our library service inside application(s).

File Structure after library build :



main-app
β”œβ”€β”€ dist/logging-lib
β”œβ”€β”€ node_modules/
β”œβ”€β”€ projects/
β”œβ”€β”€ angular.json
β”œβ”€β”€ package.json
└── tsconfig.json


Enter fullscreen mode Exit fullscreen mode

One super helpful command that i found in Angular CLI is to use generate command with --dry-run flag.



ng generate component <path-to-create-component> --project admin-app --dry-run


Enter fullscreen mode Exit fullscreen mode


ng generate service <path-to-create-service> --project logging-lib --dry-run


Enter fullscreen mode Exit fullscreen mode

--dry-run flag will not make any changes to file structure but will show where the new generated files are going to be added.


Now let's make final change to consume our library service inside application



main-app
β”œβ”€β”€ projects/
β”‚   └── admin-app/
β”‚       β”œβ”€β”€ src/
β”‚       β”‚   β”œβ”€β”€ app/                     
β”‚       β”‚   β”‚   β”œβ”€β”€ app.component.ts
β”œβ”€β”€ angular.json
β”œβ”€β”€ package.json
└── tsconfig.json


Enter fullscreen mode Exit fullscreen mode


// File Name : app.component.ts

import { Component, OnInit } from '@angular/core';
import { LoggerService } from 'logging-lib';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit{
  title = 'admin-app';

  constructor(private loggerService: LoggerService) {}

  ngOnInit(): void {
    this.loggerService.log(this.title);
  }

}



Enter fullscreen mode Exit fullscreen mode


ng serve admin-app



Enter fullscreen mode Exit fullscreen mode

If you are still around, you should see following output in Browser Console :

Final output of using Logger Lib Service in Application


Key Takeaways πŸ“

  1. Creating Angular Workspace with Applications & Library
  2. Sharing Library code with other Applications

If you are thinking of sharing one Application code in another, always use Library or Integration Application for that.

Top comments (5)

Collapse
 
diegojeptha profile image
Diego

Awesome post will use this project implementation on a project i have in mind

Collapse
 
codesuman profile image
Suman Kumar • Edited

Thanks. This is my first attempt, was the post easy to understand ?

Collapse
 
diegojeptha profile image
Diego

Definitely easy for me. I'm well versed in Angular, I just didn't think of this type of file structure

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
vahid_sam_417188fb631eba1 profile image
Vahid Sam

We have an Angular workspace with two apps, one being main-app and the other app2, along with two libraries defined in it. Now, we want to use app2 inside main-app. My first question is, how can we do this? The second question is, how can we, for example, deliver only app2 to the client without having to build the entire code?