尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Nuxt Kit 日志与终端交互指南:useLogger 与 useTerminal 源码级解析

Nuxt Kit 日志与终端交互指南:useLogger 与 useTerminal 源码级解析 Nuxt Kit 日志与终端交互指南useLogger 与 useTerminal 源码级解析【免费下载链接】nuxtthe full-stack Vue framework项目地址: https://gitcode.com/GitHub_Trending/nu/nuxtNuxt Kitnuxt/kit为模块与工具链开发提供了面向构建期的日志与终端交互能力useLogger基于 consola 为主线结合 logger.ts、terminal.ts 的实现与测试帮助你写出日志风格统一、可静默、能与交互终端优雅共存的 Nuxt 模块。阅读完本文你将掌握模块内如何获取带 tag 的日志器并控制日志级别NuxtLogger/NuxtLoggerOptions的核心字段含义以及在nuxt devTUI 与纯脚本环境两种场景下如何使用useTerminal完成交互式确认、长任务展示与驻留通知并理解其自动降级机制。useLogger获取带增强能力的日志器Nuxt 在构建期与模块上下文中维护着一个全局 logger 实例任何模块都可以通过useLogger获取它。文档将其定位为 a logger instance with extra features底层实现位于 logger.ts。类型签名import { defineNuxtModule, useLogger } from nuxt/kit function useLogger (tag?: string, options?: NuxtLoggerOptions): NuxtLogger两个参数均为可选参数说明tag字符串标签会作为后缀追加到每一条日志消息上渲染在时间戳附近用于在众多模块日志中快速定位来源options日志器选项如level、reporters、defaults、formatOptions等字段详见下文从 logger.ts 实现 可以看出其行为非常直接export const logger: NuxtLogger consola export function useLogger (tag?: string, options: NuxtLoggerOptions {}): NuxtLogger { return tag ? logger.create(options).withTag(tag) : logger }即不传tag时直接返回全局共享的logger它就是consola本身传入tag时基于传入的options派生create一个新实例再调用withTag(tag)让该实例的所有消息带上 tag。对应的单测见 logger.test.ts覆盖了无 tag、有 tag、有 tagoptions 三种调用形态。最小用法import { defineNuxtModule, useLogger } from nuxt/kit export default defineNuxtModule({ setup (options, nuxt) { const logger useLogger(my-module) logger.info(Hello from my module!) }, })输出时该行信息会带有my-module标签方便在构建日志中按模块名检索与过滤。结合模块 options 控制日志级别模块常暴露quiet之类的选项让用户关闭详细输出此时可将用户选项映射为 logger 的数字级别import { defineNuxtModule, useLogger } from nuxt/kit export default defineNuxtModule({ setup (options, nuxt) { const logger useLogger(my-module, { level: options.quiet ? 0 : 3 }) logger.info(Hello from my module!) }, })源码中的类型注释对级别范围给出了明确界定NuxtLogLevel是0 | 1 | 2 | 3 | 4 | 5的数值阈值0对应最严格的 fatal/error5对应最详细的 trace见 logger.ts 类型定义。因此在quiet: true时把level置为0即可抑制 info 这类常规输出。NuxtLogger与NuxtLoggerOptions核心结构虽然NuxtLogger在结构上由consola满足Structurally satisfied byconsola但 Nuxt 只对外保证下述成员。接口将每种日志类型都暴露为一个函数式属性并附带了大量派生与治理能力。export interface NuxtLogger extends RecordNuxtLogType, NuxtLogFn { level: NuxtLogLevel options: NuxtLoggerOptions create: (options: NuxtLoggerOptions) NuxtLogger withTag: (tag: string) NuxtLogger withDefaults: (defaults: NuxtLogInput) NuxtLogger addReporter: (reporter: NuxtLogReporter) unknown removeReporter: (reporter: NuxtLogReporter) unknown setReporters: (reporters: NuxtLogReporter[]) unknown wrapConsole: () void restoreConsole: () void wrapAll: () void restoreAll: () void pauseLogs: () void resumeLogs: () void prompt(message: string, options?: NuxtPromptOptions): Promiseany }其中NuxtLogType定义了消息类别silent | fatal | error | warn | log | info | success | fail | ready | start | box | debug | trace | verbose因此可直接调用logger.warn、logger.error、logger.success、logger.start、logger.box等见 日志类型定义。每条日志函数NuxtLogFn既接受普通字符串参数也接受结构化的NuxtLogInput可包含level、tag、type、message、additional、args、date并提供raw方法用于原样输出、跳过格式化NuxtLogInput 定义。NuxtLoggerOptions的完整字段与含义如下源码注释字段类型作用levelNuxtLogLevel当前详细程度阈值可赋值为0~5以改变输出内容reportersNuxtLogReporter[]日志报告器每条解析完成的NuxtLogObject都会交给它们渲染defaultsNuxtLogInput应用到每条消息的默认日志字段typesRecordNuxtLogType, NuxtLogInput按日志类型区分的默认字段throttlenumber相同消息可重复出现多少次后触发节流throttleMinnumber被节流的消息在多少毫秒内被抑制stdout/stderrNodeJS.WriteStream输出流mockFn(type, defaults) fn替换每个日志方法供测试使用prompt(message, options) Promiseany替换 prompt 实现formatOptions对象格式化选项columns、date、colors、compact、errorLevel等与 Nuxt 全局日志级别配置的衔接在用户侧Nuxt 提供了build.logLevel配置项来全局调节构建日志的详细程度。其在 schema 的实现 中做了校验与默认值推导只允许silent、info、verbose三个字符串取值非法值会触发 schema 诊断未显式设置时根据是否处于测试test模式默认为silent或info。模块作者可以参考这一层级划分来决定自身日志何时属于verbose级别从而与用户全局设置协同。useTerminal与交互式终端协同的原语集模块开发中常见的痛点是nuxt dev已经接管了终端 UI模块若直接写process.stdout或发起交互式提问输出会被冲刷、问题无法作答。useTerminal解决的就是这个问题——当 Nuxt 运行在交互式宿主interactive host例如nuxt dev的终端 UI中时把 prompt、任务与通知移交给宿主集中渲染否则自动降级为普通日志输出见 terminal.ts 的说明。类型签名import { defineNuxtModule, useTerminal } from nuxt/kit function useTerminal (): NuxtTerminal interface NuxtTerminal { readonly interactive: boolean withTerminal: T(work: () PromiseT) PromiseT prompt: (message: string, options?: NuxtPromptOptions) Promiseany startTask: (label: string) NuxtTerminalTask notify: (notification: NuxtTerminalNotification) NuxtTerminalNotice }成员说明成员说明interactive是否存在交互式宿主。为false时下面的原语改为向当前进程的流输出日志withTerminal在work执行期间借用终端挂起宿主的 UI 并释放stdin允许work直接读写终端。并发调用者会被串行化从借用内部发起的嵌套调用会立即执行prompt向用户提问prompt 打开期间持续借用终端。接受与logger.prompt相同的选项startTask启动一个长时间运行的任务在宿主的 status 面上渲染。用task.stop(message?, outcome?)结束或用task.update(label)修改标题notify展示一条消息并停留在屏幕上直到用户确认或调用notice.dismiss()。notice.dismissed在通知消失被确认或收回后完成完整示例安装确认 进度任务import { defineNuxtModule, useTerminal } from nuxt/kit declare function runPackageInstall (name: string): Promisevoid export default defineNuxtModule({ async setup () { const terminal useTerminal() const install await terminal.prompt(Do you want to install my-module?, { type: confirm }) if (!install) { return } const task terminal.startTask(Installing my-module...) // run your actual task await runPackageInstall(my-module) task.stop(Installed my-module) }, })宿主探测与版本契约useTerminal是否处于交互模式取决于useTerminalHost()能否在globalThis上找到宿主。宿主通过Symbol.for(nuxt:terminal-host)发布契约而非通过模块导入传递——因为同一个进程里经常存在多份nuxt/kit/nuxt/cli副本符号化全局变量是最稳妥的通信渠道terminal-host.ts 说明。export interface TerminalHost { version: 1 withTerminal: T(work: () PromiseT) PromiseT startTask: (label: string) TerminalHostTask notify?: (notification: TerminalHostNotification) TerminalHostNotice } const TERMINAL_HOST_KEY Symbol.for(nuxt:terminal-host) export function useTerminalHost (): TerminalHost | undefined { const host (globalThis as Recordsymbol, unknown)[TERMINAL_HOST_KEY] as TerminalHost | undefined if (!host || host.version ! 1 || typeof host.withTerminal ! function || typeof host.startTask ! function) { return undefined } return host }探测逻辑做了三重防御宿主必须是version: 1、必须实现withTerminal、必须实现startTask否则一律视为无宿主。任何一项不满足例如未来版本号变更、部分实现都会让useTerminal自动回退到日志模式——对应的测试用例是 should ignore a host with an incompatible versionterminal.test.ts。无宿主时的降级实现有交互宿主时四个原语全部转交宿主无宿主时 terminal.ts 会做如下降级withTerminal(work)直接执行work()不加任何包装prompt(message, options)直接调用logger.prompt(message, options)走标准 CLI 问答startTask(label)先logger.start(label)输出开始行task.update再发一条start行task.stop只执行一次内部用stopped标志防止重复成功时走logger.success(message)失败outcome failure时走logger.fail(message)notify(notification)当宿主未实现notify或完全无宿主时用logger.box把title与message以空行拼接成一个信息框并立即 resolvedismissednotice.dismiss()为空操作。测试如何验证双模式行为terminal.test.ts 对两种模式都做了细致覆盖可作为理解契约的参考无宿主withTerminal直接运行 work、interactive为falseprompt透传给logger.promptstartTask会依次触发logger.start/logger.success且重复stop只记录一次测试 should log task progress when no host is present有宿主prompt严格按照[borrow, prompt, release]的顺序在借用周期内执行startTask、notify直接委托宿主而不再触碰 logger测试 should delegate to the host、should delegate to the host when notify is implemented。与 Nuxt 模块生态的配合建议在实际的模块实现中把三者组合起来是最常见的模式setup阶段先useLogger(your-module)统一打点遇到需要用户决策安装依赖、开启实验特性、覆盖文件的地方再用useTerminal().prompt长耗时步骤用startTask渲染进度关键安全信息如令牌、验证码用notify驻留展示直到用户确认。几点来自实现细节的建议在插件中优先注入useLogger(module-name, options)Nuxt 插件与模块都可以从nuxt/kit直接导入这些 API导出见 index.tstag 能显著提升多模块场景下的日志可读性不要直接写process.stdout/process.stderr在 TUI 宿主任职期间这些流可能已被接管或缓冲使用withTerminal借用以获得对 stdin/stdout 的直接访问权是源码注释明确推荐的做法任务必须保证恰好一次stop降级模式下stop只会输出一次成功/失败消息失败任务请显式传入outcome: failure否则会被渲染为成功notify的title与message是分开的字段宿主可用level: warn等呈现差异降级时二者以空行拼合进logger.box。关于模块开发的整体结构defineNuxtModule、setup、选项解析可继续阅读 模块解剖指南其余 Kit API 的完整索引见 Nuxt Kit API 文档 对应的各个分类页。结语useLogger与useTerminal将 Nuxt 模块的输出体验收敛为两层清晰契约日志层统一走基于 consola 的NuxtLogger带 tag、带级别、可被 reporters 接管交互层则通过useTerminal与nuxt dev的 TUI 宿主解耦宿主存在则协同渲染宿主缺失则自动降级为普通日志。这种同一定义、双模式执行的设计宿主契约见 terminal-host.ts降级逻辑与测试见 terminal.ts 与 terminal.test.ts让模块无论运行在交互式开发终端还是 CI/脚本环境都能提供一致且不丢信息的输出。【免费下载链接】nuxtthe full-stack Vue framework项目地址: https://gitcode.com/GitHub_Trending/nu/nuxt创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表