Skip to content

Commit 9ef09e4

Browse files
committed
improve code, avoid race conditions with buffering and flushing multiple times
1 parent 9b7d94f commit 9ef09e4

File tree

1 file changed

+54
-60
lines changed

1 file changed

+54
-60
lines changed

packages/preview-server/src/actions/render-email-by-path.tsx

Lines changed: 54 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { getEmailComponent } from '../utils/get-email-component';
1717
import { registerSpinnerAutostopping } from '../utils/register-spinner-autostopping';
1818
import { styleText } from '../utils/style-text';
1919
import type { ErrorObject } from '../utils/types/error-object';
20+
import { log } from 'node:console';
2021

2122
export interface RenderedEmailMetadata {
2223
prettyMarkup: string;
@@ -36,50 +37,55 @@ export interface RenderedEmailMetadata {
3637
export type EmailRenderingResult =
3738
| RenderedEmailMetadata
3839
| {
39-
error: ErrorObject;
40-
};
40+
error: ErrorObject;
41+
};
4142

4243
const cache = new Map<string, EmailRenderingResult>();
4344

44-
const createLogBufferer = (log: (...args: any[]) => void) => {
45+
const createLogBufferer = (
46+
originalLogger: (...args: any[]) => void,
47+
overwriteLogger: (logger: (...args: any[]) => void) => void,
48+
) => {
4549
let logs: Array<any[]> = [];
4650

47-
const bufferer = {
48-
log: (...args: any[]) => {
49-
logs.push(args);
51+
let timesCorked = 0;
52+
53+
return {
54+
buffer: () => {
55+
timesCorked += 1;
56+
overwriteLogger((...args: any[]) => logs.push(args));
5057
},
51-
original: log,
5258
flush: () => {
53-
for (const logArgs of logs) {
54-
log(...logArgs);
59+
timesCorked = Math.max(timesCorked - 1, 0);
60+
// This ensures that, only once flushing has been called as many times as
61+
// buffering, that the logs are actually flushed.
62+
if (timesCorked === 0) {
63+
for (const logArgs of logs) {
64+
originalLogger(...logArgs);
65+
}
66+
logs = [];
67+
overwriteLogger(originalLogger);
5568
}
56-
logs = [];
5769
},
5870
};
59-
60-
return bufferer;
6171
};
6272

63-
const {
64-
log,
65-
flush: flushLog,
66-
original: originalLog,
67-
} = createLogBufferer(console.log);
68-
const {
69-
log: error,
70-
flush: flushError,
71-
original: originalError,
72-
} = createLogBufferer(console.error);
73-
const {
74-
log: info,
75-
flush: flushInfo,
76-
original: originalInfo,
77-
} = createLogBufferer(console.info);
78-
const {
79-
log: warn,
80-
flush: flushWarn,
81-
original: originalWarn,
82-
} = createLogBufferer(console.warn);
73+
const logBufferer = createLogBufferer(
74+
console.log,
75+
(logger) => (console.log = logger),
76+
);
77+
const errorBufferer = createLogBufferer(
78+
console.error,
79+
(logger) => (console.error = logger),
80+
);
81+
const infoBufferer = createLogBufferer(
82+
console.info,
83+
(logger) => (console.info = logger),
84+
);
85+
const warnBufferer = createLogBufferer(
86+
console.warn,
87+
(logger) => (console.warn = logger),
88+
);
8389

8490
export const renderEmailByPath = async (
8591
emailPath: string,
@@ -93,10 +99,10 @@ export const renderEmailByPath = async (
9399
return cache.get(emailPath)!;
94100
}
95101

96-
console.log = log;
97-
console.info = info;
98-
console.error = error;
99-
console.warn = warn;
102+
logBufferer.buffer();
103+
errorBufferer.buffer();
104+
infoBufferer.buffer();
105+
warnBufferer.buffer();
100106

101107
const emailFilename = path.basename(emailPath);
102108
let spinner: Ora | undefined;
@@ -126,14 +132,10 @@ export const renderEmailByPath = async (
126132
symbol: logSymbols.error,
127133
text: `Failed while rendering ${emailFilename}`,
128134
});
129-
flushLog();
130-
console.log = originalLog;
131-
flushError();
132-
console.error = originalError;
133-
flushInfo();
134-
console.info = originalInfo;
135-
flushWarn();
136-
console.warn = originalWarn;
135+
logBufferer.flush();
136+
errorBufferer.flush();
137+
infoBufferer.flush();
138+
warnBufferer.flush();
137139
return { error: componentResult.error };
138140
}
139141

@@ -178,14 +180,10 @@ export const renderEmailByPath = async (
178180
symbol: logSymbols.success,
179181
text: `Successfully rendered ${emailFilename} in ${timeForConsole} (bundled in ${millisecondsToBundled.toFixed(0)}ms)`,
180182
});
181-
flushLog();
182-
console.log = originalLog;
183-
flushError();
184-
console.error = originalError;
185-
flushInfo();
186-
console.info = originalInfo;
187-
flushWarn();
188-
console.warn = originalWarn;
183+
logBufferer.flush();
184+
errorBufferer.flush();
185+
infoBufferer.flush();
186+
warnBufferer.flush();
189187

190188
const renderingResult: RenderedEmailMetadata = {
191189
prettyMarkup,
@@ -211,14 +209,10 @@ export const renderEmailByPath = async (
211209
symbol: logSymbols.error,
212210
text: `Failed while rendering ${emailFilename}`,
213211
});
214-
flushLog();
215-
console.log = originalLog;
216-
flushError();
217-
console.error = originalError;
218-
flushInfo();
219-
console.info = originalInfo;
220-
flushWarn();
221-
console.warn = originalWarn;
212+
logBufferer.flush();
213+
errorBufferer.flush();
214+
infoBufferer.flush();
215+
warnBufferer.flush();
222216

223217
if (exception instanceof SyntaxError) {
224218
interface SpanPosition {

0 commit comments

Comments
 (0)