From 2849219206bf29ccb9a7268b54d31c88c12a24bf Mon Sep 17 00:00:00 2001 From: pacexy Date: Sun, 22 Mar 2026 22:35:46 +0800 Subject: [PATCH 01/13] Add dev-time Next typegen support --- packages/vinext/src/index.ts | 20 ++++ packages/vinext/src/typegen.ts | 124 +++++++++++++++++++++ tests/typegen.test.ts | 198 +++++++++++++++++++++++++++++++++ 3 files changed, 342 insertions(+) create mode 100644 packages/vinext/src/typegen.ts create mode 100644 tests/typegen.test.ts diff --git a/packages/vinext/src/index.ts b/packages/vinext/src/index.ts index db8073349..e3798aef3 100644 --- a/packages/vinext/src/index.ts +++ b/packages/vinext/src/index.ts @@ -55,6 +55,7 @@ import { asyncHooksStubPlugin } from "./plugins/async-hooks-stub.js"; import { clientReferenceDedupPlugin } from "./plugins/client-reference-dedup.js"; import { createOptimizeImportsPlugin } from "./plugins/optimize-imports.js"; import { hasWranglerConfig, formatMissingCloudflarePluginError } from "./deploy.js"; +import { createNextTypegenController } from "./typegen.js"; import tsconfigPaths from "vite-tsconfig-paths"; import type { Options as VitePluginReactOptions } from "@vitejs/plugin-react"; import MagicString from "magic-string"; @@ -832,6 +833,14 @@ export interface VinextOptions { * @default true */ react?: VitePluginReactOptions | boolean; + /** + * Run `next typegen` automatically in development when Next.js is installed. + * This generates route-aware helpers like `PageProps`/`LayoutProps` and + * typed route metadata into `.next/types` for editor type-checking. + * Set to `false` to disable automatic type generation. + * @default true + */ + typegen?: boolean; /** * Experimental vinext-only feature flags. */ @@ -2333,6 +2342,13 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] { configureServer(server: ViteDevServer) { // Watch pages directory for file additions/removals to invalidate route cache. const pageExtensions = fileMatcher.extensionRegex; + const typegen = createNextTypegenController({ + root, + enabled: options.typegen !== false, + }); + + typegen.start(); + server.httpServer?.once("close", () => typegen.close()); // Build a long-lived ModuleRunner for loading all Pages Router modules // (middleware, API routes, SSR page rendering) on every request. @@ -2384,19 +2400,23 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] { server.watcher.on("add", (filePath: string) => { if (hasPagesDir && filePath.startsWith(pagesDir) && pageExtensions.test(filePath)) { invalidateRouteCache(pagesDir); + typegen.schedule(); } if (hasAppDir && filePath.startsWith(appDir) && pageExtensions.test(filePath)) { invalidateAppRouteCache(); invalidateRscEntryModule(); + typegen.schedule(); } }); server.watcher.on("unlink", (filePath: string) => { if (hasPagesDir && filePath.startsWith(pagesDir) && pageExtensions.test(filePath)) { invalidateRouteCache(pagesDir); + typegen.schedule(); } if (hasAppDir && filePath.startsWith(appDir) && pageExtensions.test(filePath)) { invalidateAppRouteCache(); invalidateRscEntryModule(); + typegen.schedule(); } }); diff --git a/packages/vinext/src/typegen.ts b/packages/vinext/src/typegen.ts new file mode 100644 index 000000000..996e74d6c --- /dev/null +++ b/packages/vinext/src/typegen.ts @@ -0,0 +1,124 @@ +import { spawn, type ChildProcess } from "node:child_process"; +import { createRequire } from "node:module"; +import path from "node:path"; + +export interface NextTypegenControllerOptions { + root: string; + enabled?: boolean; + debounceMs?: number; + logger?: Pick; + resolveNextBin?: (root: string) => string | null; + spawnImpl?: typeof spawn; +} + +export interface NextTypegenController { + start(): void; + schedule(): void; + close(): void; +} + +export function resolveNextTypegenBin(root: string): string | null { + try { + const projectRequire = createRequire(path.join(root, "package.json")); + return projectRequire.resolve("next/dist/bin/next"); + } catch { + return null; + } +} + +export function createNextTypegenController( + options: NextTypegenControllerOptions, +): NextTypegenController { + const { + root, + enabled = true, + debounceMs = 150, + logger = console, + resolveNextBin = resolveNextTypegenBin, + spawnImpl = spawn, + } = options; + + let timer: ReturnType | null = null; + let child: ChildProcess | null = null; + let pending = false; + let nextBin: string | null | undefined; + let missingNextLogged = false; + let closed = false; + + function getNextBin(): string | null { + if (nextBin !== undefined) return nextBin; + nextBin = resolveNextBin(root); + if (!nextBin && !missingNextLogged) { + missingNextLogged = true; + logger.info("[vinext] Skipping dev typegen: `next` is not installed in this project."); + } + return nextBin; + } + + function run(): void { + if (!enabled || closed) return; + + const resolvedNextBin = getNextBin(); + if (!resolvedNextBin) return; + + if (child) { + pending = true; + return; + } + + child = spawnImpl(process.execPath, [resolvedNextBin, "typegen"], { + cwd: root, + stdio: "ignore", + env: process.env, + }); + + child.once("error", (error) => { + logger.warn(`[vinext] Failed to run \`next typegen\`: ${error.message}`); + }); + + child.once("exit", (code, signal) => { + child = null; + + if (closed) return; + + if (code !== 0) { + const detail = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`; + logger.warn(`[vinext] \`next typegen\` exited with ${detail}.`); + } + + if (pending) { + pending = false; + run(); + } + }); + } + + function scheduleWithDelay(delayMs: number): void { + if (!enabled || closed) return; + if (timer) clearTimeout(timer); + timer = setTimeout(() => { + timer = null; + run(); + }, delayMs); + } + + return { + start() { + scheduleWithDelay(0); + }, + schedule() { + scheduleWithDelay(debounceMs); + }, + close() { + closed = true; + if (timer) { + clearTimeout(timer); + timer = null; + } + if (child) { + child.kill(); + child = null; + } + }, + }; +} diff --git a/tests/typegen.test.ts b/tests/typegen.test.ts new file mode 100644 index 000000000..5e80fdb3a --- /dev/null +++ b/tests/typegen.test.ts @@ -0,0 +1,198 @@ +import { afterEach, describe, expect, it, vi } from "vite-plus/test"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { createServer, type ViteDevServer } from "vite-plus"; +import vinext from "../packages/vinext/src/index.js"; +import { + createNextTypegenController, + resolveNextTypegenBin, +} from "../packages/vinext/src/typegen.js"; + +function createTempProject(prefix: string): string { + return fs.mkdtempSync(path.join(os.tmpdir(), prefix)); +} + +function writeFile(root: string, relativePath: string, content: string): void { + const fullPath = path.join(root, relativePath); + fs.mkdirSync(path.dirname(fullPath), { recursive: true }); + fs.writeFileSync(fullPath, content, "utf8"); +} + +function readCount(root: string): number { + const countFile = path.join(root, ".typegen-count"); + if (!fs.existsSync(countFile)) return 0; + return Number(fs.readFileSync(countFile, "utf8")); +} + +async function waitFor(predicate: () => boolean, timeoutMs = 5000): Promise { + const start = Date.now(); + while (Date.now() - start < timeoutMs) { + if (predicate()) return; + await new Promise((resolve) => setTimeout(resolve, 50)); + } + throw new Error("Timed out waiting for condition"); +} + +function setupPagesProject(root: string): void { + writeFile( + root, + "package.json", + JSON.stringify({ + name: "typegen-test", + version: "1.0.0", + dependencies: { + react: "^19.2.0", + "react-dom": "^19.2.0", + }, + }), + ); + writeFile(root, "pages/index.tsx", "export default function Page() { return
hi
; }\n"); +} + +function installFakeNext(root: string): void { + writeFile( + root, + "node_modules/next/package.json", + JSON.stringify({ name: "next", version: "15.0.0" }), + ); + writeFile( + root, + "node_modules/next/dist/bin/next.js", + `const fs = require("node:fs"); +const path = require("node:path"); +const countFile = path.join(process.cwd(), ".typegen-count"); +const current = fs.existsSync(countFile) ? Number(fs.readFileSync(countFile, "utf8")) : 0; +fs.writeFileSync(countFile, String(current + 1)); +`, + ); +} + +async function startServer( + root: string, + typegen: boolean | undefined = undefined, +): Promise { + const server = await createServer({ + root, + configFile: false, + logLevel: "silent", + plugins: [vinext({ appDir: root, typegen })], + server: { port: 0 }, + }); + await server.listen(); + return server; +} + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe("next typegen controller", () => { + it("resolves the local Next.js bin from the project root", () => { + const root = createTempProject("vinext-typegen-bin-"); + try { + setupPagesProject(root); + installFakeNext(root); + + expect(resolveNextTypegenBin(root)).toBe( + path.join(root, "node_modules/next/dist/bin/next.js"), + ); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it("logs once and skips when next is missing", async () => { + const info = vi.fn(); + const controller = createNextTypegenController({ + root: "/tmp/no-next", + logger: { info, warn: vi.fn() }, + resolveNextBin: () => null, + }); + + controller.start(); + controller.schedule(); + + await waitFor(() => info.mock.calls.length === 1); + expect(info).toHaveBeenCalledTimes(1); + }); +}); + +describe("vinext dev typegen integration", () => { + it("runs `next typegen` on dev server startup by default", async () => { + const root = createTempProject("vinext-typegen-start-"); + let server: ViteDevServer | null = null; + try { + setupPagesProject(root); + installFakeNext(root); + + server = await startServer(root); + await waitFor(() => readCount(root) >= 1); + + expect(readCount(root)).toBeGreaterThanOrEqual(1); + } finally { + await server?.close(); + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it("can disable automatic typegen", async () => { + const root = createTempProject("vinext-typegen-disabled-"); + let server: ViteDevServer | null = null; + try { + setupPagesProject(root); + installFakeNext(root); + + server = await startServer(root, false); + await new Promise((resolve) => setTimeout(resolve, 400)); + + expect(readCount(root)).toBe(0); + } finally { + await server?.close(); + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it("reruns typegen when a route file is added", async () => { + const root = createTempProject("vinext-typegen-watch-"); + let server: ViteDevServer | null = null; + try { + setupPagesProject(root); + installFakeNext(root); + + server = await startServer(root); + await waitFor(() => readCount(root) >= 1); + + writeFile( + root, + "pages/about.tsx", + "export default function About() { return
about
; }\n", + ); + + await waitFor(() => readCount(root) >= 2); + expect(readCount(root)).toBeGreaterThanOrEqual(2); + } finally { + await server?.close(); + fs.rmSync(root, { recursive: true, force: true }); + } + }); + + it("starts cleanly when next is not installed", async () => { + const root = createTempProject("vinext-typegen-missing-"); + let server: ViteDevServer | null = null; + const info = vi.spyOn(console, "info").mockImplementation(() => {}); + try { + setupPagesProject(root); + + server = await startServer(root); + await new Promise((resolve) => setTimeout(resolve, 250)); + + expect(info).toHaveBeenCalledWith( + "[vinext] Skipping dev typegen: `next` is not installed in this project.", + ); + } finally { + await server?.close(); + fs.rmSync(root, { recursive: true, force: true }); + } + }); +}); From 056b6f634fd33f779948dfbf77958811a0421cd0 Mon Sep 17 00:00:00 2001 From: pacexy Date: Sun, 22 Mar 2026 22:42:13 +0800 Subject: [PATCH 02/13] Document type safety workflow --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index c9f52ed0c..6014fbc4f 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,23 @@ Yes. Add the [Nitro](https://v3.nitro.build/) Vite plugin alongside vinext, and **What happens when Next.js releases a new feature?** We track the public Next.js API surface and add support for new stable features. Experimental or unstable Next.js features are lower priority. The plan is to add commit-level tracking of the Next.js repo so we can stay current as new versions are released. +## Type Safety + +vinext uses Next.js's own type generation for route-aware helpers like `PageProps`, `LayoutProps`. During development, the Vite plugin runs [`next typegen`](https://nextjs.org/docs/app/api-reference/cli/next#next-typegen-options) automatically when `next` is installed. + +If you want to turn this off, disable it in your Vite config: + +```ts +import { defineConfig } from "vite"; +import vinext from "vinext"; + +export default defineConfig({ + plugins: [vinext({ typegen: false })], +}); +``` + +For CI, `tsc --noEmit`, or production builds that rely on these helpers, run `next typegen` before your type-check step. vinext only auto-runs type generation in dev mode. + ## Deployment ### Cloudflare Workers From 436bad619c0b48a341121d2226433311bc2d84df Mon Sep 17 00:00:00 2001 From: pacexy Date: Sun, 22 Mar 2026 23:06:57 +0800 Subject: [PATCH 03/13] update --- packages/vinext/src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/vinext/src/index.ts b/packages/vinext/src/index.ts index e3798aef3..888df7719 100644 --- a/packages/vinext/src/index.ts +++ b/packages/vinext/src/index.ts @@ -835,8 +835,7 @@ export interface VinextOptions { react?: VitePluginReactOptions | boolean; /** * Run `next typegen` automatically in development when Next.js is installed. - * This generates route-aware helpers like `PageProps`/`LayoutProps` and - * typed route metadata into `.next/types` for editor type-checking. + * This generates route-aware helpers like `PageProps`/`LayoutProps`. * Set to `false` to disable automatic type generation. * @default true */ From ad3b9367462763a76ed7e404174917fe7c425895 Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 08:49:56 +0800 Subject: [PATCH 04/13] update docs --- README.md | 6 ++++-- packages/vinext/src/index.ts | 2 ++ packages/vinext/src/typegen.ts | 9 +++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6014fbc4f..e34717f21 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,9 @@ We track the public Next.js API surface and add support for new stable features. ## Type Safety -vinext uses Next.js's own type generation for route-aware helpers like `PageProps`, `LayoutProps`. During development, the Vite plugin runs [`next typegen`](https://nextjs.org/docs/app/api-reference/cli/next#next-typegen-options) automatically when `next` is installed. +As a short-term bridge for route-aware helpers like `PageProps` and `LayoutProps`, vinext can reuse Next.js's own type generation when `next` is already installed in the project. During development, the Vite plugin runs [`next typegen`](https://nextjs.org/docs/app/api-reference/cli/next#next-typegen-options) automatically on a best-effort basis. + +This is intended to improve developer experience in the near term, not as the long-term design. Native Vinext type generation is tracked in [#664](https://github.com/cloudflare/vinext/issues/664). If you want to turn this off, disable it in your Vite config: @@ -181,7 +183,7 @@ export default defineConfig({ }); ``` -For CI, `tsc --noEmit`, or production builds that rely on these helpers, run `next typegen` before your type-check step. vinext only auto-runs type generation in dev mode. +If your project already has `next` installed and you rely on these helpers in CI or a separate type-check step, you can run `next typegen` before `tsc --noEmit`. vinext only auto-runs this bridge in dev mode. ## Deployment diff --git a/packages/vinext/src/index.ts b/packages/vinext/src/index.ts index 888df7719..f72ac04d6 100644 --- a/packages/vinext/src/index.ts +++ b/packages/vinext/src/index.ts @@ -836,6 +836,8 @@ export interface VinextOptions { /** * Run `next typegen` automatically in development when Next.js is installed. * This generates route-aware helpers like `PageProps`/`LayoutProps`. + * Temporary stopgap until Vinext ships native type generation: + * https://github.com/cloudflare/vinext/issues/664 * Set to `false` to disable automatic type generation. * @default true */ diff --git a/packages/vinext/src/typegen.ts b/packages/vinext/src/typegen.ts index 996e74d6c..9d8ff198c 100644 --- a/packages/vinext/src/typegen.ts +++ b/packages/vinext/src/typegen.ts @@ -2,6 +2,15 @@ import { spawn, type ChildProcess } from "node:child_process"; import { createRequire } from "node:module"; import path from "node:path"; +/** + * Temporary bridge for route-aware type generation. + * + * Vinext should eventually generate these types from its own route tree + * instead of delegating to `next typegen`, but this improves dev-time DX in + * the meantime without making Next.js a hard requirement for startup. + * + * Tracking issue: https://github.com/cloudflare/vinext/issues/664 + */ export interface NextTypegenControllerOptions { root: string; enabled?: boolean; From 9c8b1a66c2f178a2f18a610f643bc673963eb339 Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 09:09:39 +0800 Subject: [PATCH 05/13] fix: close typegen on vite server shutdown --- packages/vinext/src/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/vinext/src/index.ts b/packages/vinext/src/index.ts index f72ac04d6..55a823ea2 100644 --- a/packages/vinext/src/index.ts +++ b/packages/vinext/src/index.ts @@ -2347,9 +2347,13 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] { root, enabled: options.typegen !== false, }); + const closeServer = server.close.bind(server); typegen.start(); - server.httpServer?.once("close", () => typegen.close()); + server.close = async () => { + typegen.close(); + await closeServer(); + }; // Build a long-lived ModuleRunner for loading all Pages Router modules // (middleware, API routes, SSR page rendering) on every request. From 13e693b91ca97b14dc59951e3b581d23cba8c6e9 Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 09:09:55 +0800 Subject: [PATCH 06/13] fix: rely on default env inheritance for typegen --- packages/vinext/src/typegen.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vinext/src/typegen.ts b/packages/vinext/src/typegen.ts index 9d8ff198c..c40dc35ca 100644 --- a/packages/vinext/src/typegen.ts +++ b/packages/vinext/src/typegen.ts @@ -78,7 +78,6 @@ export function createNextTypegenController( child = spawnImpl(process.execPath, [resolvedNextBin, "typegen"], { cwd: root, stdio: "ignore", - env: process.env, }); child.once("error", (error) => { From 7937f92c276ae812cdf84266a31178b4bedeb6c9 Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 09:10:16 +0800 Subject: [PATCH 07/13] fix: log the first successful typegen run --- packages/vinext/src/typegen.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/vinext/src/typegen.ts b/packages/vinext/src/typegen.ts index c40dc35ca..fcb14f02c 100644 --- a/packages/vinext/src/typegen.ts +++ b/packages/vinext/src/typegen.ts @@ -52,6 +52,7 @@ export function createNextTypegenController( let pending = false; let nextBin: string | null | undefined; let missingNextLogged = false; + let firstSuccessLogged = false; let closed = false; function getNextBin(): string | null { @@ -92,6 +93,9 @@ export function createNextTypegenController( if (code !== 0) { const detail = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`; logger.warn(`[vinext] \`next typegen\` exited with ${detail}.`); + } else if (!firstSuccessLogged) { + firstSuccessLogged = true; + logger.info("[vinext] `next typegen` completed."); } if (pending) { From 79b276c7591d976e25a2ddfc21fdf70f2ebd08a4 Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 09:10:32 +0800 Subject: [PATCH 08/13] fix: detach typegen child listeners before kill --- packages/vinext/src/typegen.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vinext/src/typegen.ts b/packages/vinext/src/typegen.ts index fcb14f02c..2cf0ba3ee 100644 --- a/packages/vinext/src/typegen.ts +++ b/packages/vinext/src/typegen.ts @@ -128,6 +128,7 @@ export function createNextTypegenController( timer = null; } if (child) { + child.removeAllListeners(); child.kill(); child = null; } From a2f061d4e1b9723b0cb2c58188b48c8ae46932bb Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 09:10:48 +0800 Subject: [PATCH 09/13] docs: explain deferred dev typegen startup --- packages/vinext/src/typegen.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/vinext/src/typegen.ts b/packages/vinext/src/typegen.ts index 2cf0ba3ee..ffa8f5975 100644 --- a/packages/vinext/src/typegen.ts +++ b/packages/vinext/src/typegen.ts @@ -116,6 +116,8 @@ export function createNextTypegenController( return { start() { + // Defer the first run so configureServer can finish without waiting for + // `next typegen` to complete synchronously. scheduleWithDelay(0); }, schedule() { From 0fbb66e4475b4c7294055b0b7abdbdcf1640e2a4 Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 09:11:16 +0800 Subject: [PATCH 10/13] docs: clarify the temporary next typegen tradeoff --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e34717f21..7e1e7c373 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,9 @@ export default defineConfig({ }); ``` -If your project already has `next` installed and you rely on these helpers in CI or a separate type-check step, you can run `next typegen` before `tsc --noEmit`. vinext only auto-runs this bridge in dev mode. +If you rely on these helpers in CI or a separate type-check step, your project must also have `next` installed (typically as a `devDependency`) so `next typegen` is available. That is a temporary tradeoff of this bridge while Vinext-native type generation is still in progress. + +vinext only auto-runs this bridge in dev mode, and only when `next` is installed in the project. ## Deployment From da51df89c549106653e401ab5ac925783477ffaf Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 09:11:47 +0800 Subject: [PATCH 11/13] test: clarify the fake next typegen fixture --- tests/typegen.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/typegen.test.ts b/tests/typegen.test.ts index 5e80fdb3a..b1cc34759 100644 --- a/tests/typegen.test.ts +++ b/tests/typegen.test.ts @@ -50,6 +50,7 @@ function setupPagesProject(root: string): void { writeFile(root, "pages/index.tsx", "export default function Page() { return
hi
; }\n"); } +/** Install a fake `next` binary that increments a counter file instead of running real typegen. */ function installFakeNext(root: string): void { writeFile( root, @@ -119,7 +120,7 @@ describe("next typegen controller", () => { }); describe("vinext dev typegen integration", () => { - it("runs `next typegen` on dev server startup by default", async () => { + it("invokes the project-local Next.js typegen command on dev server startup by default", async () => { const root = createTempProject("vinext-typegen-start-"); let server: ViteDevServer | null = null; try { @@ -153,7 +154,7 @@ describe("vinext dev typegen integration", () => { } }); - it("reruns typegen when a route file is added", async () => { + it("reruns the project-local Next.js typegen command when a route file is added", async () => { const root = createTempProject("vinext-typegen-watch-"); let server: ViteDevServer | null = null; try { From c0dc029a50516d04f4c823feaa4762707803543b Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 09:12:03 +0800 Subject: [PATCH 12/13] test: avoid a race in missing next logging --- tests/typegen.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/typegen.test.ts b/tests/typegen.test.ts index b1cc34759..be56ee474 100644 --- a/tests/typegen.test.ts +++ b/tests/typegen.test.ts @@ -114,7 +114,7 @@ describe("next typegen controller", () => { controller.start(); controller.schedule(); - await waitFor(() => info.mock.calls.length === 1); + await new Promise((resolve) => setTimeout(resolve, 300)); expect(info).toHaveBeenCalledTimes(1); }); }); From f38af9dd14cea9aa41e31483d4d137b02656b805 Mon Sep 17 00:00:00 2001 From: pacexy Date: Mon, 23 Mar 2026 09:20:05 +0800 Subject: [PATCH 13/13] update --- tests/typegen.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/typegen.test.ts b/tests/typegen.test.ts index be56ee474..a95961827 100644 --- a/tests/typegen.test.ts +++ b/tests/typegen.test.ts @@ -120,7 +120,7 @@ describe("next typegen controller", () => { }); describe("vinext dev typegen integration", () => { - it("invokes the project-local Next.js typegen command on dev server startup by default", async () => { + it("runs the project-local `next typegen` command on dev server startup by default", async () => { const root = createTempProject("vinext-typegen-start-"); let server: ViteDevServer | null = null; try { @@ -154,7 +154,7 @@ describe("vinext dev typegen integration", () => { } }); - it("reruns the project-local Next.js typegen command when a route file is added", async () => { + it("reruns the project-local `next typegen` command when a route file is added", async () => { const root = createTempProject("vinext-typegen-watch-"); let server: ViteDevServer | null = null; try {