UNPKG

@cityssm/puppeteer-launch

Version:

Launch Puppeteer, falling back to system browsers when the cached ones aren't working or aren't available.

142 lines (120 loc) 4.19 kB
import { Browser, BrowserPlatform, detectBrowserPlatform, install, resolveBuildId } from '@puppeteer/browsers' import Debug from 'debug' import puppeteer from 'puppeteer' import { getCachedBrowser, PUPPETEER_CACHE_DIR, refreshInstalledBrowserCache } from './cache.js' import { DEBUG_NAMESPACE } from './debug.config.js' export const INSTALLER_TIMEOUT = 5 * 60 * 1000 const debug = Debug(`${DEBUG_NAMESPACE}:installers`) /** * Installs the specified browser for Puppeteer. * Times out after 5 minutes. * @param browser - The browser to install ('chrome' or 'firefox'). * @returns A promise that resolves when the installation is complete. */ export async function installBrowser( browser: 'chrome' | 'firefox' ): Promise<void> { const enumBrowser = browser === 'chrome' ? Browser.CHROME : Browser.FIREFOX const platform = detectBrowserPlatform() ?? BrowserPlatform.LINUX const buildId = await resolveBuildId(enumBrowser, platform, 'stable') try { await install({ browser: enumBrowser, buildId, cacheDir: PUPPETEER_CACHE_DIR, unpack: true }) await refreshInstalledBrowserCache() } catch (error) { debug('Error installing browser: %O', error) if ( error instanceof Error && error.message.includes('EEXIST: file already exists') ) { await refreshInstalledBrowserCache() return } throw error } } /** * Installs the Chrome browser for Puppeteer. */ export async function installChromeBrowser(): Promise<void> { await installBrowser('chrome') } /** * Installs the Firefox browser for Puppeteer. */ export async function installFirefoxBrowser(): Promise<void> { await installBrowser('firefox') } export interface TestInstalledBrowserResult { /** Whether the browser is installed and able to launch */ success: boolean /** Whether the installer was run */ ranInstaller: boolean } /** * Tests if the specified browser is installed. * @param browserName - The name of the browser to test ('chrome' or 'firefox'). * @param installIfUnavailable - Whether to install the browser if it's not available. * @returns An object containing the installation status and whether the installer was run. */ export async function testInstalledBrowser( browserName: 'chrome' | 'firefox', installIfUnavailable = false ): Promise<TestInstalledBrowserResult> { let browser: puppeteer.Browser | undefined const installedBrowser = await getCachedBrowser(browserName) try { browser = await puppeteer.launch({ browser: browserName, executablePath: installedBrowser?.executablePath, args: ['--no-sandbox'] }) return { ranInstaller: false, success: true } } catch (error) { if (installIfUnavailable) { await installBrowser(browserName) return { ...(await testInstalledBrowser(browserName, false)), ranInstaller: true } satisfies TestInstalledBrowserResult } debug('Browser not installed: %O', error) return { ranInstaller: false, success: false } } finally { await browser?.close() } } /** * Tests if the Puppeteer Chrome (or Chromium) browser is installed. * @param installIfUnavailable - Whether to install the browser if it's not available. * @returns A promise that resolves to an object containing the installation status and whether the installer was run. */ export async function testInstalledChromeBrowser( installIfUnavailable = false ): Promise<TestInstalledBrowserResult> { return await testInstalledBrowser('chrome', installIfUnavailable) } /** * Tests if the Puppeteer Firefox browser is installed. * @param installIfUnavailable - Whether to install the browser if it's not available. * @returns A promise that resolves to an object containing the installation status and whether the installer was run. */ export async function testInstalledFirefoxBrowser( installIfUnavailable = false ): Promise<TestInstalledBrowserResult> { return await testInstalledBrowser('firefox', installIfUnavailable) }