Skip to content

Commit f11d0fe

Browse files
committed
feat(): brick_next框架在生产运行时去掉console.xxx的输出
Closes NEXT_BUILDER-5697
1 parent 72bf516 commit f11d0fe

File tree

5 files changed

+532
-8
lines changed

5 files changed

+532
-8
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ node_modules
99
.schema
1010
.cache
1111
.nx
12+
.history
1213
*.log
1314
report.*.json
1415

cypress/e2e/sub-routes.spec.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ for (const port of Cypress.env("ports")) {
55

66
describe(`Testing sub-routes incremental rendering on port ${port}`, () => {
77
it("should render sub-routes", () => {
8-
cy.visit(`${origin}/e2e/sub-routes/1`, {
8+
cy.visit(`${origin}/e2e/sub-routes/1?__debugConsole__=true`, {
99
onBeforeLoad(win) {
1010
cy.spy(win.console, "error").as("console.error");
1111
cy.spy(win.console, "info").as("console.info");
@@ -110,7 +110,7 @@ for (const port of Cypress.env("ports")) {
110110
});
111111

112112
it("should render multiple sub-routes", () => {
113-
cy.visit(`${origin}/e2e/sub-routes-alt`, {
113+
cy.visit(`${origin}/e2e/sub-routes-alt?__debugConsole__=true`, {
114114
onBeforeLoad(win) {
115115
cy.spy(win.console, "error").as("console.error");
116116
cy.spy(win.console, "info").as("console.info");
@@ -215,12 +215,15 @@ for (const port of Cypress.env("ports")) {
215215
});
216216

217217
it("should handle multiple clicks with sub-routes", () => {
218-
cy.visit(`${origin}/e2e/sub-routes-multi-click-entry`, {
219-
onBeforeLoad(win) {
220-
cy.spy(win.console, "error").as("console.error");
221-
cy.spy(win.console, "info").as("console.info");
222-
},
223-
});
218+
cy.visit(
219+
`${origin}/e2e/sub-routes-multi-click-entry?__debugConsole__=true`,
220+
{
221+
onBeforeLoad(win) {
222+
cy.spy(win.console, "error").as("console.error");
223+
cy.spy(win.console, "info").as("console.info");
224+
},
225+
}
226+
);
224227

225228
// Click twice
226229
cy.contains("Go App").click();

packages/runtime/src/internal/bindListeners.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { getFormStateStore } from "./FormRenderer/utils.js";
3939
import { DataStore } from "./data/DataStore.js";
4040
import { hooks } from "./Runtime.js";
4141
import { startSSEStream } from "./sse.js";
42+
import { debugManager } from "./debugManager.js";
4243

4344
export function bindListeners(
4445
brick: RuntimeBrickElement,
@@ -806,6 +807,13 @@ function handleConsoleAction(
806807
args: unknown[] | undefined,
807808
runtimeContext: RuntimeContext
808809
) {
810+
const isProduction = process.env.NODE_ENV === "production";
811+
812+
// 生产环境下,只有调试模式开启且符合日志级别才输出
813+
if (isProduction && !debugManager.shouldLog(method)) {
814+
return;
815+
}
816+
809817
// eslint-disable-next-line no-console
810818
console[method](
811819
...argsFactory(args, runtimeContext, event, {
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
/* eslint-disable no-console -- allow console.log in this file */
2+
import { debugManager } from "./debugManager.js";
3+
4+
// Mock localStorage and sessionStorage
5+
const localStorageMock = {
6+
getItem: jest.fn(),
7+
setItem: jest.fn(),
8+
removeItem: jest.fn(),
9+
};
10+
const sessionStorageMock = {
11+
getItem: jest.fn(),
12+
setItem: jest.fn(),
13+
removeItem: jest.fn(),
14+
};
15+
16+
Object.defineProperty(window, "localStorage", {
17+
value: localStorageMock,
18+
});
19+
Object.defineProperty(window, "sessionStorage", {
20+
value: sessionStorageMock,
21+
});
22+
23+
// Mock URLSearchParams
24+
const mockURLSearchParams = jest.fn();
25+
Object.defineProperty(window, "URLSearchParams", {
26+
value: mockURLSearchParams,
27+
});
28+
29+
// Mock console.log to avoid test output
30+
const originalConsoleLog = console.log;
31+
const originalConsoleError = console.error;
32+
33+
beforeAll(() => {
34+
console.log = jest.fn();
35+
console.error = jest.fn();
36+
});
37+
38+
afterAll(() => {
39+
console.log = originalConsoleLog;
40+
console.error = originalConsoleError;
41+
});
42+
43+
describe("debugManager", () => {
44+
beforeEach(() => {
45+
// Reset mocks
46+
jest.clearAllMocks();
47+
localStorageMock.getItem.mockReturnValue(null);
48+
sessionStorageMock.getItem.mockReturnValue(null);
49+
mockURLSearchParams.mockReturnValue({
50+
get: jest.fn().mockReturnValue(null),
51+
});
52+
53+
// Reset the singleton instance by clearing the static property
54+
const DebugManagerClass = debugManager.constructor as any;
55+
DebugManagerClass.instance = undefined;
56+
});
57+
58+
test("should initialize with no debug mode by default", () => {
59+
const manager = debugManager;
60+
expect(manager.isDebugMode()).toBe(false);
61+
expect(manager.getDebugType()).toBe("none");
62+
});
63+
64+
test("should enable session debug mode", () => {
65+
const manager = debugManager;
66+
(window as any).debugConsole.enable();
67+
68+
expect(manager.isDebugMode()).toBe(true);
69+
expect(manager.getDebugType()).toBe("session");
70+
expect(sessionStorageMock.setItem).toHaveBeenCalledWith(
71+
"debugConsole",
72+
"true"
73+
);
74+
expect(console.log).toHaveBeenCalledWith(
75+
"🔧 调试模式已开启(会话模式 - 关闭标签页后失效)"
76+
);
77+
});
78+
79+
test("should enable persistent debug mode", () => {
80+
const manager = debugManager;
81+
(window as any).debugConsole.enablePersistent();
82+
83+
expect(manager.isDebugMode()).toBe(true);
84+
expect(manager.getDebugType()).toBe("persistent");
85+
expect(localStorageMock.setItem).toHaveBeenCalledWith(
86+
"debugConsole",
87+
"true"
88+
);
89+
expect(console.log).toHaveBeenCalledWith(
90+
"🔧 调试模式已开启(持久模式 - 内部调试)"
91+
);
92+
});
93+
94+
test("should disable debug mode", () => {
95+
const manager = debugManager;
96+
(window as any).debugConsole.enable();
97+
(window as any).debugConsole.disable();
98+
99+
expect(manager.isDebugMode()).toBe(false);
100+
expect(manager.getDebugType()).toBe("none");
101+
expect(sessionStorageMock.removeItem).toHaveBeenCalledWith("debugConsole");
102+
expect(localStorageMock.removeItem).toHaveBeenCalledWith("debugConsole");
103+
expect(console.log).toHaveBeenCalledWith("🔧 调试模式已关闭");
104+
});
105+
106+
test("should toggle debug mode", () => {
107+
const manager = debugManager;
108+
109+
// Initially disabled
110+
expect(manager.isDebugMode()).toBe(false);
111+
112+
// Toggle to enabled
113+
(window as any).debugConsole.toggle();
114+
expect(manager.isDebugMode()).toBe(true);
115+
expect(manager.getDebugType()).toBe("session");
116+
expect(console.log).toHaveBeenCalledWith(
117+
"🔧 调试模式已开启(会话模式 - 关闭标签页后失效)"
118+
);
119+
120+
// Toggle to disabled
121+
(window as any).debugConsole.toggle();
122+
expect(manager.isDebugMode()).toBe(false);
123+
expect(manager.getDebugType()).toBe("none");
124+
expect(console.log).toHaveBeenCalledWith("🔧 调试模式已关闭");
125+
});
126+
127+
test("should toggle persistent debug mode", () => {
128+
const manager = debugManager;
129+
130+
// Initially disabled
131+
expect(manager.isDebugMode()).toBe(false);
132+
133+
// Toggle to persistent enabled
134+
(window as any).debugConsole.togglePersistent();
135+
expect(manager.isDebugMode()).toBe(true);
136+
expect(manager.getDebugType()).toBe("persistent");
137+
expect(console.log).toHaveBeenCalledWith(
138+
"🔧 调试模式已开启(持久模式 - 内部调试)"
139+
);
140+
141+
// Toggle to disabled
142+
(window as any).debugConsole.togglePersistent();
143+
expect(manager.isDebugMode()).toBe(false);
144+
expect(manager.getDebugType()).toBe("none");
145+
expect(console.log).toHaveBeenCalledWith("🔧 调试模式已关闭");
146+
});
147+
148+
test("should check if method should log based on debug mode", () => {
149+
const manager = debugManager;
150+
151+
// Debug mode is disabled by default
152+
expect(manager.shouldLog("log")).toBe(false);
153+
expect(manager.shouldLog("info")).toBe(false);
154+
expect(manager.shouldLog("warn")).toBe(false);
155+
expect(manager.shouldLog("error")).toBe(true); // error always logs
156+
157+
// Enable debug mode
158+
(window as any).debugConsole.enable();
159+
expect(manager.shouldLog("log")).toBe(true);
160+
expect(manager.shouldLog("info")).toBe(true);
161+
expect(manager.shouldLog("warn")).toBe(true);
162+
expect(manager.shouldLog("error")).toBe(true);
163+
164+
// Disable debug mode
165+
(window as any).debugConsole.disable();
166+
expect(manager.shouldLog("log")).toBe(false);
167+
expect(manager.shouldLog("info")).toBe(false);
168+
expect(manager.shouldLog("warn")).toBe(false);
169+
expect(manager.shouldLog("error")).toBe(true); // error always logs
170+
});
171+
172+
test("should always log error messages", () => {
173+
const manager = debugManager;
174+
175+
// Error messages should always log regardless of debug mode
176+
expect(manager.shouldLog("error")).toBe(true);
177+
178+
// Enable debug mode
179+
(window as any).debugConsole.enable();
180+
expect(manager.shouldLog("error")).toBe(true);
181+
182+
// Disable debug mode
183+
(window as any).debugConsole.disable();
184+
expect(manager.shouldLog("error")).toBe(true);
185+
});
186+
187+
test("should initialize from localStorage persistent debug", () => {
188+
localStorageMock.getItem.mockReturnValue("true");
189+
190+
// Create a new instance to test initialization
191+
const DebugManagerClass = debugManager.constructor as any;
192+
DebugManagerClass.instance = undefined;
193+
const manager = new DebugManagerClass();
194+
195+
expect(manager.isDebugMode()).toBe(true);
196+
expect(manager.getDebugType()).toBe("persistent");
197+
expect(console.log).toHaveBeenCalledWith(
198+
"🔧 调试模式已开启(持久模式 - 内部调试)"
199+
);
200+
});
201+
202+
test("should initialize from sessionStorage session debug", () => {
203+
sessionStorageMock.getItem.mockReturnValue("true");
204+
205+
// Create a new instance to test initialization
206+
const DebugManagerClass = debugManager.constructor as any;
207+
DebugManagerClass.instance = undefined;
208+
const manager = new DebugManagerClass();
209+
210+
expect(manager.isDebugMode()).toBe(true);
211+
expect(manager.getDebugType()).toBe("session");
212+
expect(console.log).toHaveBeenCalledWith(
213+
"🔧 调试模式已开启(会话模式 - 关闭标签页后失效)"
214+
);
215+
});
216+
217+
test("should initialize from URL parameter", () => {
218+
mockURLSearchParams.mockReturnValue({
219+
get: (key: string) => {
220+
if (key === "__debugConsole__") {
221+
return "true";
222+
}
223+
return null;
224+
},
225+
});
226+
227+
// Create a new instance to test initialization
228+
const DebugManagerClass = debugManager.constructor as any;
229+
DebugManagerClass.instance = undefined;
230+
const manager = new DebugManagerClass();
231+
232+
expect(manager.isDebugMode()).toBe(true);
233+
expect(manager.getDebugType()).toBe("session");
234+
expect(sessionStorageMock.setItem).toHaveBeenCalledWith(
235+
"debugConsole",
236+
"true"
237+
);
238+
expect(console.log).toHaveBeenCalledWith(
239+
"🔧 调试模式已通过URL参数激活(会话模式)"
240+
);
241+
});
242+
243+
test("should display status correctly", () => {
244+
// First disable debug mode to ensure clean state
245+
(window as any).debugConsole.disable();
246+
247+
// Test disabled status
248+
const disabledStatus = (window as any).debugConsole.status();
249+
expect(disabledStatus.debugMode).toBe(false);
250+
expect(disabledStatus.debugType).toBe("none");
251+
expect(console.log).toHaveBeenCalledWith("🔧 调试状态:", disabledStatus);
252+
253+
// Test enabled status
254+
(window as any).debugConsole.enable();
255+
const enabledStatus = (window as any).debugConsole.status();
256+
expect(enabledStatus.debugMode).toBe(true);
257+
expect(enabledStatus.debugType).toBe("session");
258+
});
259+
260+
test("should display help information", () => {
261+
(window as any).debugConsole.help();
262+
expect(console.log).toHaveBeenCalledWith(
263+
expect.stringContaining("🔧 混合调试控制台使用说明")
264+
);
265+
expect(console.log).toHaveBeenCalledWith(
266+
expect.stringContaining("👥 生产环境使用(临时调试)")
267+
);
268+
expect(console.log).toHaveBeenCalledWith(
269+
expect.stringContaining("👨‍💻 开发人员使用(长期调试)")
270+
);
271+
});
272+
273+
test("should display initial status when debug mode is enabled", () => {
274+
// Mock debug mode enabled
275+
localStorageMock.getItem.mockReturnValue("true");
276+
277+
// Create a new instance to test initialization
278+
const DebugManagerClass = debugManager.constructor as any;
279+
DebugManagerClass.instance = undefined;
280+
const _manager = new DebugManagerClass();
281+
282+
expect(console.log).toHaveBeenCalledWith("🔧 调试模式已开启(持久模式)");
283+
});
284+
285+
test("should display initial status when debug mode is disabled", () => {
286+
// Mock debug mode disabled (default)
287+
localStorageMock.getItem.mockReturnValue(null);
288+
sessionStorageMock.getItem.mockReturnValue(null);
289+
290+
// Create a new instance to test initialization
291+
const DebugManagerClass = debugManager.constructor as any;
292+
DebugManagerClass.instance = undefined;
293+
const _manager = new DebugManagerClass();
294+
295+
expect(console.log).toHaveBeenCalledWith(
296+
"💡 提示:使用 window.debugConsole.help() 查看使用说明"
297+
);
298+
});
299+
});

0 commit comments

Comments
 (0)