Skip to content

Commit 04968c2

Browse files
bjohansebasclaude
andcommitted
fix(client): replace webpack's logging runtime with a self-contained logger
webpack/lib/logging/runtime.js pulls tapable into the client bundle, and tapable compiles its hooks with new Function — an EvalError under a require-trusted-types-for 'script' CSP that killed the client's logging and surfaced spurious runtime errors in the overlay. The replacement is a level-gated console logger with byte-identical output (same prefix merging, same level gates, groups from the "log" level up), verified against the existing console snapshots. It also drops tapable and webpack's logging machinery from the bundle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent b8d7747 commit 04968c2

1 file changed

Lines changed: 74 additions & 8 deletions

File tree

client-src/utils/log.js

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,84 @@
1-
// @ts-expect-error -- no published types for this entry point
2-
import logger from "webpack/lib/logging/runtime.js";
1+
/* eslint-disable no-console -- this module is the console logger */
2+
// A self-contained level-gated console logger. webpack's logging runtime is
3+
// deliberately not used: it pulls tapable into the bundle, whose hook
4+
// compiler calls `new Function` — which throws under a
5+
// `require-trusted-types-for 'script'` Content Security Policy.
36

4-
const LOGGER_NAME = "webpack-dev-middleware";
5-
const DEFAULT_LEVEL = "info";
7+
const LOG_PREFIX = "[webpack-dev-middleware]";
68

79
/** @typedef {false | true | "none" | "error" | "warn" | "info" | "log" | "verbose"} LogLevel */
810

11+
const LEVELS = ["none", "error", "warn", "info", "log", "verbose"];
12+
13+
const DEFAULT_LEVEL = "info";
14+
15+
let currentLevel = DEFAULT_LEVEL;
16+
917
/**
10-
* @param {LogLevel} level log level (or `false` for off, `true` for default)
18+
* @param {LogLevel} level log level (or `false` for off, `true` for "log")
1119
*/
1220
export function setLogLevel(level) {
13-
logger.configureDefaultLogger({ level });
21+
if (level === false) {
22+
currentLevel = "none";
23+
} else if (level === true) {
24+
currentLevel = "log";
25+
} else if (LEVELS.includes(level)) {
26+
currentLevel = level;
27+
}
28+
}
29+
30+
/**
31+
* @param {string} level level of the message
32+
* @returns {boolean} true when the current level shows the message
33+
*/
34+
function enabled(level) {
35+
return LEVELS.indexOf(currentLevel) >= LEVELS.indexOf(level);
1436
}
1537

16-
setLogLevel(DEFAULT_LEVEL);
38+
/**
39+
* Prefix like webpack's logger: merged into the first argument when it is a
40+
* string, passed separately otherwise (e.g. Error objects).
41+
* @param {unknown[]} args arguments
42+
* @returns {unknown[]} prefixed arguments
43+
*/
44+
function prefixed(args) {
45+
return typeof args[0] === "string"
46+
? [`${LOG_PREFIX} ${args[0]}`, ...args.slice(1)]
47+
: [LOG_PREFIX, ...args];
48+
}
1749

18-
export const log = logger.getLogger(LOGGER_NAME);
50+
export const log = {
51+
/**
52+
* @param {...unknown} args arguments
53+
*/
54+
error(...args) {
55+
if (enabled("error")) console.error(...prefixed(args));
56+
},
57+
/**
58+
* @param {...unknown} args arguments
59+
*/
60+
warn(...args) {
61+
if (enabled("warn")) console.warn(...prefixed(args));
62+
},
63+
/**
64+
* @param {...unknown} args arguments
65+
*/
66+
info(...args) {
67+
if (enabled("info")) console.info(...prefixed(args));
68+
},
69+
/**
70+
* @param {...unknown} args arguments
71+
*/
72+
log(...args) {
73+
if (enabled("log")) console.log(...prefixed(args));
74+
},
75+
/**
76+
* @param {...unknown} args arguments
77+
*/
78+
groupCollapsed(...args) {
79+
if (enabled("log")) console.groupCollapsed(...prefixed(args));
80+
},
81+
groupEnd() {
82+
if (enabled("log")) console.groupEnd();
83+
},
84+
};

0 commit comments

Comments
 (0)