Skip to content

Commit f82a4e9

Browse files
authored
fix(playwright): improve chrome installation and fix spinner duplication on narrow terminals (#2347)
* headless: false will now install binaries for headless mode too * fix spinner message duplication on narrow terminals * add changeset
1 parent 1f44340 commit f82a4e9

File tree

3 files changed

+90
-3
lines changed

3 files changed

+90
-3
lines changed

.changeset/silent-lobsters-march.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"trigger.dev": patch
3+
"@trigger.dev/build": patch
4+
---
5+
6+
- Improve playwright non-headless chrome installation
7+
- Prevent spinner message duplication in narrow terminals

packages/build/src/extensions/playwright.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,29 @@ class PlaywrightExtension implements BuildExtension {
295295
* We save this output to a file and then parse it to get the download urls for the browsers.
296296
*/
297297
instructions.push(`RUN npx playwright install --dry-run > /tmp/browser-info.txt`);
298+
299+
// Determine which browsers to actually install
300+
const browsersToInstall = new Set<PlaywrightBrowser | "chromium-headless-shell">();
301+
298302
this.options.browsers.forEach((browser) => {
299-
const browserType = browser === "chromium" ? "chromium-headless-shell" : browser;
303+
if (browser === "chromium") {
304+
if (this.options.headless) {
305+
// For headless mode, only install chromium-headless-shell
306+
browsersToInstall.add("chromium-headless-shell");
307+
} else {
308+
// For non-headless mode, install both chromium and chromium-headless-shell
309+
// This allows users to easily switch between headless and non-headless mode
310+
browsersToInstall.add("chromium");
311+
browsersToInstall.add("chromium-headless-shell");
312+
}
313+
} else {
314+
browsersToInstall.add(browser);
315+
}
316+
});
317+
318+
Array.from(browsersToInstall).forEach((browser) => {
300319
instructions.push(
301-
`RUN grep -A5 "browser: ${browserType}" /tmp/browser-info.txt > /tmp/${browser}-info.txt`,
320+
`RUN grep -A5 -m1 "browser: ${browser}" /tmp/browser-info.txt > /tmp/${browser}-info.txt`,
302321

303322
`RUN INSTALL_DIR=$(grep "Install location:" /tmp/${browser}-info.txt | cut -d':' -f2- | xargs) && \
304323
DIR_NAME=$(basename "$INSTALL_DIR") && \

packages/cli-v3/src/utilities/windows.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,67 @@ export function escapeImportPath(path: string) {
77
return isWindows ? path.replaceAll("\\", "\\\\") : path;
88
}
99

10+
// Removes ANSI escape sequences to get actual visible length
11+
function getVisibleLength(str: string): number {
12+
return (
13+
str
14+
// Remove terminal hyperlinks: \u001b]8;;URL\u0007TEXT\u001b]8;;\u0007
15+
.replace(/\u001b]8;;[^\u0007]*\u0007/g, "")
16+
// Remove standard ANSI escape sequences (colors, cursor movement, etc.)
17+
.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").length
18+
);
19+
}
20+
21+
function truncateMessage(msg: string, maxLength?: number): string {
22+
const terminalWidth = maxLength ?? process.stdout.columns ?? 80;
23+
const availableWidth = terminalWidth - 5; // Reserve some space for the spinner and padding
24+
const visibleLength = getVisibleLength(msg);
25+
26+
if (visibleLength <= availableWidth) {
27+
return msg;
28+
}
29+
30+
// We need to truncate based on visible characters, but preserve ANSI sequences
31+
// Simple approach: truncate character by character until we fit
32+
let truncated = msg;
33+
while (getVisibleLength(truncated) > availableWidth - 3) {
34+
truncated = truncated.slice(0, -1);
35+
}
36+
37+
return truncated + "...";
38+
}
39+
40+
const wrappedClackSpinner = () => {
41+
let currentMessage = "";
42+
let isActive = false;
43+
44+
const handleResize = () => {
45+
if (isActive && currentMessage) {
46+
spinner.message(truncateMessage(currentMessage));
47+
}
48+
};
49+
50+
const spinner = clackSpinner();
51+
52+
return {
53+
start: (msg?: string): void => {
54+
currentMessage = msg ?? "";
55+
isActive = true;
56+
process.stdout.on("resize", handleResize);
57+
spinner.start(truncateMessage(currentMessage));
58+
},
59+
stop: (msg?: string, code?: number): void => {
60+
isActive = false;
61+
process.stdout.off("resize", handleResize);
62+
spinner.stop(truncateMessage(msg ?? ""), code);
63+
},
64+
message: (msg?: string): void => {
65+
currentMessage = msg ?? "";
66+
spinner.message(truncateMessage(currentMessage));
67+
},
68+
};
69+
};
70+
1071
const ballmerSpinner = () => ({
1172
start: (msg?: string): void => {
1273
log.step(msg ?? "");
@@ -21,4 +82,4 @@ const ballmerSpinner = () => ({
2182

2283
// This will become unecessary with the next clack release, the bug was fixed here:
2384
// https://github.com/natemoo-re/clack/pull/182
24-
export const spinner = () => (isWindows ? ballmerSpinner() : clackSpinner());
85+
export const spinner = () => (isWindows ? ballmerSpinner() : wrappedClackSpinner());

0 commit comments

Comments
 (0)