From 625aa138f17d07d209d3b7f03334a61838c18de6 Mon Sep 17 00:00:00 2001 From: Yunfei He Date: Sun, 24 May 2026 21:28:29 +0800 Subject: [PATCH] fix(cli): clean terminal output for TUI apps - Silence Vite server logs (logLevel: 'silent') - Intercept console.log/info/warn/error/debug in child process to suppress [vite] and [Vue warn] noise from HMR client - Add 3s startup grace period to ignore initial reload requests (prevents double-spawn on first WS connection) - Clear screen before spawning child process Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/basic/package.json | 20 ------------------- examples/basic/src/App.vue | 31 ----------------------------- examples/basic/src/Item.vue | 17 ---------------- examples/basic/src/main.ts | 10 ---------- examples/basic/src/vue-shim.d.ts | 6 ------ examples/basic/tsconfig.json | 19 ------------------ examples/basic/vite.config.ts | 28 -------------------------- packages/cli/src/dev.ts | 9 +++++++++ packages/cli/src/process-manager.ts | 17 +++++++++++++++- 9 files changed, 25 insertions(+), 132 deletions(-) delete mode 100644 examples/basic/package.json delete mode 100644 examples/basic/src/App.vue delete mode 100644 examples/basic/src/Item.vue delete mode 100644 examples/basic/src/main.ts delete mode 100644 examples/basic/src/vue-shim.d.ts delete mode 100644 examples/basic/tsconfig.json delete mode 100644 examples/basic/vite.config.ts diff --git a/examples/basic/package.json b/examples/basic/package.json deleted file mode 100644 index 0346743..0000000 --- a/examples/basic/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@vue-tui/example-flappy-bird", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vite build", - "start": "vite build && node dist/game.mjs" - }, - "dependencies": { - "@vue-tui/runtime": "workspace:*", - "chalk": "^5.3.0", - "vue": "^3.4.0" - }, - "devDependencies": { - "@types/node": "catalog:", - "@vitejs/plugin-vue": "^6", - "vite": "catalog:" - } -} diff --git a/examples/basic/src/App.vue b/examples/basic/src/App.vue deleted file mode 100644 index 800f51d..0000000 --- a/examples/basic/src/App.vue +++ /dev/null @@ -1,31 +0,0 @@ - - - diff --git a/examples/basic/src/Item.vue b/examples/basic/src/Item.vue deleted file mode 100644 index 65b9280..0000000 --- a/examples/basic/src/Item.vue +++ /dev/null @@ -1,17 +0,0 @@ - - - diff --git a/examples/basic/src/main.ts b/examples/basic/src/main.ts deleted file mode 100644 index 3f59fcd..0000000 --- a/examples/basic/src/main.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Flappy Bird example for @vue-tui/runtime. -// -// pnpm --filter @vue-tui/example-flappy-bird start -// -// Controls: space / ↑ / w to flap, q or Ctrl-C to quit, r to restart after dying. - -import { createApp } from "@vue-tui/runtime"; -import App from "./App.vue"; - -createApp(App).mount(); diff --git a/examples/basic/src/vue-shim.d.ts b/examples/basic/src/vue-shim.d.ts deleted file mode 100644 index 4dabb13..0000000 --- a/examples/basic/src/vue-shim.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module "*.vue" { - import type { DefineComponent } from "vue"; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const component: DefineComponent<{}, {}, any>; - export default component; -} diff --git a/examples/basic/tsconfig.json b/examples/basic/tsconfig.json deleted file mode 100644 index a07cb3f..0000000 --- a/examples/basic/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "lib": ["es2023"], - "module": "esnext", - "moduleResolution": "bundler", - "moduleDetection": "force", - "types": ["node"], - "strict": true, - "noUnusedLocals": true, - "noEmit": true, - "allowImportingTsExtensions": true, - "esModuleInterop": true, - "isolatedModules": true, - "skipLibCheck": true, - "jsx": "preserve" - }, - "include": ["src/**/*.ts", "src/**/*.vue", "vite.config.ts"] -} diff --git a/examples/basic/vite.config.ts b/examples/basic/vite.config.ts deleted file mode 100644 index eaf5c7a..0000000 --- a/examples/basic/vite.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { defineConfig } from "vite"; -import vue from "@vitejs/plugin-vue"; -import { fileURLToPath } from "node:url"; - -const here = fileURLToPath(new URL(".", import.meta.url)); - -// Build the example as a Node ESM bundle. SFCs are compiled by -// @vitejs/plugin-vue; runtime deps (vue, @vue-tui/runtime, chalk, …) stay -// external so Node resolves them from node_modules at startup. -export default defineConfig({ - plugins: [vue()], - build: { - target: "node22", - outDir: "dist", - emptyOutDir: true, - minify: false, - lib: { - entry: `${here}src/main.ts`, - formats: ["es"], - fileName: () => "game.mjs", - }, - rollupOptions: { - // Bundle anything resolved as a relative / absolute path (the .vue - // file + its `?vue` virtual modules); externalize bare specifiers. - external: (id) => !id.startsWith(".") && !id.startsWith("/") && !id.startsWith("\0"), - }, - }, -}); diff --git a/packages/cli/src/dev.ts b/packages/cli/src/dev.ts index 26e85d4..6c54d3e 100644 --- a/packages/cli/src/dev.ts +++ b/packages/cli/src/dev.ts @@ -17,6 +17,7 @@ export async function dev(entry?: string) { const server = await createServer({ plugins: [vueTuiDevPlugin({ entry })], + logLevel: "silent", }); await server.listen(); @@ -55,8 +56,16 @@ export async function dev(entry?: string) { pm.spawn(); + // Ignore reload requests during startup — the initial WS connection + // may trigger vite:beforeFullReload before the app is ready + let acceptReloads = false; + setTimeout(() => { + acceptReloads = true; + }, 3000); + // Listen for full reload requests from child server.hot.on("vue-tui:request-reload", async () => { + if (!acceptReloads) return; const newPath = await extractBundle(clientEnv.memoryFiles, outDir); pm.setBundlePath(newPath); pm.restart(); diff --git a/packages/cli/src/process-manager.ts b/packages/cli/src/process-manager.ts index a138698..f552268 100644 --- a/packages/cli/src/process-manager.ts +++ b/packages/cli/src/process-manager.ts @@ -9,7 +9,22 @@ export interface ProcessManagerOptions { } const loaderUrl = new URL("./hmr-loader.mjs", import.meta.url).href; -const loaderBootstrap = `data:text/javascript,import{register}from"node:module";register(${JSON.stringify(loaderUrl)})`; + +// Bootstrap script: register HMR loader hooks + silence Vite/Vue console noise +const loaderBootstrap = `data:text/javascript,${encodeURIComponent(` +import{register}from"node:module"; +register(${JSON.stringify(loaderUrl)}); + +// Intercept all console methods to suppress Vite HMR client and Vue warn noise +for (const method of ["log", "info", "warn", "error", "debug"]) { + const orig = console[method]; + console[method] = (...args) => { + const first = typeof args[0] === "string" ? args[0] : ""; + if (first.includes("[vite]") || first.includes("[Vue warn]")) return; + orig.apply(console, args); + }; +} +`)}`; export function createProcessManager(options: ProcessManagerOptions) { let child: ChildProcess | null = null;