Mokup: A Build-Tool-Friendly Visual Mocking Tool for Vite, Webpack, Node.js, and Workers
Source: Dev.to
What is Mokup
Mokup is a file‑based HTTP mocking tool.
You put mock files in a mock/ directory, and Mokup automatically scans them, builds matching routes, and returns responses.
Its goal is straightforward: help mocks run quickly inside your existing frontend project and reduce the cost of building a separate service just for API collaboration.
Key features
- Build‑tool friendly – works with both Vite and Webpack without forcing a project rewrite.
- Visual debugging – built‑in Playground shows route status at a glance.
- Great developer experience – mock file and config updates refresh automatically, without frequent restarts.
- Deployable to multiple environments – local dev, Node.js server, Workers, and Service Workers.
Why I built it
For many teams, the pain is not writing mocks; it’s the surrounding workflow:
- Too many setup steps and re‑configuration whenever the build tool changes.
- Poor visibility during local debugging – people end up guessing by reading files.
- Slow feedback loops when every mock change requires a restart or manual verification.
Mokup solves these three issues: lighter setup, stronger visualization, and faster feedback.
Build‑tool friendly
Vite integration
// vite.config.ts
import mokup from 'mokup/vite'
export default {
plugins: [
mokup({
entries: { dir: 'mock', prefix: '/api' },
}),
],
}
After adding files under mock/, Mokup scans them and generates routes automatically.
You can also open the Mokup Playground from your CLI output for visual debugging.
Webpack integration
// webpack.config.js
const { mokupWebpack } = require('mokup/webpack')
const withMokup = mokupWebpack({
entries: { dir: 'mock', prefix: '/api' },
})
module.exports = withMokup({})
This lets you add mock capability into your existing build pipeline without changing your business‑code structure.
Visualization: Playground
Mokup includes a built‑in Playground to inspect scanned routes, methods, paths, and config chains.
Default entry in Vite dev:
http://localhost:5173/__mokup
Online demo:
Why it matters – When an endpoint does not work, you don’t need to
grepeverywhere. Open the Playground page and instantly see whether the route was scanned, disabled, and which config matched.
Developer experience: hot‑reload support
In Vite dev, Mokup watches the mock directories and refreshes the route table automatically. Typical changes that trigger hot reload include:
- Add / modify / delete route files, e.g.
mock/users.get.tsmock/messages.get.jsonmock/orders/[id].patch.ts
- Modify directory config files –
mock/**/index.config.ts - Change directory structure – move, rename, or create nested folders
After a change, the Playground refreshes the route list automatically, making debugging much faster.
If you do not need file watching, set watch: false in entries.
Quick example: from file to response
// mock/users.get.ts
import { defineHandler } from 'mokup'
export default defineHandler({
handler: c => c.json([{ id: 1, name: 'Ada' }]),
})
Start dev and visit /api/users (assuming prefix: '/api'). You’ll receive the mock data.
Quick integration with @faker-js/faker
Mokup handlers are plain TS/JS functions, so you can integrate with @faker-js/faker directly, without any extra adapter layer.
// mock/users.get.ts
import { faker } from '@faker-js/faker'
import { defineHandler } from 'mokup'
export default defineHandler(c => {
const size = Number(c.req.query('size')) || 5
const users = Array.from({ length: size }).map(() => ({
id: faker.datatype.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
}))
return c.json(users)
})
Now a request to /api/users?size=10 returns a list of 10 randomly generated users.
Give Mokup a try!
- GitHub:
- Docs / Playground:
Happy mocking!
const size = Number(c.req.query('size') ?? 10)
const count = Number.isNaN(size) ? 10 : Math.min(Math.max(size, 1), 50)
const list = Array.from({ length: count }, () => ({
id: faker.string.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
city: faker.location.city(),
createdAt: faker.date.recent({ days: 30 }).toISOString(),
}))
return c.json({
list,
total: 200,
page: 1,
pageSize: count,
})
This is very useful for list, search, and detail page integration.
If you need reproducible results, add faker.seed(123) at the top of the handler.
Deployable to multiple environments
Node.js dev mode example
import { createFetchServer, serve } from 'mokup/server/node'
const app = await createFetchServer({ entries: { dir: 'mock' } })
serve({ fetch: app.fetch, port: 3000 })
Cloudflare Worker example
import { createMokupWorker } from 'mokup/server/worker'
import mokupBundle from 'virtual:mokup-bundle'
export default createMokupWorker(mokupBundle)
Note:
virtual:mokup-bundleis only available in Vite with@cloudflare/vite-plugin.
In Node.js dev mode, usecreateFetchServerdirectly; you do not need that virtual module.
Core architecture
Use cases and boundaries
Good fit
- Teams with existing Vite/webpack projects that want low‑cost mock integration
- Projects that need visual route diagnostics
- Workflows that value fast feedback after mock updates
Less suitable
- Scenarios that depend heavily on complex dynamic proxy chains
- Extremely lightweight setups that do not want build‑time or plugin‑based integration
Mokup is not trying to replace every mock solution. It is designed to make mocks easier to adopt, easier to debug, and better aligned with everyday development workflows.
Closing
Mokup is still evolving quickly. Feedback is very welcome, including feature requests, DX feedback, and documentation improvements.
If this is useful for your workflow, feedback and feature requests are welcome.




