0.0.44 • Published 2 years ago

@jamarsto/kiunzi-micro-frontend-tools v0.0.44

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Kiunzi Micro-frontend Tools

Kiunzi is a scaffolding framework for building microservice based applications. The Kiunzi Micro-frontend Tools library provides support for Module Federation and Custom Elements to enable the development fully encapsulated micro-frontends

🏠Table of Contents

🎁Acknowledgements

This package uses and is inspired by @angular-architects/module-federation and @angular-architects/module-federation-tools by Manfred Steyer.

🤔Motivation

There were a few things in the angular architects packages that I felt could be expanded and improved on, and I also thought that more could be done with schematics to get a full implementation up and running without multiple tweaks to the generated code.

The key motivation is to simplify adoption of micro-frontends.

🔍Prerequisites

The general foundations:

  • Module Federation requires Webpack 5+
  • Angular's support of Webpack 5 requires Angular 12+
  • This library is built using Angular 13+

Packages used and automatically added to the package.json of the angular workspace when Kiunzi is added.

  • angular-oidc-auth-client
  • @angular-architects/module-federation
  • @angular-architects/module-federation-tools
  • @ng-bootstrap/ng-bootstrap
  • @popperjs/core
  • bootstrap

📦Installation

This library is intended to be used at the start of establishing a project as it updates configurations and generates additional code and configurations. In short it builds the scaffolding.

First, build the example application

# Create your angular workspace
ng new micro-frontend-workspace --create-application false

# Navigate into the micro-frontend-workspace folder
cd micro-frontend-workspace

# Create the shared library
ng generate library --project lib

# Create the shell
ng generate application --no-routing --style sass --project shell

# Create the micro-frontends
ng generate application --no-routing --style sass --project mfe1
ng generate application --no-routing --style sass --project mfe2

# Configure the library
ng add @jamarsto/kiunzi-micro-frontend-tools --project lib --type library --authority <your_oidc_server_url> --client <your_client_id>

# Configure the shell
ng add @jamarsto/kiunzi-micro-frontend-tools --project shell --type shell --port 8000 --library lib

# Configure the micro-frontends
ng add @jamarsto/kiunzi-micro-frontend-tools --project mfe1 --type microfrontend --port 8001 --library lib
ng add @jamarsto/kiunzi-micro-frontend-tools --project mfe2 --type microfrontend --port 8002 --library lib

Next, update the tsconfig.json to add the resolveJsonModule and esModuleInterop flags

