import { Steps, Tab, Tabs, Badge, Aside } from '@theme';


# Angular CLI Setup

This guide explains how to integrate Module Federation with Angular CLI. The `@angular-architects/module-federation` plugin is used to assist with this integration.

## Prerequisites

- **Angular CLI**: Version 10 or higher.
- **Plugin Installation**: Install the `@angular-architects/module-federation` plugin.

## Installation


  To start, configure the Angular CLI to use Module Federation during the build phase.
  A custom builder is needed to unlock Module Federation's potential.

  The `@angular-architects/module-federation` package provides this custom builder.
  Use the ng add command to incorporate it into your projects:

  <Tabs>
    <Tab label="Angular CLI">
      ```bash
      ng add @angular-architects/module-federation --project shell --port 4200 --type host
      ng add @angular-architects/module-federation --project mfe1 --port 4201 --type remote
      ```
    </Tab>
    <Tab label="Nx Cli">
      For Nx users, the procedure is slightly different.

      ```bash
      npm i @angular-architects/module-federation -D
      ng g @angular-architects/module-federation:init --project shell --port 4200 --type host
      ng g @angular-architects/module-federation:init --project mfe1 --port 4201 --type remote
      ```

    </Tab>
  </Tabs>
  <div className={"rspress-directive tip"}>
    The `--type` argument, introduced in version 14.3, ensures that only the necessary configuration is generated.
  </div>

## Shell (Host) Configuration

The Shell (Host) is crucial for Module Federation integration.
This section configures the Shell to support lazy-loading of a `FlightModule` through routing.
<Steps>
  ### Routing Configuration

  Start by defining the application routes, specifying a lazy-loaded `FlightModule` using a virtual path:

  ```javascript
  export const APP_ROUTES: Routes = [
    {
      path: '',
      component: HomeComponent,
      pathMatch: 'full'
    },
    {
      path: 'flights',
      loadChildren: () => import('mfe1/Module').then(m => m.FlightsModule)
    },
  ];
  ```

  In this configuration, the path `'mfe1/Module'` is a virtual representation, indicating it doesn't physically exist within the Shell application. Instead, it's a reference to a module in a separate project.

### TypeScript Typing

Create a type definition for the virtual path:

```typescript
// decl.d.ts
declare module 'mfe1/Module';
```

This helps the TypeScript compiler understand the virtual path.

### Webpack Configuration

Instruct Webpack to resolve all paths prefixed with `mfe1` to a remote project. This is done in the `webpack.config.js` file:

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

module.exports = withModuleFederationPlugin({

   remotes: {
     "mfe1": "http://localhost:4201/remoteEntry.js",
   },

   shared: {
     ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
   },

});
```
  In the `remotes` section, the path `mfe1` is mapped to the remote micro-frontend's entry point. This entry point, generated by Webpack, contains essential information for interacting with the micro-frontend.

<details>

  For development, hardcoding the remote entry's URL is enough. However, a dynamic approach is necessary for production. The concept of dynamic remotes is further explored in a dedicated documentation page on Dynamic Remotes.

  - The `shared` property specifies the npm packages to be shared between the Shell and the micro-frontend(s). Using the `shareAll` helper method, all dependencies listed in your `package.json` are shared. While this facilitates a quick setup, it may lead to an excessive number of shared dependencies, which could be a concern for optimization.
  - The combination of `singleton: true` and `strictVersion: true` settings instructs Webpack to throw a runtime error if there is a version mismatch between the Shell and the micro-frontend(s). Changing `strictVersion` to `false` would instead result in a runtime warning.
  - The `requiredVersion: 'auto'` option, provided by the `@angular-architects/module-federation` plugin, automatically determines the version from your `package.json`, helping to prevent version-related issues.
</details>
</Steps>


## Configuring the Remote

The Micro-frontend, also known as the Remote in Module Federation, has a structure similar to a standard Angular app. It has specific routes in the `AppModule` and a `FlightsModule` for flight-related tasks. This section explains how to smoothly load the `FlightsModule` into the Shell (Host).

<Steps>
### Route Definition

Establish the basic routes within the `AppModule`:

```typescript
export const APP_ROUTES: Routes = [
     { path: '', component: HomeComponent, pathMatch: 'full'}
 ];
```

This simple routing setup navigates to a `HomeComponent` when the application is accessed.

### Module Creation

Create a `FlightsModule` to handle flight-related operations:

```typescript
@NgModule({
   imports: [
     CommonModule,
     RouterModule.forChild(FLIGHTS_ROUTES)
   ],
   declarations: [
     FlightsSearchComponent
   ]
 })
 export class FlightsModule { }
```

This module contains a route to a `FlightsSearchComponent` defined as follows:

```typescript
export const FLIGHTS_ROUTES: Routes = [
     {
       path: 'flights-search',
       component: FlightsSearchComponent
     }
 ];
```

### Exposing Modules via Webpack Configuration

To enable the loading of `FlightsModule` into the Shell, expose it through the Remote's Webpack configuration:

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

module.exports = withModuleFederationPlugin({
   name: 'mfe1',
   exposes: {
     './Module': './projects/mfe1/src/app/flights/flights.module.ts',
   },
   shared: {
     ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
   },
});
```

<details>
In this configuration:

- The `name` property identifies the micro-frontend as `mfe1`.
- The `exposes` property signifies the exposure of `FlightsModule` under the public name `Module`, allowing its consumption by the Shell.
- The `shared` property lists the libraries to be shared with the Shell, using the `shareAll` method to share all dependencies found in your `package.json`. The `singleton: true` and `strictVersion: true` properties ensure that a single version of shared libraries is used, and a runtime error is triggered in case of version incompatibility, respectively.
</details>

</Steps>

## Starting the Applications

Having set up the Shell (Host) and Micro-frontend (Remote), it's time to test the configuration to ensure the seamless integration of Module Federation.

To start the Shell and Micro-frontend, use the following commands:

```bash
ng serve shell -o
ng serve mfe1 -o
```

Navigate to the Flights section in the Shell to see the Micro-frontend being dynamically loaded.

:::tip
The plugin installs an npm script `run:all` during the `ng-add` and `init` schematics, allowing for simultaneous serving of all applications:

```bash
npm run run:all
# or
npm run run:all shell mfe1
```
:::


## Optimizing Dependency Sharing

The initial setup with `shareAll` is simple and functional, but it can result in the creation of unnecessarily large shared bundles.

To manage shared dependencies more effectively, consider switching from `shareAll` to using the `share` helper. This provides finer control over which dependencies are shared:

```javascript
// Replace shareAll with share:
const { share, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack');

module.exports = withModuleFederationPlugin({
    // Specify the packages to share:
    shared: share({
        "@angular/core": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
        "@angular/common": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
        "@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
        "@angular/router": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
    })
});
```

In this configuration, the `share` helper allows for explicit sharing of selected packages, enabling a more optimized bundle sharing and potentially reducing load times.

