A Vite plugin that integrates srvx (Universal Server) with Vite's development server, similar to how @hono/vite-dev-server works with Hono.
- Automatic index.html serving - The plugin automatically serves
index.htmlon the root path - Hot Module Replacement (HMR) - Full HMR support for your srvx server
- Automatic Vite client script injection - Vite's dev client is automatically injected into HTML responses
- Web Standard APIs - Use Request/Response APIs that work everywhere
- Universal - Works with Node.js, Deno, and Bun
- Lightning fast - Powered by Vite's blazing fast dev server
- Vercel Edge Functions - Built-in support for deploying to Vercel (auto-detected!)
npm install vite-plugin-srvx srvx viteOr with pnpm:
pnpm add vite-plugin-srvx srvx viteCreate an index.html file in your project root:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My srvx App</title>
</head>
<body>
<h1>Hello from srvx + Vite!</h1>
<script type="module" src="/src/main.ts"></script>
</body>
</html>Create a src/server.ts file for your API routes:
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url)
// The plugin automatically serves index.html on '/'
// so you only need to handle API routes here
if (url.pathname === '/api/hello') {
return Response.json({
message: 'Hello from srvx!',
timestamp: new Date().toISOString(),
})
}
return new Response('Not Found', { status: 404 })
},
}Create a vite.config.ts file:
import { defineConfig } from 'vite'
import srvx from 'vite-plugin-srvx'
export default defineConfig({
plugins: [
...srvx({
entry: './src/server.ts',
}),
],
})viteYour srvx server will now run with Vite's dev server! Visit http://localhost:5173 to see your app:
/- Automatically servesindex.html/api/hello- Your srvx API endpoint- All other routes are handled by your srvx server's fetch handler
The plugin uses Vite's mode system to handle client and server builds separately.
Add these scripts to your package.json:
{
"scripts": {
"dev": "vite",
"build": "vite build && vite build --mode server",
"start": "srvx dist/server.js"
}
}Then build your app:
npm run buildThis will:
- Build your frontend (HTML, CSS, JS) to
dist/public(firstvite build) - Build your srvx server to
dist/server.js(secondvite build --mode server)
Run your production build:
npm run start
# or directly: srvx dist/server.jssrvx automatically serves static files from the dist/public directory!
interface SrvxOptions {
// Entry file for your srvx server (default: './src/server.ts')
entry?: string
// Output directory for server build (default: 'dist')
outDir?: string
// Server output filename (default: 'server.js')
serverOutFile?: string
// Target framework for deployment (e.g., 'vercel')
// When set to 'vercel' OR when VERCEL=1 env var is set (auto-detected),
// outputs to dist/api/index.js for Vercel Edge Functions
framework?: 'vercel'
// Development server options
// Patterns to exclude from the srvx handler (will be handled by Vite instead)
exclude?: (string | RegExp)[]
// Whether to inject Vite's client script for HMR (default: true)
injectClientScript?: boolean
// Custom module loader (default: uses Vite's ssrLoadModule)
loadModule?: (server: ViteDevServer, entry: string) => Promise<any>
}Note: The plugin returns an array of three plugins (dev server + client build + server build), so use the spread operator:
...srvx({})
import { defineConfig } from 'vite'
import srvx from 'vite-plugin-srvx'
export default defineConfig(({ mode }) => ({
plugins: [
...srvx({
entry: './src/server.ts',
outDir: 'build',
serverOutFile: 'app.js',
exclude: [
/.*\.tsx?$/,
/.*\.css$/,
/^\/@.+$/,
],
injectClientScript: true,
}),
],
}))Then build with:
npm run build
# This runs: vite build && vite build --mode server
# - Client build outputs to build/public
# - Server build outputs to build/app.jsAnd run: srvx build/app.js (it will automatically serve static files from build/public)
If you need more control, you can import the plugins separately:
import { defineConfig } from 'vite'
import { devServer, clientBuild, srvxBuild } from 'vite-plugin-srvx'
export default defineConfig(({ mode }) => ({
plugins: [
devServer({ entry: './src/server.ts' }),
clientBuild({ outDir: 'dist' }),
srvxBuild({ entry: './src/server.ts', outDir: 'dist' }),
],
}))The devServer plugin creates a Vite middleware that:
- Serves index.html on root - When requesting
/, the plugin automatically serves and transforms yourindex.htmlusing Vite'stransformIndexHtml(which handles script injection, etc.) - Intercepts other HTTP requests - All non-root requests are passed to your srvx server
- Loads your srvx server module - Uses Vite's SSR module loader for HMR support
- Converts to Web Standard APIs - Converts Node.js
IncomingMessage→ Web StandardRequest - Calls your fetch handler - Your srvx server's
fetchhandler processes the request - Converts the response - Converts the
Responseback to Node.jsServerResponse - Injects Vite client - For HTML responses from your server, Vite's client script is injected for HMR
The plugin uses Vite's mode system with three separate plugins:
-
Client build (
vite build):clientBuildplugin is active (mode !== 'server')- Builds frontend to
dist/public srvxBuildplugin is inactive
-
Server build (
vite build --mode server):srvxBuildplugin is active (mode === 'server')- Sets
ssr: truevia theconfighook - Builds server to
dist/server.js clientBuildplugin is inactive
-
Run with srvx:
srvx dist/server.js- srvx automatically serves static files from
dist/public
This approach follows the same pattern as @hono/vite-build
This gives you the best of both worlds: srvx's universal server API and Vite's lightning-fast development experience!
Check out the examples directory for full working examples:
- examples/basic - Basic srvx + Vite setup
- examples/vercel - Vercel Edge Functions deployment
To run an example:
pnpm install
pnpm build
cd examples/basic # or examples/vercel
pnpm devThis plugin is heavily inspired by @hono/vite-dev-server but designed specifically for srvx:
- Similar middleware architecture
- Same HMR capabilities
- Compatible API design
- Works with any framework that uses Web Standard fetch API
MIT
Inspired by @hono/vite-dev-server