Skip to content

Commit

Permalink
docs: Added a guide to setup MSW (#111)
Browse files Browse the repository at this point in the history
* Added the guide

* Updated snapshot tests
  • Loading branch information
patricklafrance authored Nov 9, 2023
1 parent 5c8bc11 commit ae3a3f7
Show file tree
Hide file tree
Showing 16 changed files with 363 additions and 64 deletions.
6 changes: 3 additions & 3 deletions docs/getting-started/learn-the-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ We recommend to mock the API endpoints with [Mock Service Worker](https://mswjs.

To help with that, a `@squide/msw` package is available.

First, install the plugin, then [register the plugin](../reference/msw/MswPlugin.md#register-the-msw-plugin) at bootstrap:
First, install the `@squide/msw`, then [register the plugin](../reference/msw/MswPlugin.md#register-the-msw-plugin) at bootstrap:

```ts host/src/boostrap.tsx
import { Runtime } from "@squide/react-router";
Expand Down Expand Up @@ -197,8 +197,8 @@ export const register: ModuleRegisterFunction<Runtime> = async runtime => {
if (process.env.USE_MSW) {
const mswPlugin = getMswPlugin(runtime);

// Files including an import to the "msw" package are included dynamically to prevent adding
// MSW stuff to the bundled when it's not used.
// Files that includes an import to the "msw" package are included dynamically to prevent adding
// unused MSW stuff to the code bundles.
const requestHandlers = (await import("../mocks/handlers.ts")).requestHandlers;

mswPlugin.registerRequestHandlers(requestHandlers);
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/add-a-shared-dependency.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
order: 10
order: 0
label: Add a shared dependency
---

Expand Down
22 changes: 22 additions & 0 deletions docs/guides/develop-a-module-in-isolation.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ Now, let's revisit the host application by first adding a dependency to the new
}
```

!!!warning
Don't forget to add the `peerDependencies` of `@sample/shell`.
!!!

Then, incorporate the newly introduced `AppRouter` component:

```tsx host/src/App.tsx
Expand Down Expand Up @@ -166,6 +170,10 @@ To begin, let's start by adding a dependency to the `@sample/shell` package:
}
```

!!!warning
Don't forget to add the `peerDependencies` of `@sample/shell`.
!!!

Then, create the following files in the remote module application:

``` !#2-3,5-7,10-11
Expand Down Expand Up @@ -345,6 +353,20 @@ npm install -D @workleap/webpack-configs @workleap/swc-configs @workleap/browser
While you can use any package manager to develop an application with Squide, it is highly recommended that you use [PNPM](https://pnpm.io/) as the guides has been developed and tested with PNPM.
!!!

Then, install add a dependency to the `@sample/shell` package:

```json local-module/package.json
{
"dependencies": {
"@sample/shell": "0.0.1"
}
}
```

!!!warning
Don't forget to add the `peerDependencies` of `@sample/shell`.
!!!

Then, create the following files in the local module application:

``` !#2-3,5-7,10-11
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/implement-a-custom-logger.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
order: 20
order: 10
---

# Implement a custom logger
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/migrating-from-a-monolith.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
order: 0
order: -10
label: Migrating from a monolith
---

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/override-a-react-context.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
order: 30
order: 20
label: Override a React context
---

Expand Down
154 changes: 154 additions & 0 deletions docs/guides/setup-msw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
order: 30
label: Setup Mock Service Worker
---

# Setup Mock Service Worker

[Mock Service Worker](https://mswjs.io/) (MSW) is a great tool to fake API endpoints. It has the advantage of working directly in the browser, which means that unlike alternative solutions, it doesn't require running an additional process to host the fake API endpoints.

## Add an environment variable

First, let's update the PNPM script to define with [cross-env](https://www.npmjs.com/package/cross-env) a `USE_MSW` environment variable that will conditionally enable MSW:

```json package.json
{
"scripts": {
"dev": "cross-env USE_MSW=true webpack serve --config webpack.dev.js"
}
}
```

Then, forward the `USE_MSW` environment variable to the application code bundles:

```js !#7 webpack.dev.js
// @ts-check

import { defineDevHostConfig } from "@squide/webpack-module-federation";

export default defineDevHostConfig(swcConfig, "host", 8080, {
environmentVariables: {
"USE_MSW": process.env.USE_MSW === "true"
}
});
```

> For more information about the `environmentVariables` predefined option, refer to the [webpack configuration documentation](https://gsoft-inc.github.io/wl-web-configs/webpack/configure-dev/#define-environment-variables).
!!!warning
Don't forget to define the `USE_MSW` environment variable for the build script as well (the one using `defineBuildHostConfig`).
!!!

The `USE_MSW` environment variable will prevent including MSW related code into the application code bundles when MSW is disabled.

## Register the plugin and start MSW

Then, update the host application bootstrapping code to [registrer the MSW plugin](../reference/msw/mswPlugin.md#register-the-msw-plugin) and start MSW once all the request handlers has been registered:

```tsx !#15,22-32 host/src/bootstrap.tsx
import { createRoot } from "react-dom/client";
import { ConsoleLogger, RuntimeContext, Runtime } from "@squide/react-router";
import { registerRemoteModules, type RemoteDefinition } from "@squide/webpack-module-federation";
import { MswPlugin } from "@squide/msw";
import { App } from "./App.tsx";
import { registerHost } from "./register.tsx";

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

const runtime = new Runtime({
loggers: [new ConsoleLogger()],
// Register MSW plugin to the application runtime.
plugins: [new MswPlugin()]
});

await registerLocalModules([registerHost], runtime);

await registerRemoteModules(Remotes, runtime);

if (process.env.USE_MSW) {
// Files that includes an import to the "msw" package are included dynamically to prevent adding
// unused MSW stuff to the code bundles.
const startMsw = (await import("../mocks/browser.ts")).startMsw;

// Will start MSW with the request handlers provided by every module.
startMsw(mswPlugin.requestHandlers);

// Indicate to resources that are dependent on MSW that the service has been started.
setMswAsStarted();
}

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

root.render(
<RuntimeContext.Provider value={runtime}>
<App />
</RuntimeContext.Provider>
);
```

## Delay the routes rendering until MSW is started

Then, update the host application code to delay the rendering of the application routes until MSW is started. This is done by activating the `waitForMsw` property of the [AppRouter](../reference/routing/appRouter.md) component:

```tsx !#8 host/src/App.tsx
import { AppRouter } from "@squide/firefly";

export function App() {
return (
<AppRouter
fallbackElement={<div>Loading...</div>}
errorElement={<div>An error occured!</div>}
waitForMsw={process.env.USE_MSW}
/>
);
}
```

## Register request handlers

Next, define an MSW request handler in a remote module (or local module):

```ts
import { HttpResponse, http, type HttpHandler } from "msw";

export const requestHandlers: HttpHandler[] = [
http.get("/api/character/1", async () => {
return HttpResponse.json([{
"id": 1,
"name": "Rick Sanchez",
"status": "Alive"
}]);
})
];
```

Then, register the request handler with the shared registry:

```ts !#5,10,12 remote-module/src/register.tsx
import { getMswPlugin } from "@squide/msw";
import type { ModuleRegisterFunction, Runtime } from "@squide/react-router";

export const register: ModuleRegisterFunction<Runtime> = async runtime => {
if (process.env.USE_MSW) {
const mswPlugin = getMswPlugin(runtime);

// Files that includes an import to the "msw" package are included dynamically to prevent adding
// unused MSW stuff to the code bundles.
const requestHandlers = (await import("../mocks/handlers.ts")).requestHandlers;

mswPlugin.registerRequestHandlers(requestHandlers);
}
}
```

!!!info
Don't forget to mark the registration function as `async` since there's a dynamic import.
!!!

## Try it :rocket:

Update a page component code to fetch the `/api/character/1` fake API endpoint, then start the application in development mode using the `dev` script. You should notice that the data has been fetched from the MSW request handler.

> In Chrome devtools, the status code for a successful network call to an MSW request handler will be `200 OK (from service worker)`.
12 changes: 6 additions & 6 deletions docs/reference/msw/MswPlugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ None

## Usage

!!! warning
Don't forget to [activate the msw feature](../webpack/defineDevHostConfig.md#activate-optional-features) on the host application as well as every remote module.
!!!

Do not include MSW in production code. To address this, we recommend conditionally importing the code that includes the [msw](https://www.npmjs.com/package/msw) package based on an environment variable.

To do so, first use [cross-env](https://www.npmjs.com/package/cross-env) to define a `USE_MSW` environment variable in a PNPM script:
Expand Down Expand Up @@ -54,6 +50,10 @@ export default defineDevHostConfig(swcConfig, "host", 8080, {

> For more information about the `environmentVariables` predefined option, refer to the [webpack configuration documentation](https://gsoft-inc.github.io/wl-web-configs/webpack/configure-dev/#define-environment-variables).
!!!warning
Don't forget to define the `USE_MSW` environment variable for the build script as well (the one using `defineBuildHostConfig`).
!!!

Finally, use the `USE_MSW` environment variable to conditionally import any files that includes the [msw](https://www.npmjs.com/package/msw) package:

```ts mocks/handlers.ts
Expand Down Expand Up @@ -98,8 +98,8 @@ import { getMswPlugin } from "@squide/msw";
if (process.env.USE_MSW) {
const mswPlugin = getMswPlugin(runtime);

// Files including an import to the "msw" package are included dynamically to prevent adding
// MSW stuff to the bundled when it's not used.
// Files that includes an import to the "msw" package are included dynamically to prevent adding
// unused MSW stuff to the code bundles.
const requestHandlers = (await import("./mocks/handlers.ts")).requestHandlers;

mswPlugin.registerRequestHandlers(requestHandlers);
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/routing/appRouter.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ export function App() {

### Complete deferred registrations

For more information about deferred registrations, refer to the [registerRemoteModules](../registration/registerRemoteModules.md#defer-the-registration-of-routes-or-navigation-items) and [completeModuleRegistrations](../registration/completeModuleRegistrations.md) documentation.

```tsx !#28-30,39 host/src/App.tsx
import { useState, useCallback } from "react";
import { AppRouter } from "@squide/firefly";
Expand Down
30 changes: 18 additions & 12 deletions docs/reference/webpack/defineBuildHostConfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ toc:

Creates a webpack [configuration object](https://webpack.js.org/concepts/configuration/) that is adapted for a Squide host application in **build** mode.

!!!warning
This function is a wrapper built on top of [@workleap/web-configs](https://www.npmjs.com/package/@workleap/webpack-configs). Make sure to read the [defineBuildConfig](https://gsoft-inc.github.io/wl-web-configs/webpack/configure-build/) documentation first.
!!!

## Reference

```ts
Expand All @@ -23,7 +27,7 @@ const webpackConfig = defineBuildHostConfig(swcConfig: {}, applicationName, opti
- `htmlWebpackPluginOptions`: An optional object literal accepting any property of the [HtmlWebpackPlugin](https://github.com/jantimon/html-webpack-plugin#options).
- `features`: An optional object literal of feature switches to define additional shared dependencies.
- `router`: Currently hardcoded to `"react-router"` as it's the only supported router (`@squide/react-router` and `@react-router-dom` are currently considered as default shared dependencies).
- `msw`: Whether or not to add `@squide/msw` as a shared dependency.
- `msw`: Whether or not to add `@squide/msw` as a shared dependency (`@squide/msw` is currently considered as a default shared dependency).
- `sharedDependencies`: An optional object literal of additional (or updated) module federation shared dependencies.
- `moduleFederationPluginOptions`: An optional object literal of [ModuleFederationPlugin](https://webpack.js.org/plugins/module-federation-plugin/) options.

Expand All @@ -40,13 +44,15 @@ The `defineBuildHostConfig` function will add the following shared dependencies
- [@squide/core](https://www.npmjs.com/package/@squide/core)
- [@squide/react-router](https://www.npmjs.com/package/@squide/react-router)
- [@squide/webpack-module-federation](https://www.npmjs.com/package/@squide/webpack-module-federation)
- [@squide/msw](https://www.npmjs.com/package/@squide/msw)

For the full shared dependencies configuration, have a look at the [defineConfig.ts](https://github.com/gsoft-inc/wl-squide/blob/main/packages/webpack-module-federation/src/defineConfig.ts) file on GitHub.

## Optional shared dependencies

The following shared dependencies can be added through feature switches:
- [`@squide/msw`](https://www.npmjs.com/package/@squide/msw)
The following shared dependencies can be removed through [feature switches](#deactivate-optional-features):

- [@squide/msw](https://www.npmjs.com/package/@squide/msw)

## Usage

Expand All @@ -61,11 +67,7 @@ import { swcConfig } from "./swc.build.js";
export default defineBuildHostConfig(swcConfig, "host", "http://localhost:8080/");
```

### Activate additional features

!!!info
Features must be activated on the host application as well as every remote module.
!!!
### Deactivate optional features

```js !#7-9 host/webpack.build.js
// @ts-check
Expand All @@ -75,17 +77,17 @@ import { swcConfig } from "./swc.build.js";

export default defineBuildHostConfig(swcConfig, "host", {
features: {
msw: true
msw: false
}
});
```

### Specify additional shared dependencies

!!!info
Additional shared dependencies must be configured on the host application as well as every remote module.
Features must be deactivated on the host application as well as every remote module.
!!!

### Specify additional shared dependencies

```js !#7-11 host/webpack.build.js
// @ts-check

Expand All @@ -101,6 +103,10 @@ export default defineBuildHostConfig(swcConfig, "host", {
});
```

!!!info
Additional shared dependencies must be configured on the host application as well as every remote module.
!!!

### Extend a default shared dependency

```js !#7-11 host/webpack.build.js
Expand Down
Loading

0 comments on commit ae3a3f7

Please sign in to comment.