ngx-feature-flag-router
TypeScript icon, indicating that this package has built-in type declarations

14.0.4 • Public • Published

NgxFeatureFlagRouter

GitHub package.json version GitHub npm npm Website Custom badge

Demo

Extends RouteModule functionality to allow for conditionally lazy-loading child routes based on feature flag. Allows for Services to configure Routes and includes helpers for preload strategy.

This allows you to use an endpoint to lazy-load modules, easily redirect users to 403/404 pages, performant A/B testing for features.

Angular Major Version Support

Angular Version Support
9 Yes
10 Yes
11 Yes
12 Yes
13 Yes
14 Mostly. Support for loadComponent coming soon

Installation

Add:

ng add ngx-feature-flag-router

Update:

ng update ngx-feature-flag-router #Updates ngx-feature-flag-router to latest version

If you're not using the latest version of Angular, you'll have to specify the major version:

ng update ngx-feature-flag-router@10 #Specific to Angular 10

How to Use

  1. Replace RouterModule.forChild() with FeatureFlagRouterModule.forChild()

Before:

import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
    /*...*/
];

@NgModule({
    imports: [RouterModule.forChild(routes)],
})
export class MyModule {}

After:

import { FeatureFlagRouterModule, FeatureFlagRoutes } from 'ngx-feature-flag-router';

const routes: FeatureFlagRoutes = [
    /*...*/
];

@NgModule({
    imports: [FeatureFlagRouterModule.forChild(routes)],
})
export class MyModule {}
  1. Add alternativeLoadChildren and featureFlag to conditional lazy-load alternative module when featureFlag returns true

Before:

const routes: Routes = [
    {
        path: 'hello-world',
        loadChildren: () => import('./hello-world.module').then((m) => m.HelloWorldModule),
    },
];

After:

const routes: FeatureFlagRoutes = [
    {
        path: 'hello-world',
        loadChildren: () => import('./hello-world.module').then((m) => m.HelloWorldModule),
        alternativeLoadChildren: () => import('./feature.module').then((m) => m.FeatureModule),
        featureFlag: () => showFeature(), // Function that returns boolean
    },
];

How to Use Services / API

  1. Add your Service ( MyService ) as the second argument of FeatureFlagRouterModule.forChild()
import { FeatureFlagRouterModule, FeatureFlagRoutes } from 'ngx-feature-flag-router';

// Initialize routes that don't require Service
const routes: FeatureFlagRoutes = [
    /*...*/
];

@NgModule({
    imports: [FeatureFlagRouterModule.forChild(routes, MyService)],
})
export class MyModule {}
  1. Add implements FeatureFlagRoutesService to your Service.
@Injectable({ providedIn: 'root' })
export class FeatureFlagService implements FeatureFlagRoutesService {
    // ...
}
  1. Add getFeatureRoutes() method and return your FeatureFlagRoutes
@Injectable({ providedIn: 'root' })
export class FeatureFlagService implements FeatureFlagRoutesService {
    // Get current user id
    private readonly userId$: Observable<number> = this.getUserId();

    constructor(private readonly httpClient: HttpClient) {}

    /** Set additional routes using Service */
    getFeatureRoutes(): FeatureFlagRoutes {
        return [
            {
                path: 'api-example',
                loadChildren: () => import('api-feature-flag-off.module').then((m) => m.ApiFeatureFlagOffModule),
                alternativeLoadChildren: () => import('api-feature-flag-on.module').then((m) => m.ApiFeatureFlagOnModule),
                featureFlag: () => this.showFeature(), // Function that returns Observable<boolean>
            },
        ];
    }

    /** Determine showing feature based on user id and API response */
    showFeature(): Observable<boolean> {
        // Use current user id
        return this.userId$.pipe(
            switchMap((userId) => {
                // Make specific request for that user
                return this.httpClient.get<UserStatus>('some/api');
            }),
            map((userStatus) => {
                // Check if we want to turn feature flag on or not
                return userStatus.authorized;
            }),
            // Replay results until user id changes if you only want to make the api request once
            shareReplay({ bufferSize: 1, refCount: true }),
        );
    }
}

Mono Repo

Demo and library is managed using Nx.

Contributing

Before adding any new feature or a fix, make sure to open an issue first :)

  1. Make sure to use the expected node/npm versions
node -v # v14.17.1
npm -v # 6.14.13

If you have the wrong versions, I suggest using nvm or volta for node version management.

  1. Clone the project and install dependencies
git clone https://github.com/m-thompson-code/ngx-feature-flag-router.git
npm install
  1. Create a new branch
git checkout -b feature/some-feature
  1. Add tests and make sure demo and library jest / cypress tests pass
npm run test # both demo and ngx-feature-flag-router lib

or

npm run test:demo # only demo
npm run test:lib # only ngx-feature-flag-router lib

You can also run jest tests separately

npm run jest:demo # only demo jest tests
npm run jest:lib # only ngx-feature-flag-router lib jest tests

and cypress tests separately

npm run e2e:demo # only demo cypress tests
npm run e2e:lib # only ngx-feature-flag-router lib cypress tests
  1. commit > push > create a pull request 🚀

Package Sidebar

Install

npm i ngx-feature-flag-router

Weekly Downloads

2

Version

14.0.4

License

MIT

Unpacked Size

226 kB

Total Files

51

Last publish

Collaborators

  • m-thompson-code