{
  "compileOnSave": false,
  "compilerOptions": {
    "resolveJsonModule": true,
    "esModuleInterop": true,

Finally, make sure the library is linked locally so that it is exposed as an npm package to the build

cd projects/lib
npm link
cd ../..
npm link lib

You may need to restart your ide for the tsconfig.json and npm link changes to be picked up

📀Getting Started

Update projects/shell/src/app/app-routing.module.ts to add the modules to customShellRoutes.moduleRoutes

export const customShellRoutes: CustomShellRoutes = {
	headRoutes: [
		{ path: '', redirectTo: 'retail', pathMatch: 'full' },
		{ path: 'unauthorized', component: UnauthorisedComponent }
	],
	moduleRoutes: [
		{ title: 'Module One', name: 'mfe1', prefix: 'one', items: [], guards: [AutoLoginAllRoutesWithRoleGuard], roles: ['ADMIN', 'USER'] },
		{ title: 'Module Two', name: 'mfe2', prefix: 'two', items: [], guards: [AutoLoginAllRoutesWithRoleGuard], roles: ['ADMIN', 'USER'] }
	],
	tailRoutes: [
		{ path: '**', component: NotFoundComponent }
	]
}

Update the src/app/remote-app/remote-app-routing.module.ts for each module to reflect the routing required within the module

const customRoutes: CustomModuleRoutes = {
  headRoutes: [
    { path: '', redirectTo: shellModule.prefix, pathMatch: 'full' },
    { path: 'unauthorized', component: UnauthorisedComponent }
  ],
  moduleRoute: { component: RootComponent, guards: [AutoLoginAllRoutesWithRoleGuard], roles: ['ADMIN', 'USER'], children: [
    { path: '', component: HomeComponent },
    { path: 'example', component: ExampleComponent },
  ]},
  tailRoutes: []
}

Update the src/assets/menu.json for each module to reflect routes we want to add to the shell navigation bar

{
    "menuItems": [
        { "title": "Home", "link": "/", "fullMatch": true },
        { "title": "Example", "link": "/example", "fullMatch": false }
    ]
}

Add a proxy.conf.json to the angular workspace, making sure the entries created match the modules created

{
    "/mfe/mfe1": {
        "target": "http://localhost:8001",
        "pathRewrite": {
            "^/mfe/mfe1/": "/"
        },
        "secure": false,
        "changeOrigin": true
    },
    "/mfe/mfe2": {
        "target": "http://localhost:8002",
        "pathRewrite": {
            "^/mfe/mfe2/": "/"
        },
        "secure": false,
        "changeOrigin": true
    }
}

Add proxyConfig to the serve section of the shell project in angular.json

"serve": {
    "builder": "ngx-build-plus:dev-server",
        "configurations": {
            "production": {
                "browserTarget": "shell:build:production",
                "extraWebpackConfig": "projects/shell/webpack.prod.config.js"
            },
            "development": {
                "browserTarget": "shell:build:development",
                "proxyConfig": "proxy.conf.json"
            }
        },

The modules and shell are now ready to be built and run as normal

✨Development

The shellModule constant in each src/app/remote-app/remote-app-routing.module.ts is used to simulate the shell when testing the micro-frontend in standalone mode

export const shellModule: Module = {name: 'mfe1', title: 'Module One', prefix: 'one', items: jsonMenuItems.menuItems as MenuItems};

The navigation bar in the projects/src/shell/app/component/header/header.component.ts is dynamically generated using the src/assets/menu.json from each module

ngOnInit(): void {
  this.modules.forEach((entry) => this
      .menuItemService
      .getMenuItemsForModule(entry.name)
      .subscribe((children) => entry.items = children));
}

To keep the routes from the shell and modules in sync Kiunzi uses events under the hood. To register the event handling we use syncRouteShell.sync in the constructor of projects/shell/src/app/app.component.ts

constructor(private router: Router, private syncRouteShell: SyncRouteShell) {
  this.syncRouteShell.sync(this.router, customShellRoutes);
}

and we use syncRouteModule.sync in ngOnInit of src/app/remote-app/remote-app.component.ts in each module

ngOnInit(): void {
  this.syncRouteModule.sync(this.router, shellModule.name);
}

📄License

This project is licensed under the MIT license. See the LICENSE

0.0.44

2 years ago

0.0.43

2 years ago

0.0.42

2 years ago

0.0.41

2 years ago

0.0.40

2 years ago

0.0.39

2 years ago

0.0.38

2 years ago

0.0.37

2 years ago

0.0.36

2 years ago

0.0.35

2 years ago

0.0.34

2 years ago

0.0.33

2 years ago

0.0.32

2 years ago

0.0.31

2 years ago

0.0.30

2 years ago

0.0.28

2 years ago

0.0.27

2 years ago

0.0.26

2 years ago

0.0.25

2 years ago

0.0.24

2 years ago

0.0.23

2 years ago

0.0.22

2 years ago

0.0.21

2 years ago

0.0.20

2 years ago

0.0.18

2 years ago

0.0.17

2 years ago

0.0.16

2 years ago

0.0.15

2 years ago

0.0.13

2 years ago

0.0.12

2 years ago

0.0.11

2 years ago

0.0.10

2 years ago

0.0.9

2 years ago

0.0.8

2 years ago

0.0.7

2 years ago

0.0.6

2 years ago

0.0.5

2 years ago

0.0.4

2 years ago

0.0.3

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago