From 9f5f1f9f04f49777603514b9e4ef833584f4dea7 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Sat, 25 Apr 2026 22:23:33 +0900 Subject: [PATCH 1/4] Wire logging into init templates Add startup wiring for generated Nitro and Next.js applications so their LogTape configuration modules are actually loaded before Fedify handles requests. Nitro projects now get a server plugin, while Next.js projects get an instrumentation register hook scoped to the Node.js runtime. Add regression coverage for both framework initializers and document the fix in the changelog. Fixes https://github.com/fedify-dev/fedify/issues/725 Assisted-by: Codex:gpt-5.5 --- CHANGES.md | 10 +++++ .../src/templates/next/instrumentation.ts.tpl | 5 +++ .../nitro/server/plugins/logging.ts.tpl | 3 ++ packages/init/src/webframeworks.test.ts | 45 +++++++++++++++++++ packages/init/src/webframeworks.ts | 4 ++ 5 files changed, 67 insertions(+) create mode 100644 packages/init/src/templates/next/instrumentation.ts.tpl create mode 100644 packages/init/src/templates/nitro/server/plugins/logging.ts.tpl create mode 100644 packages/init/src/webframeworks.test.ts diff --git a/CHANGES.md b/CHANGES.md index 674ed76ad..f02309c84 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,16 @@ Version 2.0.15 To be released. +### @fedify/init + + - Fixed the Nitro and Next.js project templates so their generated + *logging.ts* files are loaded during server startup. Nitro projects now + get a server plugin that imports the LogTape configuration, and Next.js + projects get an *instrumentation.ts* `register()` hook that imports it in + the Node.js runtime before Fedify handles requests. [[#725]] + +[#725]: https://github.com/fedify-dev/fedify/issues/725 + Version 2.0.14 -------------- diff --git a/packages/init/src/templates/next/instrumentation.ts.tpl b/packages/init/src/templates/next/instrumentation.ts.tpl new file mode 100644 index 000000000..6d782f34f --- /dev/null +++ b/packages/init/src/templates/next/instrumentation.ts.tpl @@ -0,0 +1,5 @@ +export async function register() { + if (process.env.NEXT_RUNTIME === "nodejs") { + await import("./logging"); + } +} diff --git a/packages/init/src/templates/nitro/server/plugins/logging.ts.tpl b/packages/init/src/templates/nitro/server/plugins/logging.ts.tpl new file mode 100644 index 000000000..32adf599a --- /dev/null +++ b/packages/init/src/templates/nitro/server/plugins/logging.ts.tpl @@ -0,0 +1,3 @@ +import "../logging"; + +export default function setupLogging() {} diff --git a/packages/init/src/webframeworks.test.ts b/packages/init/src/webframeworks.test.ts new file mode 100644 index 000000000..4439514e6 --- /dev/null +++ b/packages/init/src/webframeworks.test.ts @@ -0,0 +1,45 @@ +import { ok } from "node:assert/strict"; +import test from "node:test"; +import webFrameworks from "./webframeworks.ts"; + +test("Nitro template loads LogTape during server startup", async () => { + const { files } = await webFrameworks.nitro.init({ + projectName: "test-app", + dir: ".", + command: "init", + packageManager: "npm", + kvStore: "in-memory", + messageQueue: "in-process", + webFramework: "nitro", + testMode: false, + dryRun: true, + }); + + ok(files); + ok("server/plugins/logging.ts" in files); + const plugin = files["server/plugins/logging.ts"]; + ok(plugin); + ok(plugin.includes('import "../logging";')); +}); + +test("Next.js template loads LogTape through instrumentation", async () => { + const { files } = await webFrameworks.next.init({ + projectName: "test-app", + dir: ".", + command: "init", + packageManager: "npm", + kvStore: "in-memory", + messageQueue: "in-process", + webFramework: "next", + testMode: false, + dryRun: true, + }); + + ok(files); + ok("instrumentation.ts" in files); + const instrumentation = files["instrumentation.ts"]; + ok(instrumentation); + ok(instrumentation.includes("export async function register()")); + ok(instrumentation.includes("NEXT_RUNTIME")); + ok(instrumentation.includes('await import("./logging")')); +}); diff --git a/packages/init/src/webframeworks.ts b/packages/init/src/webframeworks.ts index f77cd4dfa..de4fa1561 100644 --- a/packages/init/src/webframeworks.ts +++ b/packages/init/src/webframeworks.ts @@ -300,6 +300,9 @@ const webFrameworks: WebFrameworks = { federationFile: "server/federation.ts", loggingFile: "server/logging.ts", files: { + "server/plugins/logging.ts": await readTemplate( + "nitro/server/plugins/logging.ts", + ), "server/middleware/federation.ts": await readTemplate( "nitro/server/middleware/federation.ts", ), @@ -338,6 +341,7 @@ const webFrameworks: WebFrameworks = { federationFile: "federation/index.ts", loggingFile: "logging.ts", files: { + "instrumentation.ts": await readTemplate("next/instrumentation.ts"), "middleware.ts": await readTemplate("next/middleware.ts"), ...(pm !== "deno" ? { From 79443df343b91ed2a3768d41036cdb69fe99ad1c Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Sat, 25 Apr 2026 23:47:19 +0900 Subject: [PATCH 2/4] Guard Next runtime checks Avoid reading process.env directly in the generated Next.js instrumentation hook. Using globalThis.process?.env keeps the hook safe when instrumentation is evaluated outside the Node.js runtime, while still loading the LogTape setup for Node.js requests. Updates the initializer regression test to assert the guarded runtime check. Review comment: https://github.com/fedify-dev/fedify/pull/727#discussion_r3142038417 Assisted-by: Codex:gpt-5.5 --- packages/init/src/templates/next/instrumentation.ts.tpl | 2 +- packages/init/src/webframeworks.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/init/src/templates/next/instrumentation.ts.tpl b/packages/init/src/templates/next/instrumentation.ts.tpl index 6d782f34f..b7b96a4fd 100644 --- a/packages/init/src/templates/next/instrumentation.ts.tpl +++ b/packages/init/src/templates/next/instrumentation.ts.tpl @@ -1,5 +1,5 @@ export async function register() { - if (process.env.NEXT_RUNTIME === "nodejs") { + if (globalThis.process?.env.NEXT_RUNTIME === "nodejs") { await import("./logging"); } } diff --git a/packages/init/src/webframeworks.test.ts b/packages/init/src/webframeworks.test.ts index 4439514e6..3b2add643 100644 --- a/packages/init/src/webframeworks.test.ts +++ b/packages/init/src/webframeworks.test.ts @@ -40,6 +40,6 @@ test("Next.js template loads LogTape through instrumentation", async () => { const instrumentation = files["instrumentation.ts"]; ok(instrumentation); ok(instrumentation.includes("export async function register()")); - ok(instrumentation.includes("NEXT_RUNTIME")); + ok(instrumentation.includes("globalThis.process?.env.NEXT_RUNTIME")); ok(instrumentation.includes('await import("./logging")')); }); From 65ced2235bf59220b91bfea234c1b498e13918e7 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Sun, 26 Apr 2026 00:00:25 +0900 Subject: [PATCH 3/4] Restore Next runtime splitting Use the documented process.env.NEXT_RUNTIME guard in the generated Next.js instrumentation hook. Next.js relies on this pattern for runtime-specific imports, so the Node-only logging module is not pulled into Edge bundles. Updates the initializer regression test to assert the documented runtime check. Review comment: https://github.com/fedify-dev/fedify/pull/727#discussion_r3142132840 Assisted-by: Codex:gpt-5.5 --- packages/init/src/templates/next/instrumentation.ts.tpl | 2 +- packages/init/src/webframeworks.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/init/src/templates/next/instrumentation.ts.tpl b/packages/init/src/templates/next/instrumentation.ts.tpl index b7b96a4fd..6d782f34f 100644 --- a/packages/init/src/templates/next/instrumentation.ts.tpl +++ b/packages/init/src/templates/next/instrumentation.ts.tpl @@ -1,5 +1,5 @@ export async function register() { - if (globalThis.process?.env.NEXT_RUNTIME === "nodejs") { + if (process.env.NEXT_RUNTIME === "nodejs") { await import("./logging"); } } diff --git a/packages/init/src/webframeworks.test.ts b/packages/init/src/webframeworks.test.ts index 3b2add643..df25d74af 100644 --- a/packages/init/src/webframeworks.test.ts +++ b/packages/init/src/webframeworks.test.ts @@ -40,6 +40,6 @@ test("Next.js template loads LogTape through instrumentation", async () => { const instrumentation = files["instrumentation.ts"]; ok(instrumentation); ok(instrumentation.includes("export async function register()")); - ok(instrumentation.includes("globalThis.process?.env.NEXT_RUNTIME")); + ok(instrumentation.includes("process.env.NEXT_RUNTIME")); ok(instrumentation.includes('await import("./logging")')); }); From ec1edc764757c600e641d65787ffa86c70ce78f3 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Sun, 26 Apr 2026 00:23:32 +0900 Subject: [PATCH 4/4] Add a PR link to the changelog --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index f02309c84..dce8915ed 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,9 +14,10 @@ To be released. *logging.ts* files are loaded during server startup. Nitro projects now get a server plugin that imports the LogTape configuration, and Next.js projects get an *instrumentation.ts* `register()` hook that imports it in - the Node.js runtime before Fedify handles requests. [[#725]] + the Node.js runtime before Fedify handles requests. [[#725], [#727]] [#725]: https://github.com/fedify-dev/fedify/issues/725 +[#727]: https://github.com/fedify-dev/fedify/pull/727 Version 2.0.14