The mionPlugin from @mionjs/devtools/vite-plugin is the single Vite plugin that handles all mion build-time features: runtime type reflection, pure function extraction, and AOT cache generation.
import {mionPlugin} from '@mionjs/devtools/vite-plugin';
mionPlugin({
// Enables the type compiler, preserves TypeScript type metadata at runtime.
// Required for mion's validation and serialization.
runTypes?: {
tsConfig?: string; // Path to tsconfig.json (auto-discovered by default)
include?: string | string[]; // Glob patterns (default: ['**/*.tsx', '**/*.ts'])
exclude?: string | string[]; // Glob patterns (default: 'node_modules/**')
reflection?: 'default' | 'explicit' | 'never';
compilerOptions?: CompilerOptions;
},
// Scans client source for pureServerFn(), registerPureFnFactory(), and mapFrom() calls.
// Extracts them into a virtual module the server imports automatically.
serverPureFunctions?: {
clientSrcPath: string; // Path to client package source directory (required)
include?: string[]; // Glob patterns (default: ['**/*.ts', '**/*.tsx'])
exclude?: string[]; // Glob patterns (default: ['**/node_modules/**', '**/.dist/**', '**/dist/**'])
noViteClient?: boolean; // Require explicit names for pureServerFn/mapFrom (default: false)
},
// Generates AOT caches for validation, serialization, and pure functions.
// Without this, caches are fetched at runtime via fetchRemoteMethodsMetadata().
aotCaches?: {
excludedFns?: string[]; // JIT function IDs to exclude
excludedPureFns?: string[]; // Pure function names to exclude
cache?: boolean | string; // Disk cache: true (default), false, or custom path
excludeReflection?: boolean; // Stub out reflection modules in bundle (reduces size)
customVirtualModuleId?: string; // Custom virtual module prefix
},
// Runs the server to generate AOT caches and optionally keeps it alive.
// If omitted, only mion's internal routes are cached (when aotCaches is set).
server?: {
startScript: string; // Server start script (required)
viteConfig?: string; // Server's vite.config.ts for vite-node (auto-discovered)
runMode: 'buildOnly' | 'childProcess' | 'middleware'; // Server run mode (required)
waitTimeout?: number; // Max wait time in ms for setPlatformConfig() IPC (default: 30000)
env?: Record<string, string>; // Extra env vars for the child process
args?: string[]; // Extra args appended after the start script
},
});
aotCaches option only applies to vite build — it has no effect during vite dev.For setups where server and client use separate build tools (e.g., Next.js, Turbopack), or when you only have a server package.
import {defineConfig} from 'vite';
import {resolve} from 'path';
import {mionVitePlugin} from '@mionjs/devtools/vite-plugin';
export default defineConfig({
plugins: [
mionVitePlugin({
// runTypes metadata
runTypes: {tsConfig: resolve(__dirname, 'tsconfig.json')},
// Scan client source for pureServerFn() and mapFrom() calls
serverPureFunctions: {
clientSrcPath: resolve(__dirname, '../client/src'),
},
}),
],
build: {
lib: {
entry: resolve(__dirname, 'src/init.ts'),
formats: ['es'],
},
rollupOptions: {
external: [/^[^./]/],
},
},
});
import {defineConfig} from 'vite';
import {resolve} from 'path';
import {mionVitePlugin} from '@mionjs/devtools/vite-plugin';
// Server config when the client is NOT built with Vite (e.g., Next.js with Turbopack).
// noViteClient requires all pureServerFn() and mapFrom() calls to have explicit names.
export default defineConfig({
plugins: [
mionVitePlugin({
runTypes: {tsConfig: resolve(__dirname, 'tsconfig.json')},
serverPureFunctions: {
clientSrcPath: resolve(__dirname, '../client/src'),
noViteClient: true,
},
}),
],
});
When both client and server are managed by Vite. In childProcess mode the server stays running for dev; in middleware mode it runs inside the same Vite process (e.g., Nuxt).
import {defineConfig} from 'vite';
import {resolve} from 'path';
import {mionVitePlugin} from '@mionjs/devtools/vite-plugin';
// IPC mode: spawns the server, generates AOT caches, and keeps the server running.
// Useful during development when the client needs a live server for API calls.
export default defineConfig({
plugins: [
mionVitePlugin({
runTypes: {tsConfig: resolve(__dirname, 'tsconfig.json')},
// runs the server in a child process separate from vite dev server
server: {
startScript: resolve(__dirname, '../server/src/init.ts'),
viteConfig: resolve(__dirname, '../server/vite.config.ts'),
runMode: 'childProcess',
waitTimeout: 30000,
env: {PORT: '3000'},
},
}),
],
});
import {defineConfig} from 'vite';
import {resolve} from 'path';
import vue from '@vitejs/plugin-vue';
import {mionVitePlugin} from '@mionjs/devtools/vite-plugin';
// viteSSR mode: loads the server in the same Vite process.
// Used with frameworks like Nuxt that run Vite in middlewareMode.
export default defineConfig({
plugins: [
vue(),
mionVitePlugin({
runTypes: {tsConfig: resolve(__dirname, 'tsconfig.json')},
// run mion ins the same dev server as FE but in SSR mode
// mion runs as a middleware function
// api calls are directly proxied to the mion request handler function
server: {
startScript: resolve(__dirname, '../server/src/init.ts'),
runMode: 'middleware',
},
}),
],
});
// vitest globalSetup — wait for the mion server before running tests
import {serverReady} from '@mionjs/devtools/vite-plugin';
export async function setup() {
await serverReady;
}
The client fetches validation and serialization metadata from the server at runtime using optimistic updates, so no AOT caches or build-time server spawning is needed.
// Client without mion Vite plugin — no AOT caches needed.
// Validation and serialization metadata is fetched at runtime
// from the server via fetchRemoteMethodsMetadata().
import {initClient} from '@mionjs/client';
import type {MyApi} from './aot-routes-example.ts';
const {routes, middleFns} = initClient<MyApi>({baseURL: 'http://localhost:3000'});
mion provides an ESLint plugin with rules to catch common mistakes with type imports, route typing, and pure functions. See the ESLint Rules page for full documentation.
{
"extends": ["plugin:@mionjs/recommended"]
}