fix(build): keep the server logger out of client bundles
CI / check (push) Successful in 33s
CI / tests-imaging-browsers (push) Successful in 1m50s
CI / tests-integration (push) Successful in 2m28s
CI / tests-unit (push) Successful in 3m6s
CI / tests-quality (push) Successful in 1m40s
CI / tests-ui (push) Successful in 5m56s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m58s
CI / check (push) Successful in 33s
CI / tests-imaging-browsers (push) Successful in 1m50s
CI / tests-integration (push) Successful in 2m28s
CI / tests-unit (push) Successful in 3m6s
CI / tests-quality (push) Successful in 1m40s
CI / tests-ui (push) Successful in 5m56s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m58s
The production webpack build failed with UnhandledSchemeError: client components imported @/lib/logger, which binds pino, AsyncLocalStorage (node:async_hooks), node:crypto and node:fs — and validates server env on import. The UI fixture aliased those modules, so the harness and tests never hit it. - add src/lib/browser-log.ts: browser-safe logger with the same interface; errors are forwarded to /api/diagnostics/errors via reportBrowserError - guard src/lib/logger.ts with server-only and drop its now-dead browser branches - switch the 11 client components/hooks to @/lib/browser-log Verified with the Dockerfile's production build (pnpm run build) and the full vitest suite.
This commit is contained in:
1 parent
fb470123c3
commit
c15177a52e
13 files changed
+71
-42
No files matched your search
@@ -0,0 +1,53 @@
|
||||
import { reportBrowserError } from "./browser-errors";
|
||||
|
||||
/**
|
||||
* Browser counterpart of `@/lib/logger` for client components.
|
||||
*
|
||||
* The server logger pulls in pino, AsyncLocalStorage, node:crypto and the
|
||||
* filesystem, so it must never end up in a client bundle. Client components
|
||||
* import this module instead — same interface (debug/info/warn/error), but
|
||||
* console-based. Errors are also forwarded to the diagnostics endpoint so
|
||||
* they surface in housekeeping, and `error()` returns the error reference id.
|
||||
*/
|
||||
|
||||
function formatMeta(meta: Record<string, unknown> = {}): string {
|
||||
const keys = Object.keys(meta);
|
||||
if (keys.length === 0) return "";
|
||||
return keys
|
||||
.map((k) => {
|
||||
const v = meta[k];
|
||||
return `${k}=${v instanceof Error ? v.message : String(v)}`;
|
||||
})
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
const canReport = typeof window !== "undefined";
|
||||
|
||||
export const logger = {
|
||||
debug(message: string, meta: Record<string, unknown> = {}): void {
|
||||
console.debug(`[debug] ${message} ${formatMeta(meta)}`.trim());
|
||||
},
|
||||
info(message: string, meta: Record<string, unknown> = {}): void {
|
||||
console.info(`[info] ${message} ${formatMeta(meta)}`.trim());
|
||||
},
|
||||
warn(message: string, meta: Record<string, unknown> = {}): void {
|
||||
console.warn(`[warn] ${message} ${formatMeta(meta)}`.trim());
|
||||
},
|
||||
error(message: string, meta: Record<string, unknown> = {}): string {
|
||||
console.error(`[error] ${message} ${formatMeta(meta)}`.trim());
|
||||
if (!canReport) return "";
|
||||
const error =
|
||||
meta.err instanceof Error
|
||||
? meta.err
|
||||
: meta.error instanceof Error
|
||||
? meta.error
|
||||
: new Error(
|
||||
typeof meta.err === "string"
|
||||
? meta.err
|
||||
: typeof meta.error === "string"
|
||||
? meta.error
|
||||
: message,
|
||||
);
|
||||
return reportBrowserError(error) ?? "";
|
||||
},
|
||||
};
|
||||
+7
-31
@@ -1,3 +1,4 @@
|
||||
import "server-only";
|
||||
import pino from "pino";
|
||||
import { env } from "@/env";
|
||||
import { captureCmsError } from "./error-monitor";
|
||||
@@ -5,9 +6,6 @@ import { getOperationContext } from "./foundation/request-context";
|
||||
|
||||
type LogLevel = "debug" | "info" | "warn" | "error";
|
||||
|
||||
const isBrowser =
|
||||
typeof window !== "undefined" && typeof window.console !== "undefined";
|
||||
|
||||
const level: LogLevel =
|
||||
(env.LOG_LEVEL as LogLevel | undefined) ??
|
||||
(env.NODE_ENV === "production" ? "info" : "debug");
|
||||
@@ -35,45 +33,23 @@ export function generateRequestId(): string {
|
||||
return `${Date.now().toString(36)}-${requestIdCounter.toString(36)}`;
|
||||
}
|
||||
|
||||
function formatMeta(meta: Record<string, unknown> = {}): string {
|
||||
const keys = Object.keys(meta);
|
||||
if (keys.length === 0) return "";
|
||||
return keys
|
||||
.map((k) => {
|
||||
const v = meta[k];
|
||||
return `${k}=${v instanceof Error ? v.message : String(v)}`;
|
||||
})
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
/** Universal logger: pino on server, console in browser. Same interface everywhere. */
|
||||
/**
|
||||
* Server-side logger — pino with request context, errors are persisted by the
|
||||
* CMS error monitor. Client components must use `@/lib/browser-log` instead:
|
||||
* this module is guarded by `server-only` and binds pino, AsyncLocalStorage
|
||||
* and the filesystem, so it can never be part of a client bundle.
|
||||
*/
|
||||
export const logger = {
|
||||
debug(message: string, meta: Record<string, unknown> = {}): void {
|
||||
if (isBrowser) {
|
||||
console.debug(`[debug] ${message} ${formatMeta(meta)}`.trim());
|
||||
return;
|
||||
}
|
||||
pinoLogger.debug({ ...meta, ...getOperationContext() }, message);
|
||||
},
|
||||
info(message: string, meta: Record<string, unknown> = {}): void {
|
||||
if (isBrowser) {
|
||||
console.info(`[info] ${message} ${formatMeta(meta)}`.trim());
|
||||
return;
|
||||
}
|
||||
pinoLogger.info({ ...meta, ...getOperationContext() }, message);
|
||||
},
|
||||
warn(message: string, meta: Record<string, unknown> = {}): void {
|
||||
if (isBrowser) {
|
||||
console.warn(`[warn] ${message} ${formatMeta(meta)}`.trim());
|
||||
return;
|
||||
}
|
||||
pinoLogger.warn({ ...meta, ...getOperationContext() }, message);
|
||||
},
|
||||
error(message: string, meta: Record<string, unknown> = {}): string {
|
||||
if (isBrowser) {
|
||||
console.error(`[error] ${message} ${formatMeta(meta)}`.trim());
|
||||
return "";
|
||||
}
|
||||
const error =
|
||||
meta.err instanceof Error
|
||||
? meta.err
|
||||
|
||||
Reference in new issue
Block a user