msw: MSW does not mock APIS in react-router-6 loader in the first load
Prerequisites
- I confirm my issue is not in the opened issues
- I confirm the Frequently Asked Questions didn’t contain the answer to my issue
Environment check
- I’m using the latest
msw
version - I’m using Node.js version 14 or higher
Browsers
Chromium (Chrome, Brave, etc.)
Reproduction repository
https://github.com/abhaykumar01234/hacker-news
Reproduction steps
npm run dev:mock
Current behavior
I am running a vite application, using react-router-dom:v6 and msw:latest.
I have 2 pages
import { createBrowserRouter, RouterProvider } from "react-router-dom";
const router = createBrowserRouter([
{
path: "/",
element: <App />,
loader: appLoader,
},
{
path: "/about",
element: <About />,
loader: aboutLoader,
},
]);
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
if (import.meta.env.VITE_MSW_MOCKED === "1") {
const { worker } = await import("~/mocks/browser");
await worker.start({ onUnhandledRequest: "bypass" });
}
root.render(<RouterProvider router={router} />);
Each page having code
import { Link, json, useLoaderData } from "react-router-dom";
export const loader = async () => {
try {
const res = await fetch(`${import.meta.env.VITE_BASE_URL}/global`);
return json(await res.json());
} catch (err) {
console.error(err);
return null;
}
};
export default function Layout() {
const data = useLoaderData();
console.log("home", data);
return (
<div>
<h1>Home</h1>
<Link to="/about">About</Link>
</div>
);
}
and one link to the other page.
When the page loads for the first time, Mocks are enabled but the API endpoint fails. When the links are clicked to navigate back and forth the pages, the mock works the next time
Expected behavior
Mocks should work the first time for loader APIs
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 6
- Comments: 23 (1 by maintainers)
If you can use ES2022 (with top-level await) you can simply do the following:
This would be the easiest setup. If you, however, do not include the msw- and the react-router related code in the same module (file), you need to be a bit more careful due to the nature of how ESM imports work. Let’s assume you have the following two files:
Now we need to know one thing about the execution order of this code. The ESM imports are evaluated first! This means the order of execution is the following (roughly speaking):
This is why you need to call createBrowserRouter from within the App component (make sure to memoize it!) if you want to follow this file structure. For this you can do it for example as @lucider5 has suggested above: https://github.com/mswjs/msw/issues/1653#issuecomment-1776867147. Hope this helps! I think this could be better documented in the react-router documentation but I don’t see any issues on the msw side. I think we can close this issue.
As @marcomuser stated. Here is the solution
This works for me:
Dynamic import is not necessary. Try this way, and it works.
Just make sure that you create the browser router after resolving the
worker.start()
.That is, put the
createBrowserRouter
after the async functionenableMocking()
like so:React query hits the API after the mounting of the page and uses
useEffect
underneath. Correct me if I am wrong. Also, I am looking for a solution to work with plain react-router-dom. loader calls. I know I may sound vanilla here, not using any packages, but shouldn’t it work like that? @wangel13@wangel13 Doesn’t work for me
For some reason, react-router-6 loaders are invoked before the handlers are mocked in msw.
Did you try it with loaders in your react page making API calls?
In my case exporting the worker.start() from another file worked for me:

Any news?
Any updates??