npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@unily/angular-sdk

v17.1.0

Published

This SDK provides the tools needed to support Angular Module Federation development within Unily

Downloads

1,384

Readme

Unily - Angular SDK

This SDK provides the tools needed to support Angular Module Federation development within Unily. It includes a schematics package that automatically sets up the scaffolding for a new micro frontend module build, it generates the essential files and configurations needed to make Angular Module Federation facilities available within the set workspace.

Prerequisites

This project requires NodeJS and NPM to be installed. To make sure you have them available on your machine, try running the following commands:

npm -v
node -v

Installation

To run the schematics collection, first you'll need to install the following Angular development packages globally on your machine so they will provide you with the schematics command line tools:

npm install -g @angular-devkit/schematics
npm install -g @angular-devkit/schematics-cli

Next, install this SDK globally on your machine:

npm install -g @unily/angular-sdk

Usage

Target the workspace folder you wish to generate the micro frontend module in, then run the new-mfe schematic with the following command:

cd {path}
schematics @unily/angular-sdk:new-mfe

This will prompt you to input some configuration settings for the new project:

  • Project name - This will set the workspace directory name accordingly
  • Angular directive selector prefix - This will enforce a linting rule across the project requiring the set value as a prefix for the 'selector' property
  • Webpack server port number - This will set the port number for the module to run on

After running the schematic, the workspace will be populated with the associated file structure. Package dependencies will also be downloaded and installed automatically to prepare the newly generated module for development.

Configuration

Environment configuration details can be fetched from the CMS.

Run MFE

To start a module on your local environment, run the following command:

Note - This will serve the module on the configured port number.

npm run start

Deploy MFE

To deploy a module, run the following commands:

npm run build
npm run deploy

This will prompt you to choose from different deployment options:

  • Lazy Loaded - Choose whether the module should be lazily or eagerly loaded
  • Starts enabled - Choose whether the module should be immediately enabled after being deployed

The module will then be added to the 'Application Federated Modules' page in the CMS once it's been successfully deployed.

Deploy via CI/CD pipelines

Alternative to deploying manually, deploying via CI/CD pipelines can be achieved by calling the deploy-ci script with the required parameters.

To do so, update your pipeline to run the following command.

Note that the parameters passed to the npm script need to be passed to a node script hence the use of -- is very important

npm run deploy-ci -- -h https://myexamplehost-api.unily.com -c myClientId -s myClientSecret

The deploy-ci script accepts the following options. Each option requires a value assigned to it. Options can be used in the short or long version. Both will have the same result.

  • -h, --host - The domain of your api gateway
  • -c, --clientId - Your client ID. Contact customer support to provide you one.
  • -s, --secret - Your secret key. Contact customer support to provide you one.
  • -l, --lazy - Accepts a boolean value. True or false. Defaults to true if unspecified. If true, the module will be configured as lazy loaded. If false, it would be loaded eagerly.
  • -e, --enabled - Accepts a boolean value. True or false. Defaults to true if unspecified. If true, the module will be enabled, otherwise it will not and will never be loaded.

Examples

  • Deploying a module that is enabled, and eagerly loaded
npm run deploy-ci -- -h https://myexamplehost-api.unily.com -c myClientId -s myClientSecret -l false
  • Deploying a module that is lazy loaded but not enabled
npm run deploy-ci -- -h https://myexamplehost-api.unily.com -c myClientId -s myClientSecret -e false
  • Deploying a module that is eagerly loaded but not enabled
npm run deploy-ci -- --host  https://myexamplehost-api.unily.com --clientId myClientId --secret myClientSecret --lazy false --enabled false

Functionality

The public surface of a newly generated module is defined by what we expose in webpack.config.js file. Anything that needs to be exposed publicly by the module needs to be defined in public.module.metadata.ts file:

Note: If you do not wish to export a component and prefer to keep it as internal, you just need to exclude it from the exports array.

public.module.metadata.ts

...
export const metadata = {
    imports: [
        BrowserModule
    ],
    declarations: [
        ButtonComponent,
    ],
    exports: [
        // On bootstrap, custom HTML elements are created for the components listed here.
        // These components will be immediately available when a module is imported.
        ButtonComponent,
    ],
    providers: [
        // These are the services that will be publicly exposed by this module.
        // The string token allows us to have a reference to the injector without requiring any reference to a specific construct inside this module.
        // Specified dependencies do not need to be exported, but they need to be specified here for the services that require them.
        {
            provide: 'ButtonService',
            useClass: ButtonService,
            deps: [IncrementService]
        }
    ],
    // We specify this to allow custom elements to be used within HTML templates.
    // It suppresses Angular warnings about non-existent selectors at compile time.
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
} as NgModule;
...

Module loading

These are the capabilities of loading a remote module:

  • Can be side-loaded through CMS config ✔
  • Can be imported ✔
  • Can be lazy loaded ✔
  • Can be deployed to a blob ✔
  • Requires environment redeployment on change ❌
  • Can side-load modules through CMS config ❌

Note: Remote modules do not import side-loaded modules explicitly, but inherit any side-loaded module configurations. When running stand-alone, the side-loaded modules will not be available to the remote module.

Dynamically importing modules

A remote module can import myFederatedModules, applicationFederatedModules and unilyFederatedModules modules. Each remote module is configured separately and can import other modules' type definitions when their name is added inside module-federation/mf.config.js file.

mf.config.js

module.exports = {
    projectName: 'my-project',
    dependencies: {
        // Load types from the client's blob storage.
        applicationFederatedModules: [
            /* 
                'app-state',
                'ui-library'
                ...
            */
        ],
        // Load types from Unily's package manager.
        unilyFederatedModules: [
            /* 
                'unily-ui-library'
                ...
            */
        ],
        // Load types AND remote modules from the local environment. 
        // This is useful for testing and development without having to side-load modules through the CMS.
        myFederatedModules: [
            /*
                'app-state',
                'counter'
                ...
            */
        ]
    },
    // Authentication token needed to load types for `applicationFederatedModules` and `unilyFederatedModules`
    // OR to deploy the current module.
    /**
     * Fetch your endpoint and auth token from
     * 'My Federated Modules' or 'Application Federated Modules' pages in CMS
     * by clicking on 'Get PAT Token' and copying the values provided
     * in the overlay.
     */ 
    endpoint: '',
    authToken: ''
}

Lazy loading

Modules can be either lazily or eagerly loaded. Eagerly loaded modules are imported and bootstrapped before the module importing those modules is bootstrapped. This is useful when a module specifies some global state or runs an app initialisation script. Lazily loaded modules need to be manually imported wherever they are first needed using a dynamic import as follows:


...
import { RemoteNgModule, importRemote } from '@unily/remote-service';
...
// Dynamically import the module - this lazily loads the module when the importing module is bootstrapped.
// By this point, we can already use any exported components.
const uiLibrary = await importRemote<RemoteNgModule>('ui-library');
const counter = await importRemote<RemoteNgModule>('counter');
...
@NgModule({
    ...
    providers: [
        ...
        // add the service provider for the desired service from the imported module
        uiLibrary.getProviders('ButtonService'),
        ...
    ],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
...
    private readonly counterService: CounterService;

    constructor(
        ...
        // inject the service using the provided injection token...
        @Inject('ButtonService') private readonly buttonService: ButtonService,
        ...
    ) {
        // ...or get the service directly without providing or injecting it.
        this.counterService = counter.getService('CounterService');
    }
 ...   

More information about Angular Module Federation and its setup can be found in this Wiki page.