From 1692097bba744a8371c9bcfbb5fd9f7faef471eb Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Sat, 25 Apr 2026 15:39:41 +0900 Subject: [PATCH] Wire Nuxt init logging Generate a Nuxt-specific logging template that exports the LogTape configuration promise without top-level await. Add a Nitro server plugin to await that promise during startup so generated Nuxt apps actually enable Fedify logging. Allow framework initializers to override the default logging template and cover the Nuxt wiring with a generated-file regression test. Fixes https://github.com/fedify-dev/fedify/issues/724 Assisted-by: Codex:gpt-5.5 --- packages/init/src/action/configs.test.ts | 56 +++++++++++++++++++ packages/init/src/action/templates.ts | 6 +- .../src/templates/nuxt/server/logging.ts.tpl | 23 ++++++++ .../nuxt/server/plugins/logging.ts.tpl | 5 ++ packages/init/src/types.ts | 2 + packages/init/src/webframeworks/nuxt.ts | 4 ++ 6 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 packages/init/src/templates/nuxt/server/logging.ts.tpl create mode 100644 packages/init/src/templates/nuxt/server/plugins/logging.ts.tpl diff --git a/packages/init/src/action/configs.test.ts b/packages/init/src/action/configs.test.ts index c63d31730..ef6190fcd 100644 --- a/packages/init/src/action/configs.test.ts +++ b/packages/init/src/action/configs.test.ts @@ -7,6 +7,7 @@ import { message } from "@optique/core"; import { kvStores, messageQueues } from "../lib.ts"; import type { InitCommandData } from "../types.ts"; import bareBonesDescription from "../webframeworks/bare-bones.ts"; +import nuxtDescription from "../webframeworks/nuxt.ts"; import { loadDenoConfig } from "./configs.ts"; import { patchFiles } from "./patch.ts"; @@ -133,6 +134,28 @@ test("patchFiles creates a Biome config matching the npm package version", async } }); +test("patchFiles wires Nuxt logging through a Nitro plugin", async () => { + const dir = await mkdtemp(join(tmpdir(), "fedify-init-nuxt-")); + + try { + const data = await createNuxtNpmInitData(dir); + await patchFiles(data); + + const logging = await readFile(join(dir, "server/logging.ts"), "utf8"); + const plugin = await readFile( + join(dir, "server/plugins/logging.ts"), + "utf8", + ); + + assert.match(logging, /export default configure\(/); + assert.doesNotMatch(logging, /await configure\(/); + assert.match(plugin, /import loggingConfigured from "\.\.\/logging";/); + assert.match(plugin, /await loggingConfigured;/); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); + async function createNpmInitData(dir: string): Promise { const initializer = await bareBonesDescription.init({ command: "init", @@ -166,6 +189,39 @@ async function createNpmInitData(dir: string): Promise { return data; } +async function createNuxtNpmInitData(dir: string): Promise { + const initializer = await nuxtDescription.init({ + command: "init", + projectName: "example", + packageManager: "npm", + webFramework: "nuxt", + kvStore: "in-memory", + messageQueue: "in-process", + dryRun: false, + allowNonEmpty: false, + testMode: false, + dir, + }); + + const data = { + command: "init", + projectName: "example", + packageManager: "npm", + webFramework: "nuxt", + kvStore: "in-memory", + messageQueue: "in-process", + dryRun: false, + allowNonEmpty: false, + testMode: false, + dir, + initializer, + kv: kvStores["in-memory"], + mq: messageQueues["in-process"], + env: {}, + } satisfies InitCommandData; + return data; +} + function getSchemaVersion(schema: string): string { const match = schema.match(/\/schemas\/(\d+\.\d+\.\d+)\//); assert.ok(match, `Unexpected Biome schema URL: ${schema}`); diff --git a/packages/init/src/action/templates.ts b/packages/init/src/action/templates.ts index 8e489c11e..813c0d327 100644 --- a/packages/init/src/action/templates.ts +++ b/packages/init/src/action/templates.ts @@ -38,9 +38,11 @@ export const loadFederation = async ( * @param param0 - Destructured object containing the project name * @returns The complete logging configuration file content as a string */ -export const loadLogging = async ({ projectName }: InitCommandData) => +export const loadLogging = async ( + { projectName, initializer }: InitCommandData, +) => pipe( - await readTemplate("defaults/logging.ts"), + await readTemplate(initializer.loggingTemplate ?? "defaults/logging.ts"), replace(/\/\* project name \*\//, JSON.stringify(projectName)), ); diff --git a/packages/init/src/templates/nuxt/server/logging.ts.tpl b/packages/init/src/templates/nuxt/server/logging.ts.tpl new file mode 100644 index 000000000..3eabb10c4 --- /dev/null +++ b/packages/init/src/templates/nuxt/server/logging.ts.tpl @@ -0,0 +1,23 @@ +import { configure, getConsoleSink } from "@logtape/logtape"; +import { AsyncLocalStorage } from "node:async_hooks"; + +export default configure({ + contextLocalStorage: new AsyncLocalStorage(), + sinks: { + console: getConsoleSink(), + }, + filters: {}, + loggers: [ + { + category: /* project name */, + lowestLevel: "debug", + sinks: ["console"], + }, + { category: "fedify", lowestLevel: "info", sinks: ["console"] }, + { + category: ["logtape", "meta"], + lowestLevel: "warning", + sinks: ["console"], + }, + ], +}); diff --git a/packages/init/src/templates/nuxt/server/plugins/logging.ts.tpl b/packages/init/src/templates/nuxt/server/plugins/logging.ts.tpl new file mode 100644 index 000000000..e52d96936 --- /dev/null +++ b/packages/init/src/templates/nuxt/server/plugins/logging.ts.tpl @@ -0,0 +1,5 @@ +import loggingConfigured from "../logging"; + +export default defineNitroPlugin(async () => { + await loggingConfigured; +}); diff --git a/packages/init/src/types.ts b/packages/init/src/types.ts index fb46c9f0e..479c184e9 100644 --- a/packages/init/src/types.ts +++ b/packages/init/src/types.ts @@ -78,6 +78,8 @@ export interface WebFrameworkInitializer { federationFile: string; /** Relative path where the logging configuration file will be created. */ loggingFile: string; + /** Optional template path for the logging configuration file. */ + loggingTemplate?: string; /** * Additional files to create, keyed by relative path to file content. * Do not use `".env"` as a key — use the {@link env} property instead so diff --git a/packages/init/src/webframeworks/nuxt.ts b/packages/init/src/webframeworks/nuxt.ts index 2e02f4187..083e6d672 100644 --- a/packages/init/src/webframeworks/nuxt.ts +++ b/packages/init/src/webframeworks/nuxt.ts @@ -19,9 +19,13 @@ const nuxtDescription: WebFrameworkDescription = { }, federationFile: "server/federation.ts", loggingFile: "server/logging.ts", + loggingTemplate: "nuxt/server/logging.ts", env: testMode ? { HOST: "127.0.0.1" } : {} as Record, files: { "nuxt.config.ts": await readTemplate("nuxt/nuxt.config.ts"), + "server/plugins/logging.ts": await readTemplate( + "nuxt/server/plugins/logging.ts", + ), ...(pm !== "deno" && { "eslint.config.ts": await readTemplate("defaults/eslint.config.ts"), }),