Angular Multi-repo Micro-Apps: Sharing Singleton services

With reference to the apps we already have set up,

Disclaimer: This is just to demonstrate a shared state. Not to be used in an ideal login/logout scenario. The best way to handle login/logouts are to use httpOnly cookies that use a token in BFF layer

Let's say we we want to handle user's authentication

create a folder, i am calling it "shared-library"

  • cd shared-library
  • ng new shared-library --create-application=false
  • ng generate library KavyaMyUserServiceLibrary
    • (cant use too generic names, it will not allow for public publish)

Inside
shared-library\shared-library\projects\user-service-library\src\lib\user-service-library.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

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

  constructor() { }
  private loggedIn = new BehaviorSubject<boolean>(false);
  loggedIn$ = this.loggedIn.asObservable();

  login(): void {
    console.log("from library logging in", this.isLoggedIn)
    this.loggedIn.next(true);
  }

  logout(): void {
    console.log("from library logging out", this.isLoggedIn)
    this.loggedIn.next(false);
  }

  get isLoggedIn(): boolean {
    console.log("from library loggedIn", this.loggedIn.getValue())
    return this.loggedIn.getValue();
  }
}

  • ng build KavyaMyUserServiceLibrary
  • npm login
  • cd dist/kavya-myuser-service-library
  • npm publish --access public

This is the library i published:

https://www.npmjs.com/package/kavya-myuser-service-library

Time to install the library.

You need to install in all the apps individually. 

BUT, in webpack.config.ts

const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack');

module.exports = withModuleFederationPlugin({

  name: 'account-management',
  filename: 'remoteEntry.js',
  exposes: {
    './Component': './src/app/app.component.ts',
  },

  shared: {
    ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
    'kavya-myuser-service-library': {
      singleton: true,
      strictVersion: false,
      requiredVersion: '^0.0.1'
    }
  },

});

Make sure singleton is marked as true.
Also, DO NOT provide inside component/module again in remote apps.

It needs to be provided ONLY ONCE in the shell app. 

shell:

hotel-reservation-system\src\app\app.component.ts

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { UserServiceLibraryService } from 'kavya-myuser-service-library';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet],
  providers: [UserServiceLibraryService],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent {
  title = 'hotel-reservation-system';
  constructor(private userService: UserServiceLibraryService) {

  }

  ngOnInit() {
    this.userService.loggedIn$.subscribe(res => {
      console.log("from shell",this.userService.isLoggedIn, res)
    })
  }

  login() {
    this.userService.login()
  }
}

account-management\src\app\app.component.ts

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { UserServiceLibraryService } from 'kavya-myuser-service-library';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent {
  title = 'account-management';
  constructor(private service: UserServiceLibraryService){}

  isLoggedIn?: boolean;

  ngOnInit() {
    this.service.loggedIn$.subscribe(res => {
      this.isLoggedIn = res;
      console.log("from account-mgmt",this.service.isLoggedIn, res)
    })
  }
}

Now, when we click 'login' that is on shell app, the new logged in state is also reflected in account management app!




Comments

Popular posts from this blog

Inside the JavaScript Memory Box: Visualizing Variables, References, and Copies

React & State Management: All Concepts

React: Communication between components