从 GetInstalledBrowsersOptions 入手:用 @puppeteer/browsers 枚举缓存中已安装的浏览器
发布时间:2026/9/8 18:11:49 锦皓数字建站

从 GetInstalledBrowsersOptions 入手用 puppeteer/browsers 枚举缓存中已安装的浏览器【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteerpuppeteer/browsers位于仓库packages/browsers/既提供npx puppeteer/browsers这样的 CLI也提供一套程序化 API用来下载、缓存、管理并启动 Chrome/Chromium、Chrome for Testing、ChromeDriver 与 Firefox 等浏览器二进制。其中getInstalledBrowsers(options)与它的唯一入参类型GetInstalledBrowsersOptions是“盘点”本机缓存目录中到底装了哪些浏览器、版本与平台的关键入口——相当于给浏览器缓存做了一次“库存清点”。本文以 GetInstalledBrowsersOptions 接口文档为主体结合其配套的 getInstalledBrowsers() 函数文档以及packages/browsers/下的源码实现与测试用例带你弄清楚cacheDir到底指向哪里、缓存目录的内部结构如何解析、返回值InstalledBrowser[]携带哪些元数据以及如何在真实工程中用它做浏览器安装状态的查询与校验。读完你将能编写出“先查询、后安装/启动”的健壮脚本并理解browsers list这个 CLI 子命令的底层逻辑。一、接口定位一个属性支撑起整个“库存查询”入口GetInstalledBrowsersOptions是puppeteer/browsers公共 API 中getInstalledBrowsers()的入参对象类型。它的源码声明位于 packages/browsers/src/install.ts官方接口文档的描述是export interface GetInstalledBrowsersOptions { /** * The path to the root of the cache directory. */ cacheDir: string; }对应类型签名如下export interface GetInstalledBrowsersOptionsProperties 一览PropertyModifiersTypeDescriptionDefaultcacheDir—stringThe path to the root of the cache directory缓存目录的根路径无必填要点提炼该接口只包含一个字段cacheDir且是必填的string文档中没有任何默认值。cacheDir的语义是 “path to the root of the cache directory”即缓存目录的根而不是某个具体浏览器或某个具体版本子目录的路径。它描述的是一个“查询动作”的输入调用方声明“请帮我去这个目录里看看装了什么”。把接口放进调用场景其搭档函数 getInstalledBrowsers() 的签名是export declare function getInstalledBrowsers( options: GetInstalledBrowsersOptions, ): PromiseInstalledBrowser[];Returns:PromiseInstalledBrowser[]—— 即返回一个InstalledBrowser对象数组数组中的每个元素代表一个“在缓存目录中检测到的已安装浏览器”。二、cacheDir 到底是什么缓存目录的结构约定要正确填写cacheDir就必须理解puppeteer/browsers的磁盘缓存布局。在 Cache.ts 的类注释中给出了明确的层级约定rootDir ├── browser1 # 例如 chrome / firefox / chromedriverBrowser 枚举名 │ └── platform-buildId # 例如 linux-116.0.5793.0 │ └── 具体浏览器二进制内容 └── browser2 └── platform-buildId落到代码上packages/browsers/src/Cache.tsbrowserRoot(browser: Browser): string { return path.join(this.#rootDir, browser); }也就是说第一层按浏览器种类Browser枚举建目录第二层以platform-buildId命名的安装目录例如chrome/linux-116.0.5793.0每个浏览器根目录下还可能有一个.metadata文件用来记录别名如stable、canary映射到具体buildId以及自定义 provider 写入的可执行文件相对路径详见下文测试部分。因此当 Puppeteer 生态以默认配置运行时cacheDir的默认值来自 packages/puppeteer-core/src/common/Configuration.ts 的注释说明defaultValue path.join(os.homedir(), .cache, puppeteer)即默认根目录通常为~/.cache/puppeteerLinux/macOS。如果你在代码里显式传了自定义的cacheDir比如/tmp/my-browser-cache那么后续install、uninstall、launch和getInstalledBrowsers必须使用同一个根目录查询结果才与实际安装状态一致。需要特别注意cacheDir指的是缓存根的父级路径而不是形如.../chrome/linux-116.0.5793.0的深层目录。传入错误层级会导致检测不到浏览器。三、底层实现getInstalledBrowsers 是如何“扫盘”的getInstalledBrowsers的实现非常轻量——它把所有工作委托给了Cache类packages/browsers/src/install.ts/** * Returns metadata about browsers installed in the cache directory. * * public */ export async function getInstalledBrowsers( options: GetInstalledBrowsersOptions, ): PromiseInstalledBrowser[] { return new Cache(options.cacheDir).getInstalledBrowsers(); }真正执行目录扫描的是 Cache.getInstalledBrowsers()getInstalledBrowsers(): InstalledBrowser[] { if (!fs.existsSync(this.#rootDir)) { return []; } const types fs.readdirSync(this.#rootDir); const browsers types.filter((t): t is Browser { return (Object.values(Browser) as string[]).includes(t); }); return browsers.flatMap(browser { const files fs.readdirSync(this.browserRoot(browser)); return files .map(file { const result parseFolderPath( path.join(this.browserRoot(browser), file), ); if (!result) { return null; } return new InstalledBrowser( this, browser, result.buildId, result.platform as BrowserPlatform, ); }) .filter((item: InstalledBrowser | null): item is InstalledBrowser { return item ! null; }); }); }从源码结构可以总结出它的判定流程容错优先若cacheDir指向的根目录根本不存在直接返回空数组[]不抛异常——这意味着“查询一个尚未初始化的缓存目录”是一种合法且安全的状态。只识别已知浏览器第一层子目录中只有名字恰好命中Browser枚举值的才会被纳入扫描filterObject.values(Browser).includes(t)。例如仓库 docs/browsers-api/browsers.browser.md 中定义的CHROME、FIREFOX等枚举名所对应的目录名。混入的无关目录会被自动忽略。目录名解析对每个浏览器根目录下的子目录调用parseFolderPath解析packages/browsers/src/Cache.tsfunction parseFolderPath( folderPath: string, ): {platform: string; buildId: string} | undefined { const name path.basename(folderPath); const splits name.split(-); if (splits.length ! 2) { return; } const [platform, buildId] splits; if (!buildId || !platform) { return; } return {platform, buildId}; }可以看到解析依赖“恰好两段”的命名约定platform-buildId。之所以成立是因为 Chrome 的buildId如116.0.5793.0用点号分隔而不用连字符不满足两段格式或段为空的目录会被跳过返回null后过滤掉。这是实现层面的推断性约定命名必须与Cache.installationDir()的写入格式保持一致否则装得进去却查不出来。构造返回值每个通过解析的目录会被包装成一个 InstalledBrowser 实例构造函数内部通过cache.computeExecutablePath({...})计算出该浏览器的可执行文件绝对路径。InstalledBrowser对外暴露的关键元数据见 docs/browsers-api/browsers.installedbrowser.md包括成员含义browserBrowser枚举标识是哪一种浏览器buildId具体版本号/构建号如116.0.5793.0platformBrowserPlatform如linux、mac、win64见 docs/browsers-api/browsers.browserplatform.mdexecutablePath可执行文件chrome/firefox/chromedriver 等的完整绝对路径pathgetter安装目录根路径等价于Cache.installationDir()的结果四、实战示例查询已安装的浏览器并打印元数据与 CLI 子命令npx puppeteer/browsers list的行为一致程序化调用getInstalledBrowsers的典型用法如下import { getInstalledBrowsers, install, Browser, BrowserPlatform, } from puppeteer/browsers; const cacheDir /tmp/my-browser-cache; // 必须与 install 时使用的 cacheDir 一致 // 1) 先确保装了一个浏览器幂等已存在则复用缓存 await install({ cacheDir, browser: Browser.CHROME, buildId: stable, // 也支持具体 buildId 或 milestone如 116.0.5793.0 / 117 platform: BrowserPlatform.LINUX, // 省略时自动探测 }); // 2) 盘点缓存目录里所有已安装浏览器 const installed await getInstalledBrowsers({cacheDir}); for (const browser of installed) { console.log(${browser.browser}${browser.buildId} (${browser.platform})); console.log( executable: ${browser.executablePath}); } if (installed.length 0) { console.log(缓存目录 ${cacheDir} 中没有检测到任何已安装的浏览器。); }输出效果形如chrome116.0.5793.0 (linux) executable: /tmp/my-browser-cache/chrome/linux-116.0.5793.0/chrome-linux64/chrome这段脚本对应了仓库 CLI 中list子命令的等价逻辑——packages/browsers/src/CLI.ts 内部正是先new Cache(cacheDir)再调用cache.getInstalledBrowsers()然后逐行打印for (const browser of browsers) { console.log( ${browser.browser}${browser.buildId} (${browser.platform}) ${browser.executablePath}, ); }CLI 侧对应命令为# 列出默认缓存目录下的已安装浏览器 npx puppeteer/browsers list # 列出指定缓存目录等价于传入 cacheDir: /tmp/my-browser-cache npx puppeteer/browsers list --path /tmp/my-browser-cache所以“程序化 API 传cacheDir”与“CLI 传--path”指向的是同一件事指定缓存根目录。五、实践中的典型用法查询 按需安装/启动GetInstalledBrowsersOptions最常见的实战场景是避免盲目重复安装先查询缓存命中则直接复用未命中再安装。可以这样组织伪代码思路import {getInstalledBrowsers, install, launch, Browser} from puppeteer/browsers; const cacheDir process.env.BROWSER_CACHE_DIR ?? /tmp/my-browser-cache; const desiredBuildId 116.0.5793.0; async function ensureBrowser() { const installed await getInstalledBrowsers({cacheDir}); const found installed.find(b { return b.browser Browser.CHROME b.buildId desiredBuildId; }); if (!found) { console.log(未检测到目标版本开始安装…); await install({ cacheDir, browser: Browser.CHROME, buildId: desiredBuildId, // 如需定位问题可开启调试日志 // 在命令行使用 env NODE_DEBUGpuppeteer:browsers:* 观察 install/cache 各环节 }); } const current await getInstalledBrowsers({cacheDir}); const target current.find(b b.buildId desiredBuildId)!; return target.executablePath; // 之后可直接交给 launch() 或 Puppeteer 使用 }几点工程化建议用同一个cacheDir贯穿 install/get/launch。若 scripts 里不一致会出现“安装了却查不到”“查到了却启动失败”的隐性 bug当配置错误时Puppeteer 的错误提示也会引导你检查 cache path见 packages/puppeteer-core/src/node/BrowserLauncher.ts 相关报错文案。观察缓存层行为puppeteer/browsers支持NODE_DEBUGpuppeteer:browsers:cache来输出缓存操作日志相关调试通道定义见 packages/browsers/src/debug.ts排查查询结果异常时非常有用。启动前做兜底getInstalledBrowsers返回的executablePath可以直接作为launch()的输入launch 相关选项见 docs/browsers-api/browsers.launchoptions.md避免再次解析目录。六、源码与测试如何验证接口行为仓库的单元测试对该接口的两种关键场景做了覆盖是理解cacheDir语义的最好佐证“安装后必然可被查询到”。在 packages/browsers/test/src/chrome/install.test.ts 中测试先通过install({cacheDir: tmpDir, browser: Browser.CHROME, ...})完成安装随后const cache new Cache(tmpDir); const installed cache.getInstalledBrowsers(); assert.deepStrictEqual(browser, installed[0]); assert.deepStrictEqual(browser!.executablePath, installed[0]?.executablePath);这验证了只要cacheDir传对安装结果与查询结果是一一对应的且InstalledBrowser的executablePath会被原样返回。“自定义 provider 写入的可执行路径也能被正确读出”。在 packages/browsers/test/src/installWithProviders.test.ts 中测试确认当使用自定义 provider 安装时安装程序会把相对可执行路径持久化到.metadata的executablePaths键为${platform}-${buildId}随后const installed await getInstalledBrowsers({cacheDir: tmpDir}); const found installed.find(b { return b.buildId testChromeBuildId; }); assert.strictEqual( found?.executablePath, result.executablePath, getInstalledBrowsers should return the correct executable path, );这说明cacheDir查询不只是“看目录名”还会回读.metadata中的可执行路径记录对应 Cache.computeExecutablePath() 中“优先使用存储路径、其次使用默认路径”的逻辑。同一个文件 packages/browsers/test/src/installWithProviders.test.ts 里还有一处验证自定义路径写入后getInstalledBrowsers({cacheDir: tmpDir})能拾取到该记录。七、小结使用 GetInstalledBrowsersOptions 的要点清单关注点结论cacheDir是否必填必填无默认值cacheDir的层级缓存根目录内部布局为cacheDir/browser/platform-buildId根目录不存在时返回[]不抛错返回类型PromiseInstalledBrowser[]元素含browser/buildId/platform/executablePath/path目录识别的判据一级目录名须命中Browser枚举二级目录名须可解析成恰好两段platform-buildId与 CLI 的关系getInstalledBrowsers({cacheDir})等价于npx puppeteer/browsers list --path cacheDir的核心逻辑见 CLI.ts联动约束必须与install()/launch()/uninstall()使用同一cacheDir否则状态不一致GetInstalledBrowsersOptions虽然只有cacheDir一个字段却是浏览器管理链路上“安装—查询—启动—卸载”闭环里的关键拼图。理解它背后基于目录约定的检测机制你就能在 CI 缓存复用、本地多版本浏览器管理、以及 Puppeteer 集成场景中准确判断“目标浏览器到底在不在、在哪里”。【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。