| ... | @@ -2,11 +2,17 @@ | ... | @@ -2,11 +2,17 @@ |
| 2 | import { INCOGNITO_BROWSER_PROFILE_ID } from "@t3tools/contracts"; | 2 | import { INCOGNITO_BROWSER_PROFILE_ID } from "@t3tools/contracts"; |
| 3 | import { constVoid } from "effect/Function"; | 3 | import { constVoid } from "effect/Function"; |
| 4 | import * as NodeFSP from "node:fs/promises"; | 4 | import * as NodeFSP from "node:fs/promises"; |
| | 5 | import * as NodeModule from "node:module"; |
| 5 | import * as NodePath from "node:path"; | 6 | import * as NodePath from "node:path"; |
| 6 | import type { Browser, BrowserContext } from "playwright-core"; | 7 | import type { Browser, BrowserContext } from "playwright-core"; |
| 7 | | 8 | |
| 8 | import { sandboxDisabled } from "./PreviewBrowserHost.ts"; | 9 | import { sandboxDisabled } from "./PreviewBrowserHost.ts"; |
| 9 | | 10 | |
| | 11 | // Playwright needs its files on disk. createRequire also resolves it from a Node SEA executable. |
| | 12 | const requirePlaywright = NodeModule.createRequire(import.meta.url); |
| | 13 | const loadPlaywright = () => |
| | 14 | requirePlaywright("playwright-core") as typeof import("playwright-core"); |
| | 15 | |
| 10 | interface Options { | 16 | interface Options { |
| 11 | readonly profilesDir: string; | 17 | readonly profilesDir: string; |
| 12 | /** The shared headless browser's executable, installing it on first use. */ | 18 | /** The shared headless browser's executable, installing it on first use. */ |
| ... | @@ -54,7 +60,7 @@ export class ServerBrowserContexts { | ... | @@ -54,7 +60,7 @@ export class ServerBrowserContexts { |
| 54 | private sharedBrowser() { | 60 | private sharedBrowser() { |
| 55 | if (!this.browser) { | 61 | if (!this.browser) { |
| 56 | const launched = this.launchOptions().then(async (options) => { | 62 | const launched = this.launchOptions().then(async (options) => { |
| 57 | const { chromium } = await import("playwright-core"); | 63 | const { chromium } = loadPlaywright(); |
| 58 | const browser = await this.launch(options, () => chromium.launch(options)); | 64 | const browser = await this.launch(options, () => chromium.launch(options)); |
| 59 | browser.on("disconnected", () => { | 65 | browser.on("disconnected", () => { |
| 60 | if (this.browser === launched) this.browser = undefined; | 66 | if (this.browser === launched) this.browser = undefined; |
| ... | @@ -104,7 +110,7 @@ export class ServerBrowserContexts { | ... | @@ -104,7 +110,7 @@ export class ServerBrowserContexts { |
| 104 | } | 110 | } |
| 105 | const directory = this.profileDirectory(profileId); | 111 | const directory = this.profileDirectory(profileId); |
| 106 | const options = await this.launchOptions(); | 112 | const options = await this.launchOptions(); |
| 107 | const { chromium } = await import("playwright-core"); | 113 | const { chromium } = loadPlaywright(); |
| 108 | await NodeFSP.mkdir(directory, { recursive: true }); | 114 | await NodeFSP.mkdir(directory, { recursive: true }); |
| 109 | return this.launch(options, () => | 115 | return this.launch(options, () => |
| 110 | chromium.launchPersistentContext(directory, { ...options, ...contextOptions }), | 116 | chromium.launchPersistentContext(directory, { ...options, ...contextOptions }), |
| ... | @@ -133,7 +139,7 @@ export class ServerBrowserContexts { | ... | @@ -133,7 +139,7 @@ export class ServerBrowserContexts { |
| 133 | * serves. The page keeps the desktop's storage, size, and window. | 139 | * serves. The page keeps the desktop's storage, size, and window. |
| 134 | */ | 140 | */ |
| 135 | async connectDesktopPage(endpoint: string) { | 141 | async connectDesktopPage(endpoint: string) { |
| 136 | const { chromium } = await import("playwright-core"); | 142 | const { chromium } = loadPlaywright(); |
| 137 | const browser = await chromium.connectOverCDP(endpoint, { timeout: 15_000 }); | 143 | const browser = await chromium.connectOverCDP(endpoint, { timeout: 15_000 }); |
| 138 | const page = browser.contexts().flatMap((context) => context.pages())[0]; | 144 | const page = browser.contexts().flatMap((context) => context.pages())[0]; |
| 139 | if (!page) { | 145 | if (!page) { |