Skip to content

Commit

Permalink
chore: migrate to module federation 2.0 (#168)
Browse files Browse the repository at this point in the history
* chore: Update the packages and samples to MF enhanced

* More stuff

* Fixed all tests

* Added tests for sharedDependenciesResolutionPlugin

* Clean up

* More stuff

* More docs

* More docs

* More stuff

* More stuff

* More doc fixes

* Rename @squide/firefly-configs to @squide/firefly-webpack-configs

* docs about shared dependencies

* Added a changeset file

* Updated CI script
  • Loading branch information
patricklafrance authored May 1, 2024
1 parent e4620f1 commit 89ace29
Show file tree
Hide file tree
Showing 160 changed files with 5,665 additions and 4,865 deletions.
111 changes: 111 additions & 0 deletions .changeset/funny-chairs-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
"@squide/firefly-webpack-configs": major
"@squide/module-federation": major
"@squide/webpack-configs": major
"@squide/react-router": major
"@squide/firefly": major
"@squide/core": major
---

This release Migrates Squide from Webpack Module Federation to [Module Federation 2.0](https://module-federation.io/guide/start/quick-start.html).

This release deprecates the following packages:

- `@squide/webpack-module-federation`, use `@squide/module-federation` instead.
- `@squide/firefly-configs`, use `@squide/firefly-webpack-configs` instead.

And introduce a few changes to existing API:

- The `FireflyRuntime` nows accept a `useMsw` option and expose a new `isMswEnabled` getter:

```ts
// bootstrap.tsx

import { FireflyRuntime } from "@squide/firefly";

const runtime = new FireflyRuntime({
useMsw: true
});

// Use the runtime to determine if MSW handlers should be registered.
if (runtime.isMswEnabled) {
// ...
}
```

- The `registerRemoteModules` function doesn't accept the remotes URL anymore. The remotes URL should be configured in the webpack configuration files.

Previously:

```ts
// bootstrap.tsx

import { registerRemoteModules, type RemoteDefinition } from "@squide/firefly";

const Remotes: RemoteDefinition = [
{
name: "remote1",
url: "http://localhost:8081"
}
];

await registerRemoteModules(Remotes, runtime);
```

```js
// webpack.dev.js

import { defineDevHostConfig } from "@squide/firefly-webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevHostConfig(swcConfig, "host", 8080, {
overlay: false
});
```

Now:

```ts
// bootstrap.tsx

import { registerRemoteModules, type RemoteDefinition } from "@squide/firefly";

const Remotes: RemoteDefinition = [
{
name: "remote1"
}
];

await registerRemoteModules(Remotes, runtime);
```

```js
// webpack.dev.js

import { defineDevHostConfig } from "@squide/firefly-webpack-configs";
import { swcConfig } from "./swc.dev.js";

/**
* @typedef {import("@squide/firefly-webpack-configs").RemoteDefinition}[]
*/
export const Remotes = [
{
name: "remote1",
url: "http://localhost:8081"
}
];

export default defineDevHostConfig(swcConfig, "host", 8080, Remotes, {
overlay: false
});
```

To migrate:

1. Replace the `@squide/webpack-module-federation` dependency by `@squide/module-federation`.

2. Replace the `@squide/firefly-configs` dependency by `@squide/firefly-webpack-configs`.

3. Move the remotes URL from the `bootstrap.tsx` file to the `webpack.*.js` files.

4. Integrate the new `useMsw` and `isMswEnabled` props.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: ">=20.0.0"
check-latest: true

- uses: pnpm/action-setup@v3
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ If you are having issue with the Retype license, make sure the `RETYPE_API_KEY`

There are a few steps to add new packages to the monorepo.

Before you add a new package, please read the [GSoft GitHub guidelines](https://github.com/gsoft-inc/github-guidelines#npm-package-name).
Before you add a new package, please read the [Workleap GitHub guidelines](https://github.com/gsoft-inc/github-guidelines#npm-package-name).

### Create the package

Expand All @@ -345,7 +345,7 @@ pnpm init

Answer the CLI questions.

Once the `package.json` file is generated, please read again the [GSoft GitHub guidelines](https://github.com/gsoft-inc/github-guidelines#npm-package-name) and make sure the package name, author and license are valid.
Once the `package.json` file is generated, please read again the [Workleap GitHub guidelines](https://github.com/gsoft-inc/github-guidelines#npm-package-name) and make sure the package name, author and license are valid.

Don't forget to add the [npm scope](https://docs.npmjs.com/about-scopes) `"@squide"` before the package name. For example, if the project name is "foo", your package name should be `@squide/foo`.

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# wl-squide

A federated web application shell built on top of [Module Federation](https://webpack.js.org/concepts/module-federation/) and [React Router](https://reactrouter.com/en/main).
A federated web application shell built on top of [Module Federation](https://module-federation.io/) and [React Router](https://reactrouter.com/en/main).

[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](./LICENSE)
[![CI](https://github.com/gsoft-inc/wl-squide/actions/workflows/ci.yml/badge.svg)](https://github.com/gsoft-inc/wl-squide/actions/workflows/ci.yml)
Expand All @@ -9,12 +9,12 @@ A federated web application shell built on top of [Module Federation](https://we
| --- | --- |
| [@squide/core](packages/core/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/core)](https://www.npmjs.com/package/@squide/core) |
| [@squide/react-router](packages/react-router/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/react-router)](https://www.npmjs.com/package/@squide/react-router) |
| [@squide/webpack-module-federation](packages/webpack-module-federation/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/webpack-module-federation)](https://www.npmjs.com/package/@squide/webpack-module-federation) |
| [@squide/module-federation](packages/module-federation/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/module-federation)](https://www.npmjs.com/package/@squide/module-federation) |
| [@squide/webpack-configs](packages/webpack-configs/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/webpack-configs)](https://www.npmjs.com/package/@squide/webpack-configs) |
| [@squide/msw](packages/msw/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/msw)](https://www.npmjs.com/package/@squide/msw) |
| [@squide/i18next](packages/i18next/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/i18next)](https://www.npmjs.com/package/@squide/i18next) |
| [@squide/firefly](packages/firefly/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/firefly)](https://www.npmjs.com/package/@squide/firefly) |
| [@squide/firefly-configs](packages/firefly-configs/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/firefly-configs)](https://www.npmjs.com/package/@squide/firefly-configs) |
| [@squide/firefly-webpack-configs](packages/firefly-webpack0configs/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/firefly-webpack-configs)](https://www.npmjs.com/package/@squide/firefly-webpack-configs) |
| [@squide/fakes](packages/fakes/README.md) | [![npm version](https://img.shields.io/npm/v/@squide/fakes)](https://www.npmjs.com/package/@squide/fakes) |

## Have a question or found an issue?
Expand Down
106 changes: 78 additions & 28 deletions docs/getting-started/create-host.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ Create a new application (we'll refer to ours as `host`), then open a terminal a

+++ pnpm
```bash
pnpm add -D @workleap/webpack-configs @workleap/swc-configs @workleap/browserslist-config @squide/firefly-configs webpack webpack-dev-server webpack-cli @swc/core @swc/helpers browserslist postcss typescript
pnpm add -D @workleap/webpack-configs @workleap/swc-configs @workleap/browserslist-config @squide/firefly-webpack-configs webpack webpack-dev-server webpack-cli @swc/core @swc/helpers browserslist postcss typescript @types/react @types/react-dom
pnpm add @squide/firefly react react-dom react-router-dom react-error-boundary
```
+++ yarn
```bash
yarn add -D @workleap/webpack-configs @workleap/swc-configs @workleap/browserslist-config @squide/firefly-configs webpack webpack-dev-server webpack-cli @swc/core @swc/helpers browserslist postcss typescript
yarn add -D @workleap/webpack-configs @workleap/swc-configs @workleap/browserslist-config @squide/firefly-webpack-configs webpack webpack-dev-server webpack-cli @swc/core @swc/helpers browserslist postcss typescript @types/react @types/react-dom
yarn add @squide/firefly react react-dom react-router-dom react-error-boundary
```
+++ npm
```bash
npm install -D @workleap/webpack-configs @workleap/swc-configs @workleap/browserslist-config @squide/firefly-configs webpack webpack-dev-server webpack-cli @swc/core @swc/helpers browserslist postcss typescript
npm install -D @workleap/webpack-configs @workleap/swc-configs @workleap/browserslist-config @squide/firefly-webpack-configs webpack webpack-dev-server webpack-cli @swc/core @swc/helpers browserslist postcss typescript @types/react @types/react-dom
npm install @squide/firefly react react-dom react-router-dom react-error-boundary
```
+++
Expand All @@ -44,6 +44,7 @@ host
├──── App.tsx
├──── RootLayout.tsx
├──── HomePage.tsx
├──── NotFoundPage.tsx
├──── bootstrap.tsx
├──── index.ts
├──── register.tsx
Expand Down Expand Up @@ -81,29 +82,23 @@ export {};

Next, to register the modules, instanciate a shell [FireflyRuntime](/reference/runtime/runtime-class.md) instance and register the remote module with the [registerRemoteModules](/reference/registration/registerRemoteModules.md) function (the configuration of the remote module will be covered in the [next section](create-remote-module.md)):

```tsx !#12-14,17-19,22 host/src/bootstrap.tsx
```tsx !#11-13,16 host/src/bootstrap.tsx
import { createRoot } from "react-dom/client";
import { ConsoleLogger, RuntimeContext, FireflyRuntime, registerRemoteModules, type RemoteDefinition } from "@squide/firefly";
import type { AppContext} from "@sample/shared";
import { App } from "./App.tsx";

// Define the remote modules.
const Remotes: RemoteDefinition[] = [
{ url: "http://localhost:8081", name: "remote1" }
{ name: "remote1" }
];

// Create the shell runtime.
const runtime = new FireflyRuntime({
loggers: [new ConsoleLogger()]
});

// Create an optional context.
const context: AppContext = {
name: "Demo application"
};

// Register the remote module.
await registerRemoteModules(Remotes, runtime, { context });
await registerRemoteModules(Remotes, runtime;

const root = createRoot(document.getElementById("root")!);

Expand Down Expand Up @@ -256,33 +251,27 @@ The [ManagedRoutes](../reference/routing/ManagedRoutes.md) placeholder indicates
Finally, update the bootstrapping code to [register](../reference/registration/registerLocalModules.md) the newly created local module:
```tsx !#23 host/src/bootstrap.tsx
```tsx !#17 host/src/bootstrap.tsx
import { createRoot } from "react-dom/client";
import { ConsoleLogger, RuntimeContext, FireflyRuntime, registerRemoteModules, type RemoteDefinition } from "@squide/firefly";
import type { AppContext} from "@sample/shared";
import { App } from "./App.tsx";
import { registerHost } from "./register.tsx";

// Define the remote modules.
const Remotes: RemoteDefinition[] = [
{ url: "http://localhost:8081", name: "remote1" }
{ name: "remote1" }
];

// Create the shell runtime.
const runtime = new FireflyRuntime({
loggers: [new ConsoleLogger()]
});

// Create an optional context.
const context: AppContext = {
name: "Demo application"
};

// Register the newly created local module.
await registerLocalModules([registerHost], runtime, { context });
await registerLocalModules([registerHost], runtime);

// Register the remote module.
await registerRemoteModules(Remotes, runtime, { context });
await registerRemoteModules(Remotes, runtime);

const root = createRoot(document.getElementById("root")!);

Expand All @@ -293,6 +282,53 @@ root.render(
);
```
### Not found page (404)
Now, let's ensure that users who enter a wrong URL end up somewhere by registering a custom [no-match route](https://reactrouter.com/en/main/start/faq#how-do-i-add-a-no-match-404-route-in-react-router-v6). First, create the `NotFoundPage` component, which will serve as the page for handling not found routes:
```tsx host/src/NotFoundPage.tsx
export function NotFoundPage() {
return (
<div>Not found! Please try another page.</div>
);
}
```
Then, register the newly created component as the `*` route:
```tsx !#19-24 host/src/register.tsx
import { ManagedRoutes, type ModuleRegisterFunction, type FireflyRuntime } from "@squide/firefly";
import { HomePage } from "./HomePage.tsx";
import { NotFoundPage } from "./NotFoundPage.tsx";
import { RootLayout } from "./RootLayout.tsx";

export const registerHost: ModuleRegisterFunction<FireflyRuntime> = runtime => {
runtime.registerRoute({
// Pathless route to declare a root layout.
element: <RootLayout />,
children: [
// Placeholder to indicate where managed routes (routes that are not hoisted or nested)
// will be rendered.
ManagedRoutes
]
}, {
hoist: true
});

runtime.registerRoute({
path: "*",
element: <NotFoundPage />
}, {
hoist: true
});

runtime.registerRoute({
index: true,
element: <HomePage />
});
};
```
## Configure webpack
!!!info
Expand Down Expand Up @@ -334,13 +370,20 @@ export const swcConfig = defineDevConfig(targets);
Then, open the `webpack.dev.js` file and use the [defineDevHostConfig](/reference/webpack/defineDevHostConfig.md) function to configure webpack:
```js !#6-13 host/webpack.dev.js
```js !#13-20 host/webpack.dev.js
// @ts-check

import { defineDevHostConfig } from "@squide/firefly-configs";
import { defineDevHostConfig } from "@squide/firefly-webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevHostConfig(swcConfig, "host", 8080, {
/**
* @typedef {import("@squide/firefly-webpack-configs").RemoteDefinition}[]
*/
const Remotes: RemoteDefinition[] = [
{ name: "remote1", url: "http://localhost:8081" }
];

export default defineDevHostConfig(swcConfig, "host", 8080, Remotes, {
sharedDependencies: {
"@sample/shared": {
singleton: true,
Expand Down Expand Up @@ -368,13 +411,20 @@ export const swcConfig = defineBuildConfig(targets);
Then, open the `webpack.build.js` file and use the [defineBuildHostConfig](/reference/webpack/defineBuildHostConfig.md) function to configure webpack:
```js !#6-13 host/webpack.build.js
```js !#13-20 host/webpack.build.js
// @ts-check

import { defineBuildHostConfig } from "@squide/firefly-configs";
import { defineBuildHostConfig } from "@squide/firefly-webpack-configs";
import { swcConfig } from "./swc.build.js";

export default defineBuildHostConfig(swcConfig, "host", {
/**
* @typedef {import("@squide/firefly-webpack-configs").RemoteDefinition}[]
*/
const Remotes = [
{ name: "remote1", url: "http://localhost:8081" }
];

export default defineBuildHostConfig(swcConfig, "host", Remotes, {
sharedDependencies: {
"@sample/shared": {
singleton: true,
Expand Down
Loading

0 comments on commit 89ace29

Please sign in to comment.