@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
text/typescript
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)
}