Virtual Module System
Vinext uses Vite’s virtual module system to generate dynamic entry points for different runtime environments. This guide explains how virtual modules work, how they’re generated, and the resolution patterns used.What Are Virtual Modules?
Virtual modules are modules that don’t exist on disk. They’re generated at runtime by Vite plugins and resolved via theresolveId and load hooks.
Why use virtual modules?
- Generate entry points based on file-system routing
- Embed route metadata at build time
- Create environment-specific entries (RSC vs SSR vs Client)
- Avoid writing generated files to disk
Virtual Module IDs
Vinext defines several virtual modules:Pages Router
App Router
\0 prefix is a Rollup convention indicating a resolved virtual module. It prevents other plugins from attempting to resolve it further.
Resolution Hooks
Frompackages/vinext/src/index.ts:
Resolution Quirks
1. Build-time root prefix During SSR builds, Vite prefixes virtual module IDs with the project root path:- Dev:
virtual:vinext-server-entry - Build:
/home/user/project/virtual:vinext-server-entry
resolveId hook strips the root prefix before matching.
2. \0 prefix in client environment
When the RSC plugin generates its browser entry, it imports virtual modules using the already-resolved \0-prefixed ID. Vite’s import-analysis plugin can’t resolve this.
Fix: Strip the \0 prefix before pattern matching:
import.meta.url and path resolution to generate absolute paths:
Server Entry Generation
The Pages Router server entry (virtual:vinext-server-entry) is a self-contained SSR handler:
- All page and API routes are imported and registered
- Config is embedded at build time (no runtime file I/O)
- Middleware matching logic is inlined
- ISR cache helpers are included
- Supports both development and production
RSC Entry Generation
The App Router RSC entry (virtual:vinext-rsc-entry) is the request handler:
From packages/vinext/src/server/app-dev-server.ts:
- All routes are discovered and imported at build time
- Metadata files are embedded as base64 (works on Workers with no filesystem)
- Full middleware, rewrite, redirect, and header logic is inlined
- Component tree building logic is included
- Server action handling is built-in
Client Entry Generation
The Pages Router client entry (virtual:vinext-client-entry) bootstraps React hydration:
virtual:vinext-app-browser-entry) is generated by the RSC plugin and consumes the RSC stream for hydration.
SSR Entry Generation
The App Router SSR entry (virtual:vinext-app-ssr-entry) consumes the RSC stream and renders HTML:
- RSC uses
react-server(server-only APIs) - SSR uses
node(React client APIs for SSR)
Shim Resolution
Allnext/* imports are resolved to shim modules:
Next Steps
Architecture Deep Dive
Core architecture and patterns
RSC Integration
React Server Components integration
Build Pipeline
Production build pipeline
Contributing
Contribute to Vinext