diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index 4f833d7113..b721948787 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -1932,6 +1932,14 @@ "isExternal": false, "children": [], "disableCollapsible": false + }, + { + "name": "How to Federate a Module", + "path": "/recipes/module-federation/federate-a-module", + "id": "federate-a-module", + "isExternal": false, + "children": [], + "disableCollapsible": false } ], "disableCollapsible": false @@ -3306,6 +3314,14 @@ "isExternal": false, "children": [], "disableCollapsible": false + }, + { + "name": "How to Federate a Module", + "path": "/recipes/module-federation/federate-a-module", + "id": "federate-a-module", + "isExternal": false, + "children": [], + "disableCollapsible": false } ], "disableCollapsible": false @@ -3326,6 +3342,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "How to Federate a Module", + "path": "/recipes/module-federation/federate-a-module", + "id": "federate-a-module", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Enforce Module Boundaries", "path": "/recipes/enforce-module-boundaries", diff --git a/docs/generated/manifests/nx.json b/docs/generated/manifests/nx.json index 059622ad75..5540769483 100644 --- a/docs/generated/manifests/nx.json +++ b/docs/generated/manifests/nx.json @@ -2408,6 +2408,16 @@ "isExternal": false, "path": "/recipes/module-federation/create-a-remote", "tags": [] + }, + { + "id": "federate-a-module", + "name": "How to Federate a Module", + "description": "A guide on how to federate a module in your Nx workspace", + "file": "shared/recipes/module-federation/federate-a-module", + "itemList": [], + "isExternal": false, + "path": "/recipes/module-federation/federate-a-module", + "tags": [] } ], "isExternal": false, @@ -4122,6 +4132,16 @@ "isExternal": false, "path": "/recipes/module-federation/create-a-remote", "tags": [] + }, + { + "id": "federate-a-module", + "name": "How to Federate a Module", + "description": "A guide on how to federate a module in your Nx workspace", + "file": "shared/recipes/module-federation/federate-a-module", + "itemList": [], + "isExternal": false, + "path": "/recipes/module-federation/federate-a-module", + "tags": [] } ], "isExternal": false, @@ -4148,6 +4168,16 @@ "path": "/recipes/module-federation/create-a-remote", "tags": [] }, + "/recipes/module-federation/federate-a-module": { + "id": "federate-a-module", + "name": "How to Federate a Module", + "description": "A guide on how to federate a module in your Nx workspace", + "file": "shared/recipes/module-federation/federate-a-module", + "itemList": [], + "isExternal": false, + "path": "/recipes/module-federation/federate-a-module", + "tags": [] + }, "/recipes/enforce-module-boundaries": { "id": "enforce-module-boundaries", "name": "Enforce Module Boundaries", diff --git a/docs/map.json b/docs/map.json index 7e09d1f34d..29b0303373 100644 --- a/docs/map.json +++ b/docs/map.json @@ -833,6 +833,12 @@ "name": "How to create a Module Federation Remote Application", "description": "A guide on how to create a Module Federation Remote Application in your Nx workspace", "file": "shared/recipes/module-federation/creating-a-remote" + }, + { + "id": "federate-a-module", + "name": "How to Federate a Module", + "description": "A guide on how to federate a module in your Nx workspace", + "file": "shared/recipes/module-federation/federate-a-module" } ] }, diff --git a/docs/shared/recipes/module-federation/federate-a-module.md b/docs/shared/recipes/module-federation/federate-a-module.md new file mode 100644 index 0000000000..eb2db17cc9 --- /dev/null +++ b/docs/shared/recipes/module-federation/federate-a-module.md @@ -0,0 +1,164 @@ +# Federate a Module + +Module Federation is a concept that allows developers to share code between applications at run-time. It is a way of doing micro-frontends, but it can also be used to share code between applications that are not micro-frontends. + +In the context of Module Federation, a _module_ can be thought as any piece of code, functionally independent, that can be reused in different applications. It can be a component, a service, a library, a utility, etc. + +In order to share a module, it must be _federated_. This means that the module must be configured to be shared, and the application that wants to use it must be configured to use it. + +**Nx** includes first class support for Module Federation for React and Angular applications. This means that you can federate modules in your workspace with a few simple commands. + +{% callout type="info" title="Assumption" %} +With this recipe we assume that you have already created a workspace with at least one React or Angular Module Federation host application. +If you haven't, you can follow the [Create a Host Recipe](https://nx.dev/recipes/module-federation/create-a-host). +{% /callout %} + +## Step 1: Create the module + +We will create a module that exports a hello function. +Since we are using Nx, we will create a library for this module. + +**Create a library** + +```shell +nx generate @nx/js:library --name=hello --unitTestRunner=jest --projectNameAndRootFormat=as-provided +``` + +Update the `hello.ts` file with the following code: + +```typescript {% fileName="hello/src/lib/hello.ts" %} +export default function hello(): string { + return 'Hello from Nx'; +} +``` + +Update `hello/` barrel file `index.ts` with the following code: + +```typescript {% fileName="hello/src/index.ts" %} +export { default } from './lib/hello'; +``` + +## Step 2: Federate the module + +Now that we have created the module, we need to configure it to be federated. + +{% tabs %} +{%tab label="React"%} + +```shell +nx generate @nx/react:federate-module Hello --remote=greeting --path=hello/src/index.ts --projectNameAndRootFormat=as-provided +``` + +{% /tab %} +{%tab label="Angular"%} + +```shell +nx generate @nx/angular:federate-module Hello --remote=greeting --path=hello/src/index.ts --projectNameAndRootFormat=as-provided +``` + +{% /tab %} +{% /tabs %} + +{% callout type="note" title="Remote does not exist" %} +If the remote provided does not exist (in this instance _greeting_), Nx will create it for you. +{% /callout %} + +This command will: + +- Adds a module entry to the `greeting` remote module federation config file. + +{% tabs %} +{%tab label="Typescript Config File"%} + +```typescript {% fileName="greeting/module-federation.config.ts" %} +import { ModuleFederationConfig } from '@nx/webpack'; + +const config: ModuleFederationConfig = { + name: 'greeting', + exposes: { + './Module': './src/remote-entry.ts', + './Hello': 'hello/src/index.ts', // <-- this line was added, + }, +}; +export default config; +``` + +{% /tab %} +{%tab label="Javascript Config File"%} + +```javascript {% fileName="greeting/module-federation.config.js" %} +module.exports = { + name: 'greeting', + exposes: { + './Module': './src/remote-entry.ts', + './Hello': 'hello/src/index.ts', // <-- this line was added + }, +}; +``` + +{% /tab %} +{% /tabs %} + +- Adds a Typescript path mapping to the `greeting/Hello` module in your root TSConfig file. + +```json {% fileName="/tsconfig.base.json" %} +{ + "paths": { + "greeting/Module": ["greeting/src/remote-entry.ts"], + "greeting/Hello": ["hello/src/index.ts"] // <-- this line was added + } +} +``` + +## Step 3: Use the module + +Update the host application to use the federated module. + +{% tabs %} +{%tab label="Typescript Config File"%} + +```ts {% fileName="host/module-federation.config.ts" %} +import { ModuleFederationConfig } from '@nx/webpack'; + +const config: ModuleFederationConfig = { + name: 'host', + remotes: ['greeting'], // <-- Ensure that greeting remote is listed here +}; + +export default config; +``` + +{% /tab %} +{%tab label="Javascript Config File"%} + +```javascript {% fileName="host/module-federation.config.js" %} +module.exports = { + name: 'host', + remotes: ['greeting'], // <-- Ensure that greeting remote is listed here +}; +``` + +{% /tab %} +{% /tabs %} + +```tsx {% fileName="host/src/app/app.tsx" %} +import hello from 'greeting/Hello'; + +export function App() { + return
{hello()}
; +} + +export default App; +``` + +If you are using Angular, you would update the application in a similar fashion to use the federated module. + +## Step 4: Run the application + +Just run the application as usual. + +```shell +nx serve host +``` + +To start the application, use the following address: [http://localhost:4200](http://localhost:4200). Once opened, you'll see the message **"Hello from Nx."** This message is loaded from the greeting remote, which runs on port 4201. diff --git a/docs/shared/reference/sitemap.md b/docs/shared/reference/sitemap.md index c2d4bceaab..e1978fc7f7 100644 --- a/docs/shared/reference/sitemap.md +++ b/docs/shared/reference/sitemap.md @@ -139,6 +139,7 @@ - [Module Federation](/recipes/module-federation) - [How to create a Module Federation Host Application](/recipes/module-federation/create-a-host) - [How to create a Module Federation Remote Application](/recipes/module-federation/create-a-remote) + - [How to Federate a Module](/recipes/module-federation/federate-a-module) - [Enforce Module Boundaries](/recipes/enforce-module-boundaries) - [Ban Dependencies with Certain Tags](/recipes/enforce-module-boundaries/ban-dependencies-with-tags) - [Tag in Multiple Dimensions](/recipes/enforce-module-boundaries/tag-multiple-dimensions)