#
Setup Mock Service Worker
To speed up frontend development and encourage an API first approach, Squide has built-in support for Mock Service Worker (MSW). MSW offers an API to host fake endpoints directly in the browser. This means that unlike alternative solutions, it doesn't require running an additional process to host fake endpoints.
#
Setup the host application
First, open a terminal at the root of the host application and install the msw package:
pnpm add -D cross-env
pnpm add msw
yarn add -D cross-env
yarn add msw
npm install -D cross-env
npm install msw
Then initialize MSW by executing the following command:
pnpm dlx msw init ./public
yarn dlx msw init ./public
npx msw init ./public
While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM.
#
Add an environment variable
Then, update the dev
PNPM script to define with cross-env an USE_MSW
environment variable that will conditionally include MSW code into the application bundles:
{
"scripts": {
"dev": "cross-env USE_MSW=true webpack serve --config webpack.dev.js"
}
}
Then, update the development webpack configuration file to include the USE_MSW
environment variable into the application bundles:
// @ts-check
import { defineDevHostConfig } from "@squide/firefly-webpack-configs";
/**
* @typedef {import("@squide/firefly-webpack-configs").RemoteDefinition[]}
*/
const Remotes = [
{ name: "remote1", url: "http://localhost:8081" }
];
export default defineDevHostConfig(swcConfig, 8080, Remotes, {
environmentVariables: {
"USE_MSW": process.env.USE_MSW === "true"
}
});
For more information about the
environmentVariables
predefined option, refer to the webpack configuration documentation.
Don't forget to define the USE_MSW
environment variable for the build script and build webpack configuration as well.
#
Start the service
With the newly added USE_MSW
environment variable, the host application bootstrapping code can now be updated to conditionally start MSW when all the request handlers has been registered.
First, define a function to start MSW:
import type { RequestHandler } from "msw";
import { setupWorker } from "msw/browser";
export function startMsw(moduleRequestHandlers: RequestHandler[]) {
const worker = setupWorker(...moduleRequestHandlers);
return worker.start();
}
Then, update the bootstrapping code to start the service and mark MSW as started if MSW is enabled:
import { createRoot } from "react-dom/client";
import { ConsoleLogger, RuntimeContext, FireflyRuntime, registerRemoteModules, type RemoteDefinition } from "@squide/firefly";
import { App } from "./App.tsx";
import { registerHost } from "./register.tsx";
const Remotes: RemoteDefinition[] = [
{ name: "remote1" }
];
const runtime = new FireflyRuntime({
useMsw: !!process.env.USE_MSW,
loggers: [new ConsoleLogger()]
});
await registerLocalModules([registerHost], runtime);
await registerRemoteModules(Remotes, runtime);
// Once both register functions are done, we can safely assume that all the request handlers has been registered.
if (runtime.isMswEnabled) {
// Files that includes an import to the "msw" package are included dynamically to prevent adding
// unused MSW stuff to the application bundles.
const startMsw = (await import("../mocks/browser.ts")).startMsw;
// Will start MSW with the modules request handlers.
startMsw(runtime.requestHandlers).then(() => {
// Indicate that MSW has been started and the routes can now be safely rendered.
setMswAsStarted();
});
}
const root = createRoot(document.getElementById("root")!);
root.render(
<RuntimeContext.Provider value={runtime}>
<App />
</RuntimeContext.Provider>
);
#
Delay routes rendering until the service is started
Finally, update the host application code to delay the rendering of the routes until MSW is started. This is done by setting the waitForMsw
property of the AppRouter component to true
:
import { AppRouter } from "@squide/firefly";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
export function App() {
return (
<AppRouter
fallbackElement={<div>Loading...</div>}
errorElement={<div>An error occured!</div>}
waitForMsw={!!process.env.USE_MSW}
>
{(routes, providerProps) => (
<RouterProvider router={createBrowserRouter(routes)} {...providerProps} />
)}
</AppRouter>
);
}
#
Setup a remote module
First, open a terminal at the root of the remote module application and install the msw package:
pnpm add msw
yarn add msw
npm install msw
Then, define a request handler:
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"
}]);
})
];
Finally, register the request handler with the FireflyRuntime instance:
import type { ModuleRegisterFunction, FireflyRuntime } from "@squide/firefly";
export const register: ModuleRegisterFunction<FireflyRuntime> = async runtime => {
if (runtime.isMswEnabled) {
// Files that includes an import to the "msw" package are included dynamically to prevent adding
// unused MSW stuff to the application bundles.
const requestHandlers = (await import("../mocks/handlers.ts")).requestHandlers;
runtime.registerRequestHandlers(requestHandlers);
}
}
Don't forget to mark the registration function as async
since there's a dynamic import.
#
Setup a local module
Follow the same steps as for a
#
Try it 🚀
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 request handler.
In Chrome devtools, the status code for a successful network call that has been handled by an MSW request handler will be
200 OK (from service worker)
.
#
Troubleshoot issues
If you are experiencing issues with this guide:
- Open the DevTools console. You'll find a log entry for each request handlers registration that occurs and error messages if something went wrong:
[squide] The following MSW request handlers has been registered: ...
- Refer to a working example on GitHub.
- Refer to the troubleshooting page.