|
10 | 10 | * npm install -g playwright && npx playwright install chromium |
11 | 11 | */ |
12 | 12 |
|
| 13 | +import { execFileSync } from 'node:child_process'; |
13 | 14 | import fs from 'node:fs'; |
| 15 | +import { createRequire } from 'node:module'; |
14 | 16 | import path from 'node:path'; |
15 | 17 |
|
16 | 18 | export interface PreAuthOptions { |
@@ -43,10 +45,30 @@ interface PlaywrightChromium { |
43 | 45 | launch(opts: { headless: boolean }): Promise<PlaywrightBrowser>; |
44 | 46 | } |
45 | 47 |
|
| 48 | +function resolvePlaywrightPath(): string { |
| 49 | + // Try local node_modules first, then global |
| 50 | + const localPath = path.resolve('node_modules', 'playwright'); |
| 51 | + if (fs.existsSync(localPath)) return localPath; |
| 52 | + |
| 53 | + try { |
| 54 | + const globalRoot = execFileSync('npm', ['root', '-g'], { encoding: 'utf-8' }).trim(); |
| 55 | + const globalPath = path.join(globalRoot, 'playwright'); |
| 56 | + if (fs.existsSync(globalPath)) return globalPath; |
| 57 | + } catch { |
| 58 | + // npm not available or failed |
| 59 | + } |
| 60 | + |
| 61 | + return 'playwright'; // Fallback to bare specifier |
| 62 | +} |
| 63 | + |
46 | 64 | async function loadPlaywright(): Promise<PlaywrightChromium> { |
47 | 65 | try { |
48 | | - // Dynamic import — playwright is an optional peer dependency, not bundled |
49 | | - const pw = await (Function('return import("playwright")')() as Promise<{ chromium: PlaywrightChromium }>); |
| 66 | + // Use createRequire to resolve playwright from local or global node_modules. |
| 67 | + // ESM dynamic import can't resolve bare directory paths, but require.resolve can. |
| 68 | + const resolved = resolvePlaywrightPath(); |
| 69 | + const require = createRequire(import.meta.url); |
| 70 | + const pw = require(resolved) as { chromium: PlaywrightChromium }; |
| 71 | + if (!pw.chromium) throw new Error('chromium not found in playwright module'); |
50 | 72 | return pw.chromium; |
51 | 73 | } catch { |
52 | 74 | console.error('\nERROR: Playwright is required for interactive authentication.'); |
|
0 commit comments