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) <noreply@anthropic.com>
This commit is contained in:
@@ -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:"
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { shallowRef } from "vue";
|
||||
import { Box, Text, useFocusManager, useInput } from "@vue-tui/runtime";
|
||||
import Item from "./Item.vue";
|
||||
|
||||
const items = ["apple", "banana", "orange", "grape", "watermelon"];
|
||||
const selected = shallowRef<null | string>(null);
|
||||
|
||||
const focusManager = useFocusManager();
|
||||
|
||||
useInput((input, key) => {
|
||||
if (key.upArrow) {
|
||||
focusManager.focusPrevious();
|
||||
} else if (key.downArrow) {
|
||||
focusManager.focusNext();
|
||||
} else if (key.return) {
|
||||
console.log("Selected:", focusManager.activeId);
|
||||
selected.value = focusManager.activeId;
|
||||
}
|
||||
if (input === "q") {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Box>
|
||||
<Item v-for="item in items" :key="item" :id="item" :label="item" />
|
||||
<Text>You selected: {{ focusManager.activeId }}</Text>
|
||||
</Box>
|
||||
</template>
|
||||
@@ -1,17 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { Box, Text, useFocus } from "@vue-tui/runtime";
|
||||
const props = defineProps<{
|
||||
id: string;
|
||||
label: string;
|
||||
}>();
|
||||
|
||||
const focusCtx = useFocus({ id: props.id });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Box>
|
||||
<Text :color="focusCtx.isFocused.value ? 'cyan' : 'undefined'"
|
||||
>{{ focusCtx.isFocused.value ? ">" : " " }} {{ props.label }}</Text
|
||||
>
|
||||
</Box>
|
||||
</template>
|
||||
@@ -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();
|
||||
Vendored
-6
@@ -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;
|
||||
}
|
||||
@@ -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"]
|
||||
}
|
||||
@@ -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"),
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user