Skip to content

Latest commit

 

History

History
252 lines (208 loc) · 9.95 KB

advanced-scenarios.md

File metadata and controls

252 lines (208 loc) · 9.95 KB

Expert scenarios

This is a collection of advanced use cases and example implementations. If you are new to Luigi, take a look at our Getting Started section first.

Use a SPA router and keep Luigi Core URL in sync

Overview

This example shows you how to keep an existing routing strategy and use an existing micro frontend as drop-in without the need to refactor everything to LuigiClient.linkManager(). To update the Luigi Core URL when routing internally with the micro frontend router, without updating the URL on the Luigi Client side, use the linkManager() withoutSync and fromVirtualTreeRoot methods.

If you are running Luigi Core v0.7.7+, you can use fromClosestContext instead of fromVirtualTreeRoot, which requires a navigationContext at the virtualTree node configuration.

NOTE: This is a very simple example. For cases like modals or split views, you still require the use of Luigi Client.

Steps

  1. Configure the Luigi navigation node:

NOTE: To keep the example simple, we use virtualTree to allow any nested navigation, but this is not mandatory. You can always specify the node tree yourself and still use automatic navigation with router events.

    {
      pathSegment: 'Orders',
      label: 'orders',
      viewUrl: 'https://orders.microfrontend/',
      virtualTree: true
    }
  1. Use an Angular Router for navigation.

Angular provides Router events. We are reacting on NavigationEnd to update the URL after a successful route change.

We assume that the whole Angular app is one micro frontend and has its routes declared on the root level:

  { path: 'preload', component: PreloadComponent },
  { path: '', component: OrderListComponent },
  { path: ':id', component: OrderComponent },
  { path: ':id/details', component: OrderDetailsComponent },

Use this code to implement luigi-auto-navigation.service.ts, which is globally imported in our app.module.ts:

import { Router, NavigationEnd } from '@angular/router';
import { Injectable, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import { linkManager } from '@luigi-project/client';

@Injectable({ providedIn: 'root' })
export class LuigiAutoNavigationService implements OnDestroy {
  private subscriptions: Subscription = new Subscription();
  constructor(private router: Router) {
    this.subscriptions.add(
      router.events
        .pipe(filter(ev => ev instanceof NavigationEnd))
        .subscribe((ev: NavigationEnd) => {
          linkManager()
            .fromVirtualTreeRoot()
            .withoutSync()
            .navigate(ev.url);
        })
    );
  }

  ngOnDestroy(): void {
    this.subscriptions.unsubscribe();
  }
}

app.module.ts:

@NgModule({
    providers: [LuigiAutoNavigationService],

Result

Other than the added service, which you can also implement as a RouteGuard or similar, the micro frontend is unchanged and uses [routerLink=''] or other functionality to navigate.

Authenticate Luigi with Google Cloud Identity

Overview

This example shows you how to use Luigi with a Google account.

Steps

  1. Register a project and generate an OAuth2 Web Client based on Google Developers Identity - OAuth2UserAgent.
  2. To get your app running locally, set the Authorized JavaScript Origins URIs to http://localhost:4200 and Authorized redirect URIs to http://localhost:4200/luigi-core/auth/oauth2/callback.html?storageType=localStorage.
  3. Copy the Client ID which ends with apps.googleusercontent.com.
  4. Update the LuigiConfig auth section. In this example, we have also provided a configuration for logout and getting user information:
  {
    auth: {
      use: 'oAuth2ImplicitGrant',
      oAuth2ImplicitGrant: {
        authorizeUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
        oAuthData: {
          response_type: 'id_token token',
          client_id: 'YOUR_CLIENT_ID...apps.googleusercontent.com',
          scope: 'openid https://www.googleapis.com/auth/userinfo.email profile',
        }
      },
      logoutFn: async (settings, authData, logoutCallback) => {
        console.log('revoking token');
        await fetch(`https://accounts.google.com/o/oauth2/revoke?token=${authData.accessToken}`);
        logoutCallback('/logout.html');
      }
    }
  }

Google's id_token contains basic identity data like name and user ID, which allows for this data to be shown in the profile. 5. If you would also like to show the user picture, add the following code to enrich the user profile information:

  userInfoFn: async (settings, authData) => {
    const response = await fetch('https://www.googleapis.com/oauth2/v1/userinfo', {
      method: 'GET',
      headers: {
        'Authorization': 'Bearer ' + authData.accessToken
      }
    });
    const json = await response.json();
    return json;
  },

Use Feature Toggles in Luigi

There are two possibilities to add feature toggles to the active feature toggles list. On the one hand you can use the core api and on the other hand it is possible to add a feature toggle through url parameters.

Overview

Luigi allows you to implement and configure feature toggles. They can be used to organize and compartmentalize your code.

Usage

  • To set feature toggles, you have two possibilities:
    1. Set feature toggles to the active feature toggle list through Luigi Core API:
      Luigi.featureToggles().setFeatureToggle('ft1');
    1. Set feature toggles to the active feature toggle list via URL parameters:
    http://localhost:4200/projects/pr1?ft=ft1,ft2
    
  • To unset feature toggles, you have to use the Core API:
      Luigi.featureToggles().unsetFeatureToggle('ft1');
  • To restrict node visiblity with feature toggles: You can define a list of feature toggles for a particular top or left navigation node. Then, you can use the visibleForFeatureToggles parameter in order to display the node for certain feature toggles. For example, this node will be visible if ft1 is added to the active feature toggle list:
    {
        category: { label: 'Feature Toggle: Settings 2', icon: 'action-settings' },
        pathSegment: 'settings_ft',
        label: 'Project Settings 2',
        viewUrl: '/sampleapp.html#/projects/' + projectId + '/settings',
        icon: 'settings',
        visibleForFeatureToggles: ['ft1']
    }
    It is also possible to negate the visibility of a node by adding an exclamation mark at the beginning of the feature toggle name. In this example, the node is always visible except if ft1 is set as an active feature toggle:
    {
        category: { label: 'Feature Toggle: Settings 2', icon: 'action-settings' },
        pathSegment: 'settings_ft',
        label: 'Project Settings 2',
        viewUrl: '/sampleapp.html#/projects/' + projectId + '/settings',
        icon: 'settings',
        visibleForFeatureToggles: ['!ft1']
    }
  • To use feature toggles in a micro frontend: It is possible to restrict content in a micro frontend using feature toggles. The active feature toggle list is available in the Luigi Client API.
      if (LuigiClient.getActiveFeatureToggles().includes('ft1')) {
        //display content
      }

Use Intent-Based Navigation in Luigi Client

Overview

Luigi Client allows you to navigate through micro frontends by using an intent-based navigation. This type of navigation decouples navigation triggers from the actual navigation targets. Rather than directly encoding the name of the target app into the URL fragment, app developers provide a navigation intent such as display or edit as shown in the examples below.

Usage

  • To enable intent-based navigation, you need to first identify the necessary target mappings. This can be done by defining intentMapping in the Luigi configuration under navigation as in the example below:

    intentMapping = [
      {
        semanticObject: 'Sales',
        action: 'display',
        pathSegment: '/projects/sap/munich/database/sales/display'
      },
      {
        semanticObject: 'Sales',
        action: 'edit',
        pathSegment: '/projects/sap/munich/database/sales/edit'
      }
    ];
    1. The intent link is built using the semanticObject, action and optional parameters in the following format: #?intent=semanticObject-action?params. An example of an intent link would be as follows:
      #?intent=Sales-edit?id=100
    1. Navigation to a micro frontend through this intent is then made possible by using the linkManager navigate method from Luigi Client API:
      LuigiClient.linkManager().navigate('#?intent=Sales-edit?id=100');
    1. This method would then be navigating to the translated real path segment:
      https://example.com/projects/sap/munich/database/sales/edit?~id=100;
    1. Alternatively, the intent link can also be accessed through the browser URL and accessed from outside:
      https://example.com/#?intent=Sales-edit?id=100;