正在加载完整 README。 以下为已保存的摘录。
A TanStack DevTools plugin for managing MSW (Mock Service Worker) mocks in the browser. Register your existing MSW handlers, then toggle, customize, and inspect them from a visual panel -- no changes to your handler code required.
Note: This project is a work in progress -- the API has not been finalised yet, which is why we haven't reached 1.0.0. Expect breaking changes between minor versions.查看完整 README ↗A TanStack DevTools plugin for managing MSW (Mock Service Worker) mocks in the browser. Register your existing MSW handlers, then toggle, customize, and inspect them from a visual panel -- no changes to your handler code required.
Note: This project is a work in progress -- the API has not been finalised yet, which is why we haven't reached 1.0.0. Expect breaking changes between minor versions.
useMockRefetch instead)Everything ships in a single package. Adapters are available via subpath exports and are tree-shakeable.
| Import path | Description |
|---|---|
@mugenlabs/msw-devtools | Registry, store, MSW integration, React UI plugin, adapter system |
@mugenlabs/msw-devtools/types | Type-only entry point (no runtime code) |
@mugenlabs/msw-devtools/adapters/tanstack-query | Auto-refetch via query invalidation |
@mugenlabs/msw-devtools/adapters/urql | Auto-refetch via custom exchange |
@mugenlabs/msw-devtools/adapters/swr | Auto-refetch via global mutate |
@mugenlabs/msw-devtools/adapters/apollo | Auto-refetch via refetchQueries |
@mugenlabs/msw-devtools/adapters/rtk-query | Auto-refetch via resetApiState |
@mugenlabs/msw-devtools/adapters/axios | Registration marker for Axios users (use useMockRefetch for live updates) |
npm install @mugenlabs/msw-devtools
The package is ESM-only and runs in the browser: MSW needs Service Worker support, so serve the app over HTTPS or from localhost. It is safe to import during server rendering (SSR): registering mocks there only records them, and the worker starts in the browser when the plugin mounts.
| Dependency | Version | Required |
|---|---|---|
msw | ^2.0.0 | Yes |
react | ^18.0.0 || ^19.0.0 | Yes |
@tanstack/react-devtools | ^0.9.0 | Optional — only needed to host the panel |
@tanstack/react-query | ^5.0.0 | Only if using TanStack Query adapter |
@urql/core + wonka | ^5.0.0 || ^6.0.0 / ^6.3.2 | Only if using URQL adapter |
The Apollo (Client 3 or 4), SWR (2.x) and RTK Query adapters only call the client you pass in, so those libraries are not peer dependencies.
This guide assumes you already have MSW installed and mockServiceWorker.js generated in your public directory.
Use registerRestMocks and registerGraphqlMocks to register your existing MSW handlers with the devtools. Operation metadata (method, path, operation name) is automatically derived from handler info.
// mocks/setup.ts
import { registerRestMocks, registerGraphqlMocks } from "@mugenlabs/msw-devtools";
import { http, HttpResponse, graphql } from "msw";
// REST -- pass your HttpHandler directly
registerRestMocks(
{ handler: http.get("/api/users", () => HttpResponse.json({ users: [] })) },
{ handler: http.get("/api/posts", () => HttpResponse.json({ posts: [] })), group: "Blog" },
);
// GraphQL -- with multiple variants
registerGraphqlMocks({
group: "Users",
variants: [
graphql.query("GetUser", () =>
HttpResponse.json({ data: { user: { id: 1, name: "John" } } })
),
{
handler: graphql.query("GetUser", () =>
HttpResponse.json({ data: { user: null } })
),
label: "Not Found",
},
],
});
// App.tsx
import { TanStackDevtools } from "@tanstack/react-devtools";
import { createMswDevToolsPlugin } from "@mugenlabs/msw-devtools";
import "./mocks/setup";
function App() {
return (
<>
<YourApp />
<TanStackDevtools plugins={[createMswDevToolsPlugin()]} />
</>
);
}
The MSW service worker starts automatically when the plugin mounts.
Custom worker options: If you need to customise the worker (e.g. a different
serviceWorkerUrl), callstartWorker()before the plugin mounts. The plugin detects an already-running worker and skips auto-start. Options passed after the worker has started are ignored, and a console warning says so.import { startWorker } from "@mugenlabs/msw-devtools"; void startWorker({ serviceWorkerUrl: "/custom-path/mockServiceWorker.js" });
The plugin bundles MSW and your mock data, and it starts a service worker that intercepts requests. Load it only in development, for example with a dynamic import so production bundles never include it:
// main.tsx (Vite)
if (import.meta.env.DEV) {
await import("./mocks/setup");
}
Render <TanStackDevtools> behind the same check, and leave mockServiceWorker.js out of production deploys unless you mean to mock there.
Adapters automatically refetch/revalidate queries when you change mock configuration in the devtools panel.
TanStack Query:
import { registerAdapter } from "@mugenlabs/msw-devtools";
import { createTanStackQueryAdapter } from "@mugenlabs/msw-devtools/adapters/tanstack-query";
import { QueryClient } from "@tanstack/react-query";
const queryClient = new QueryClient();
registerAdapter(createTanStackQueryAdapter(queryClient));
URQL:
import { registerAdapter } from "@mugenlabs/msw-devtools";
import { createUrqlAdapter, mockRefetchExchange } from "@mugenlabs/msw-devtools/adapters/urql";
import { createClient, cacheExchange, fetchExchange } from "@urql/core";
registerAdapter(createUrqlAdapter());
const client = createClient({
url: "/graphql",
exchanges: [cacheExchange, mockRefetchExchange, fetchExchange],
});
SWR:
import { useEffect } from "react";
import { registerAdapter } from "@mugenlabs/msw-devtools";
import { createSwrAdapter } from "@mugenlabs/msw-devtools/adapters/swr";
import { useSWRConfig } from "swr";
function SetupAdapter() {
const { mutate } = useSWRConfig();
useEffect(() => {
const unregister = registerAdapter(createSwrAdapter(mutate));
return unregister;
}, [mutate]);
return null;
}
Apollo Client:
import { registerAdapter } from "@mugenlabs/msw-devtools";
import { createApolloAdapter } from "@mugenlabs/msw-devtools/adapters/apollo";
const apolloClient = new ApolloClient({ uri: "/graphql", cache: new InMemoryCache() });
registerAdapter(createApolloAdapter(apolloClient));
RTK Query:
import { registerAdapter } from "@mugenlabs/msw-devtools";
import { createRtkQueryAdapter } from "@mugenlabs/msw-devtools/adapters/rtk-query";
import { store } from "./store";
import { pokemonApi } from "./pokemon-api";
registerAdapter(createRtkQueryAdapter(store, pokemonApi));
RTK Query has no "refetch everything" action, so the adapter dispatches api.util.resetApiState(). That clears the whole API slice, including cached data and mutation results, and every mounted query refetches.
Axios / plain fetch:
Axios has no built-in query cache. Register the adapter as a marker and use useMockRefetch in your components:
import { registerAdapter } from "@mugenlabs/msw-devtools";
import { createAxiosAdapter } from "@mugenlabs/msw-devtools/adapters/axios";
registerAdapter(createAxiosAdapter());
Registration returns type-safe operation handles. Destructure them and pass a handle to useMockRefetch instead of hard-coding operation-name strings (typos silently no-op):
import { registerRestMocks, useMockRefetch } from "@mugenlabs/msw-devtools";
const [users] = registerRestMocks({ handler: http.get("/api/users", resolver) });
function UserCard() {
const { data, refetch } = useMyFetch("/api/users/1");
useMockRefetch(users, refetch); // typo-proof — raw strings like "GET /api/users" also still work
// With explicit operationNames, handles["GET Users"] is typed and handles["typo"] fails to compile
return <div>{data?.name}</div>;
}
Tip: If you're starting a new project, consider using a server-state library like TanStack Query, SWR, or Apollo Client instead of plain
fetch()or Axios. These libraries provide built-in caching, deduplication, and automatic refetching, and their adapters integrate seamlessly with@mugenlabs/msw-devtoolswithout needing per-operationuseMockRefetchcalls.
The operation name is derived from the handler info (e.g. GET /api/users):
registerRestMocks({ handler: http.get("/api/users", resolver) });
https://a.com/users and https://b.com/users would both be GET /users. A console warning flags names that clash; pass operationName to tell them apart.http.all() handlers are named ALL /path and match every method. graphql.operation() handlers match queries and mutations; give them an operationName./^GetUser/.registerRestMocks({
handler: http.get("https://api.example.com/users", resolver),
operationName: "GET Users",
group: "User Management",
});
Provide an array of variants instead of a single handler. Each variant is either a bare handler or { handler, label }:
registerGraphqlMocks({
group: "Users",
variants: [
graphql.query("GetUser", successResolver), // label: "Default"
{ handler: graphql.query("GetUser", emptyResolver), label: "Empty" },
{ handler: graphql.query("GetUser", errorResolver), label: "Error" },
],
});
@mugenlabs/msw-devtools)| Export | Description |
|---|---|
registerRestMocks(...defs) | Register REST mock handlers. Metadata is auto-derived from HttpHandler info. Returns OperationHandlesFor<typeof defs>. |
registerGraphqlMocks(...defs) | Register GraphQL mock handlers. Metadata is auto-derived from GraphQLHandler info. Returns OperationHandlesFor<typeof defs>. |
registerAdapter(adapter) | Register a data-fetching adapter for auto-refetch. Returns an unregister function. |
createMswDevToolsPlugin(options?) | Create the TanStack DevTools plugin config object. |
useMockRefetch(operation, refetch) | React hook that auto-refetches when mock config changes for a specific operation. Accepts an OperationHandle (recommended) or a raw operation-name string. |
startWorker(options?) | Manually start the MSW service worker. |
stopWorker() | Stop the worker and detach the devtools from it. Registered mocks and persisted config are kept. |
getWorker() | Get the current MSW SetupWorker instance (or null). |
mockRegistry | Singleton registry instance (subscribe, get, unregister). |
useMockStore | Zustand store hook for mock operation state. |
mockStore | Direct Zustand store reference (non-hook). |
| Import path | Export | Description |
|---|---|---|
@mugenlabs/msw-devtools/adapters/tanstack-query | createTanStackQueryAdapter(queryClient) | TanStack Query adapter |
@mugenlabs/msw-devtools/adapters/urql | createUrqlAdapter() | URQL adapter |
@mugenlabs/msw-devtools/adapters/urql | mockRefetchExchange | URQL exchange for mock-triggered re-execution |
@mugenlabs/msw-devtools/adapters/swr | createSwrAdapter(mutate) | SWR adapter |
@mugenlabs/msw-devtools/adapters/apollo | createApolloAdapter(apolloClient) | Apollo Client adapter |
@mugenlabs/msw-devtools/adapters/apollo | ApolloClientLike | Structural type for the subset of ApolloClient the adapter needs |
@mugenlabs/msw-devtools/adapters/rtk-query | createRtkQueryAdapter(store, api) | RTK Query adapter (resets the API state) |
@mugenlabs/msw-devtools/adapters/axios | createAxiosAdapter() | Axios adapter (use with useMockRefetch) |
| Type | Description |
|---|---|
RestMockDef | Input for registerRestMocks -- { handler?, variants?, operationName?, group? } |
GraphqlMockDef | Input for registerGraphqlMocks -- { handler?, variants?, operationName?, operationType?, group? } |
OperationHandle | Type-safe reference to a registered operation -- { operationName }. Pass to useMockRefetch. |
OperationHandlesFor<Defs> | Return type of the register functions: a tuple of OperationHandles also indexable by operationName. Keys are literal when every def has an explicit operationName, so handles["typo"] is a type error. |
OperationHandles | The untyped form: OperationHandle[] indexable by any string. |
HandlerVariant | A resolved variant stored in the registry -- { handler, id, label, options? } |
HandlerVariantInput<H> | What you pass as a variant: a bare handler or { handler, label } |
RestMockDescriptor | Internal descriptor for a registered REST operation -- { type: "rest", method, path: string | RegExp, operationName, group?, variants } |
GraphQLMockDescriptor | Internal descriptor for a registered GraphQL operation -- { type: "graphql", operationName, graphqlOperationName, operationType, endpoint, group?, variants }. graphqlOperationName is what the handler matches on; operationName is the display name |
MockOperationDescriptor | Union of RestMockDescriptor and GraphQLMockDescriptor |
OperationMockConfig | Per-operation runtime state (enabled, active variant, overrides) |
MswDevToolAdapter | Interface for creating custom adapters |
MockChangeType | "toggle" | "variant" | "json-override" | "status-override" | "headers-override" | "delay-override" | "error-override" | "enable-all" | "disable-all" |
Full documentation and live playground: https://msw-devtools.mugenlabs.dev/
The changelog lists every change. The ones that can need action:
zustand, react-dom, swr, graphql and @apollo/client are no longer peer dependencies. zustand is now a regular dependency, so you can remove it from your app if nothing else uses it. Node 20 or later is required for tooling that loads the package.http.all() handlers are named ALL /path and graphql.operation() handlers get the "operation" type. RestMethod gains "head" | "options" | "all" and GraphQLOperationType gains "operation", so exhaustive switch statements over them need the new cases.UnknownOperation, so their saved settings reset once.operationName set to ALL_OPERATIONS ("*"). Custom adapters that filter by name should use affectsOperation(event, name).registerRestMocks / registerGraphqlMocks return OperationHandlesFor<Defs>. With explicit operationNames, handles["typo"] is now a type error.@apollo/client ^3.0.0 || ^4.0.0), and @tanstack/react-devtools is an optional peer at ^0.9.0.Requires Node 24 LTS (see .nvmrc) and pnpm >=10.
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run the demo app
pnpm dev:demo
# Type checking (builds first, then checks packages/core and apps/demo)
pnpm typecheck
# Unit tests
pnpm test:ci
# Storybook interaction tests
pnpm test-storybook
# Lint and format
pnpm lint:fix
# E2E tests (Playwright)
pnpm test:e2e
This README is also the npm README: pnpm readme:sync copies it to packages/core/README.md, without this section. See CONTRIBUTING.md for the full workflow, including the Changesets release process.
msw-devtools/
api/ # Edge function for the demo site's API error responses
apps/
demo/ # Demo application & documentation site
packages/
core/ # Core library (registry, store, MSW integration, UI plugin, adapters)
e2e/ # Playwright E2E tests
scripts/ # Utility scripts (e.g. OG image generation)
MIT
ALL_OPERATIONS | Sentinel operationName ("*") carried by bulk enable-all / disable-all events. Use affectsOperation(event, name) in custom adapters to match it. |
WorkerOptions | Configuration for startWorker() |
MswDevToolsPluginOptions | Configuration for createMswDevToolsPlugin() |