@@ -10,12 +10,173 @@ interface PlaywrightExtensionOptions {
1010 browsers ?: PlaywrightBrowser [ ] ;
1111
1212 /**
13- * Whether to support non- headless mode.
13+ * Run the browsers in headless mode (Recommended)
1414 * @default true
1515 */
1616 headless ?: boolean ;
1717}
1818
19+ /**
20+ * This list is from the official playwright registry.
21+ *
22+ * @see https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/registry/nativeDeps.ts
23+ */
24+ const debian12Deps = {
25+ tools : [
26+ "xvfb" ,
27+ "fonts-noto-color-emoji" ,
28+ "fonts-unifont" ,
29+ "libfontconfig1" ,
30+ "libfreetype6" ,
31+ "xfonts-scalable" ,
32+ "fonts-liberation" ,
33+ "fonts-ipafont-gothic" ,
34+ "fonts-wqy-zenhei" ,
35+ "fonts-tlwg-loma-otf" ,
36+ "fonts-freefont-ttf" ,
37+ ] ,
38+ chromium : [
39+ "libasound2" ,
40+ "libatk-bridge2.0-0" ,
41+ "libatk1.0-0" ,
42+ "libatspi2.0-0" ,
43+ "libcairo2" ,
44+ "libcups2" ,
45+ "libdbus-1-3" ,
46+ "libdrm2" ,
47+ "libgbm1" ,
48+ "libglib2.0-0" ,
49+ "libnspr4" ,
50+ "libnss3" ,
51+ "libpango-1.0-0" ,
52+ "libx11-6" ,
53+ "libxcb1" ,
54+ "libxcomposite1" ,
55+ "libxdamage1" ,
56+ "libxext6" ,
57+ "libxfixes3" ,
58+ "libxkbcommon0" ,
59+ "libxrandr2" ,
60+ ] ,
61+ firefox : [
62+ "libasound2" ,
63+ "libatk1.0-0" ,
64+ "libcairo-gobject2" ,
65+ "libcairo2" ,
66+ "libdbus-1-3" ,
67+ "libdbus-glib-1-2" ,
68+ "libfontconfig1" ,
69+ "libfreetype6" ,
70+ "libgdk-pixbuf-2.0-0" ,
71+ "libglib2.0-0" ,
72+ "libgtk-3-0" ,
73+ "libharfbuzz0b" ,
74+ "libpango-1.0-0" ,
75+ "libpangocairo-1.0-0" ,
76+ "libx11-6" ,
77+ "libx11-xcb1" ,
78+ "libxcb-shm0" ,
79+ "libxcb1" ,
80+ "libxcomposite1" ,
81+ "libxcursor1" ,
82+ "libxdamage1" ,
83+ "libxext6" ,
84+ "libxfixes3" ,
85+ "libxi6" ,
86+ "libxrandr2" ,
87+ "libxrender1" ,
88+ "libxtst6" ,
89+ ] ,
90+ webkit : [
91+ "libsoup-3.0-0" ,
92+ "gstreamer1.0-libav" ,
93+ "gstreamer1.0-plugins-bad" ,
94+ "gstreamer1.0-plugins-base" ,
95+ "gstreamer1.0-plugins-good" ,
96+ "libatk-bridge2.0-0" ,
97+ "libatk1.0-0" ,
98+ "libcairo2" ,
99+ "libdbus-1-3" ,
100+ "libdrm2" ,
101+ "libegl1" ,
102+ "libenchant-2-2" ,
103+ "libepoxy0" ,
104+ "libevdev2" ,
105+ "libfontconfig1" ,
106+ "libfreetype6" ,
107+ "libgbm1" ,
108+ "libgdk-pixbuf-2.0-0" ,
109+ "libgles2" ,
110+ "libglib2.0-0" ,
111+ "libglx0" ,
112+ "libgstreamer-gl1.0-0" ,
113+ "libgstreamer-plugins-base1.0-0" ,
114+ "libgstreamer1.0-0" ,
115+ "libgtk-4-1" ,
116+ "libgudev-1.0-0" ,
117+ "libharfbuzz-icu0" ,
118+ "libharfbuzz0b" ,
119+ "libhyphen0" ,
120+ "libicu72" ,
121+ "libjpeg62-turbo" ,
122+ "liblcms2-2" ,
123+ "libmanette-0.2-0" ,
124+ "libnotify4" ,
125+ "libopengl0" ,
126+ "libopenjp2-7" ,
127+ "libopus0" ,
128+ "libpango-1.0-0" ,
129+ "libpng16-16" ,
130+ "libproxy1v5" ,
131+ "libsecret-1-0" ,
132+ "libwayland-client0" ,
133+ "libwayland-egl1" ,
134+ "libwayland-server0" ,
135+ "libwebp7" ,
136+ "libwebpdemux2" ,
137+ "libwoff1" ,
138+ "libx11-6" ,
139+ "libxcomposite1" ,
140+ "libxdamage1" ,
141+ "libxkbcommon0" ,
142+ "libxml2" ,
143+ "libxslt1.1" ,
144+ "libatomic1" ,
145+ "libevent-2.1-7" ,
146+ "libavif15" ,
147+ ] ,
148+ lib2package : {
149+ "libavif.so.15" : "libavif15" ,
150+ "libsoup-3.0.so.0" : "libsoup-3.0-0" ,
151+ "libasound.so.2" : "libasound2" ,
152+ "libatk-1.0.so.0" : "libatk1.0-0" ,
153+ "libatk-bridge-2.0.so.0" : "libatk-bridge2.0-0" ,
154+ "libatspi.so.0" : "libatspi2.0-0" ,
155+ "libcairo.so.2" : "libcairo2" ,
156+ "libcups.so.2" : "libcups2" ,
157+ "libdbus-1.so.3" : "libdbus-1-3" ,
158+ "libdrm.so.2" : "libdrm2" ,
159+ "libgbm.so.1" : "libgbm1" ,
160+ "libgio-2.0.so.0" : "libglib2.0-0" ,
161+ "libglib-2.0.so.0" : "libglib2.0-0" ,
162+ "libgobject-2.0.so.0" : "libglib2.0-0" ,
163+ "libnspr4.so" : "libnspr4" ,
164+ "libnss3.so" : "libnss3" ,
165+ "libnssutil3.so" : "libnss3" ,
166+ "libpango-1.0.so.0" : "libpango-1.0-0" ,
167+ "libsmime3.so" : "libnss3" ,
168+ "libX11.so.6" : "libx11-6" ,
169+ "libxcb.so.1" : "libxcb1" ,
170+ "libXcomposite.so.1" : "libxcomposite1" ,
171+ "libXdamage.so.1" : "libxdamage1" ,
172+ "libXext.so.6" : "libxext6" ,
173+ "libXfixes.so.3" : "libxfixes3" ,
174+ "libxkbcommon.so.0" : "libxkbcommon0" ,
175+ "libXrandr.so.2" : "libxrandr2" ,
176+ "libgtk-4.so.1" : "libgtk-4-1" ,
177+ } ,
178+ } ;
179+
19180/**
20181 * Creates a Playwright extension for trigger.dev
21182 * @param options Configuration options
@@ -24,6 +185,23 @@ export function playwright(options: PlaywrightExtensionOptions = {}) {
24185 return new PlaywrightExtension ( options ) ;
25186}
26187
188+ /**
189+ * Background:
190+ *
191+ * Running `npx playwright install --with-deps` normally will install the browsers and the dependencies.
192+ * However, this is not possible in a build context, because we don't have sudo access.
193+ *
194+ * So we need to install the dependencies manually and then download and install the browsers.
195+ * This has a few challenges:
196+ * 1. We don't want to download all browsers, only the ones we need with it's dependencies
197+ * The less dependencies we have to install, the faster the build, and the smaller the image.
198+ * 2. We need to know where to download the browsers from
199+ * while we can hardcode the download url it might change over time (as it has in the past)
200+ * so we need to download the browser info first and then parse the output to get the download url.
201+ *
202+ * Note: While this looks like we are downloading & installing a lot of stuff, it's actually not that bad
203+ * since running `npx playwright install --with-deps` will result in the same amount of downloads.
204+ */
27205class PlaywrightExtension implements BuildExtension {
28206 public readonly name = "PlaywrightExtension" ;
29207 private readonly options : Required < PlaywrightExtensionOptions > ;
@@ -43,7 +221,7 @@ class PlaywrightExtension implements BuildExtension {
43221 ) ;
44222
45223 const instructions : string [ ] = [
46- // Base dependencies
224+ // Base dependencies, we need these to download the browsers
47225 `RUN apt-get update && apt-get install -y --no-install-recommends \
48226 curl \
49227 unzip \
@@ -57,90 +235,26 @@ class PlaywrightExtension implements BuildExtension {
57235 `RUN npm install -g playwright` ,
58236 ] ;
59237
60- // Browser-specific dependencies
61- const chromiumDeps = [
62- "libnspr4" ,
63- "libatk1.0-0" ,
64- "libatk-bridge2.0-0" ,
65- "libatspi2.0-0" ,
66- "libasound2" ,
67- "libnss3" ,
68- "libxcomposite1" ,
69- "libxdamage1" ,
70- "libxfixes3" ,
71- "libxrandr2" ,
72- "libgbm1" ,
73- "libxkbcommon0" ,
74- ] ;
75-
76- const firefoxDeps = [
77- "libgtk-3.0" ,
78- "libgtk-4-1" ,
79- "libgtk-4-common" ,
80- "libgtk-4-dev" ,
81- "libgtk-4-doc" ,
82- "libasound2" ,
83- ] ;
84-
85- const webkitDeps = [
86- "libenchant-2-2" ,
87- "libgl1" ,
88- "libgles2" ,
89- "libgstreamer-gl1.0-0" ,
90- "libgstreamer-plugins-base1.0-0" ,
91- "libgstreamer-plugins-bad1.0-0" ,
92- "libharfbuzz-icu0" ,
93- "libhyphen0" ,
94- "libicu72" ,
95- "libjpeg-dev" ,
96- "libopenjp2-7" ,
97- "libopus0" ,
98- "libpng-dev" ,
99- "libsecret-1-0" ,
100- "libvpx7" ,
101- "libwebp7" ,
102- "libwoff1" ,
103- "libx11-6" ,
104- "libxcomposite1" ,
105- "libxdamage1" ,
106- "libxrender1" ,
107- "libxt6" ,
108- "libgtk-4-1" ,
109- "libgraphene-1.0-0" ,
110- "libxslt1.1" ,
111- "libevent-2.1-7" ,
112- "libmanette-0.2-0" ,
113- "libwebpdemux2" ,
114- "libwebpmux3" ,
115- "libatomic1" ,
116- "libavif15" ,
117- "libx264-dev" ,
118- "flite" ,
119- "libatk1.0-0" ,
120- "libatk-bridge2.0-0" ,
121- ] ;
238+ const deps = [ ...debian12Deps . tools , ...Object . values ( debian12Deps . lib2package ) ] ;
239+ if ( this . options . browsers . includes ( "chromium" ) ) deps . push ( ...debian12Deps . chromium ) ;
240+ if ( this . options . browsers . includes ( "firefox" ) ) deps . push ( ...debian12Deps . firefox ) ;
241+ if ( this . options . browsers . includes ( "webkit" ) ) deps . push ( ...debian12Deps . webkit ) ;
122242
123- const deps = [ ] ;
124- if ( this . options . browsers . includes ( "chromium" ) ) deps . push ( ...chromiumDeps ) ;
125- if ( this . options . browsers . includes ( "firefox" ) ) deps . push ( ...firefoxDeps ) ;
126- if ( this . options . browsers . includes ( "webkit" ) ) deps . push ( ...webkitDeps ) ;
127-
128- const uniqueDeps = [ ...new Set ( deps ) ] ;
129-
130- if ( uniqueDeps . length > 0 ) {
131- instructions . push (
132- `RUN apt-get update && apt-get install -y --no-install-recommends ${ uniqueDeps . join ( " " ) } \
243+ instructions . push (
244+ `RUN apt-get update && apt-get install -y --no-install-recommends ${ deps . join ( " " ) } \
133245 && apt-get clean && rm -rf /var/lib/apt/lists/*`
134- ) ;
135- }
246+ ) ;
136247
137- // Setup Playwright browsers
248+ // Setup directory for playwright browsers
138249 instructions . push ( `RUN mkdir -p /ms-playwright` ) ;
139- instructions . push ( `RUN npx playwright install --dry-run > /tmp/browser-info.txt` ) ;
140250
251+ /**
252+ * `npx playwright install --dry-run` prints the download urls for the browsers.
253+ * We save this output to a file and then parse it to get the download urls for the browsers.
254+ */
255+ instructions . push ( `RUN npx playwright install --dry-run > /tmp/browser-info.txt` ) ;
141256 this . options . browsers . forEach ( ( browser ) => {
142257 const browserType = browser === "chromium" ? "chromium-headless-shell" : browser ;
143-
144258 instructions . push (
145259 `RUN grep -A5 "browser: ${ browserType } " /tmp/browser-info.txt > /tmp/${ browser } -info.txt` ,
146260
@@ -160,9 +274,9 @@ class PlaywrightExtension implements BuildExtension {
160274
161275 // Environment variables
162276 const envVars : Record < string , string > = {
163- PLAYWRIGHT_BROWSERS_PATH : "/ms-playwright" ,
164- PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD : "1" ,
165- PLAYWRIGHT_SKIP_BROWSER_VALIDATION : "1" ,
277+ PLAYWRIGHT_BROWSERS_PATH : "/ms-playwright" , // where playwright will find the browsers
278+ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD : "1" , // we already downloaded the browsers
279+ PLAYWRIGHT_SKIP_BROWSER_VALIDATION : "1" , // we already downloaded the browsers
166280 } ;
167281
168282 if ( ! this . options . headless ) {
@@ -173,7 +287,7 @@ class PlaywrightExtension implements BuildExtension {
173287 `RUN chmod +x /usr/local/bin/xvfb-exec`
174288 ) ;
175289
176- envVars . DISPLAY = ":99" ;
290+ envVars . DISPLAY = ":99" ; // Virtual display for the browsers
177291 }
178292
179293 context . addLayer ( {
0 commit comments