cloudflare / cloudflare/vinext
Refactor: Extract template string code generation from index.ts and app-dev-server.ts into separate modules
- Dominant language
- TypeScript
- Stars
- 8.8k
- Forks
- 406
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 120
Description
## Problem
`index.ts` (3,528 lines) and `app-dev-server.ts` (2,734 lines) are the two largest files in the codebase. Both files mix Vite plugin logic with massive template string blocks that generate runtime JavaScript modules. This creates several problems:
1. **AI agents can't hold the entire file in context.** These files exceed typical context windows, leading to partial reads and missed interactions between sections.
2. **Template string edits are error-prone.** The generated code uses escaped characters (`\\n`, `\\.`), `var` instead of `const/let`, and mixes interpolated expressions with static code. AI agents routinely break escaping or confuse plugin code with generated runtime code.
3. **No way to test generated code in isolation.** The template strings are embedded in plugin functions, so the only way to verify generated output is to run the full dev/build pipeline.
## What needs to be extracted
### From `index.ts`
| Template | Lines | Span | Function | Generates |
|----------|-------|------|----------|-----------|
| Pages Router prod server entry | 806-1549 | ~743 lines | `generateServerEntry()` | Complete production server module: SSR, ISR, API routes, i18n, asset injection, middleware, route matching |
| Middleware runtime | 655-801 | ~147 lines | `middlewareExportCode` variable | Middleware matching and execution, ReDoS protection (embedded inside the server entry) |
| Pages Router client entry | 1576-1634 | ~58 lines | `generateClientEntry()` | Client hydration: page loaders, `_app` wrapping, `hydrateRoot()` |
The server entry template (743 lines) is the primary target. It contains the entire Pages Router production request lifecycle as a template string.
### From `app-dev-server.ts`
| Template | Lines | Span | Function | Generates |
|----------|-------|------|----------|-----------|
| RSC entry | 201-2060 | ~1,860 lines | `generateRscEntry()` | The entire App Router request handler: route matching, middleware, CSRF, config redirects/rewrites/headers, metadata routes, server actions, layout tree construction, RSC streaming, caching |
| SSR entry | 2070-2425 | ~356 lines | `generateSsrEntry()` | RSC-to-HTML rendering, progressive streaming, font/head injection |
| Browser entry | 2436-2733 | ~298 lines | `generateBrowserEntry()` | Client hydration, RSC navigation, server actions, prefetch cache, HMR |
The RSC entry template (1,860 lines) is the largest single template string in the codebase. It contains at least 15 logically distinct subsystems inlined as generated code.
## Proposed approach
### 1. Create an `entries/` directory
```
packages/vinext/src/entries/
pages-server-entry.ts # From index.ts generateServerEntry()
pages-client-entry.ts # From index.ts generateClientEntry()
app-rsc-entry.ts # From app-dev-server.ts generateRscEntry()
app-ssr-entry.ts # From app-dev-server.ts generateSsrEntry()
app-browser-entry.ts # From app-dev-server.ts generateBrowserEntry()
```
Each file exports a function that takes the same parameters the current generator functions receive (route table, config, feature flags) and returns the generated code string.
### 2. Add snapshot tests
For each extracted template function, add a test that:
- Calls the function with representative inputs (a few routes, middleware present/absent, basePath set/unset, i18n enabled/disabled)
- Snapshots the generated output
- When an AI edits a template, the snapshot diff shows exactly what changed in the generated code
This is the key safety improvement. Currently there's no way to see what the generated code looks like without running the full pipeline.
### 3. Reduce `index.ts` and `app-dev-server.ts` to orchestration
After extraction, `index.ts` should be the Vite plugin shell (resolveId, load, configureServer, config hooks) that calls into the entry generators. `app-dev-server.ts` should be a thin module that calls the three App Router entry generators.
### Non-goals
- **Don't eliminate the template string pattern entirely.** Code generation via template strings is the right approach for virtual modules that need dynamic imports based on the scanned route table. The goal is to isolate the templates, not replace them.
- **Don't refactor the generated code's internal logic.** That's a separate concern (see the shared request handler issue). This issue is purely about file organization.
## Verification
- `pnpm test` (all Vitest tests pass)
- `pnpm run test:e2e` (all Playwright E2E tests pass)
- `pnpm run typecheck`
- `pnpm run lint`
- Manually verify that `index.ts` is under 1,000 lines and `app-dev-server.ts` is under 500 lines after extraction
Contributor guide
Assessment
This issue has not been assessed yet.