Puppeteer CreatePageOptions 详解:用 type、windowBounds 与 background 精准控制新建页面与窗口
CreatePageOptions 是 Puppeteer 中定义「新建页面」行为方式的统一选项类型,由 Browser.newPage() 与 BrowserContext.newPage() 接收,用于决定新页面以**标签页(tab)还是独立窗口(window)**形式创建,并可同时指定窗口边界以及页面是否在后台创建。读完本文,你将掌握该类型的全部字段含义、跨协议(CDP 与 WebDriver BiDi)的底层映射行为,以及如何在真实代码中写出可用的新建页面调用。
类型定义总览
按 docs/api/puppeteer.createpageoptions.md 的签名,CreatePageOptions 是一个**可辨识联合类型(discriminated union)**与交叉类型的组合,源码定义位于 packages/puppeteer-core/src/api/Browser.ts#L255-L270:
export type CreatePageOptions = (
| {
type?: 'tab';
}
| {
type: 'window';
windowBounds?: WindowBounds;
}
) & {
/**
* Whether to create the page in the background.
*
* @defaultValue `false`
*/
background?: boolean;
};
该类型由两个分支求交、再与 { background?: boolean } 交叉得到:
- tab 分支:
type?: 'tab'。type为可选,省略时默认按标签页处理; - window 分支:
type: 'window'为必填字面量,并携带可选的windowBounds?: WindowBounds; - 公共字段:
background?: boolean,默认为false。
由于是联合类型与交叉类型结合,TypeScript 会根据你传入的 type 值自动收窄合法字段:传 type: 'window' 时才能写 windowBounds;若完全不传 type(等价于 tab),则 windowBounds 不可用。
字段语义与取值范围
下表逐字段说明 CreatePageOptions 的语义,依据来自类型文档与 Browser.ts 的源码注释:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
type |
'tab' | 'window' |
否 | 'tab' |
指定新页面以浏览器标签页还是独立浏览器窗口形式创建 |
windowBounds |
WindowBounds |
否 | — | 仅当 type: 'window' 时允许出现;控制新窗口的位置与尺寸 |
background |
boolean |
否 | false |
是否在后台创建页面(不抢占前台焦点) |
type:标签页还是窗口
type 是决定页面挂载形态的核心开关:
type: 'tab'或不传该字段:页面作为当前浏览器窗口中的新标签页创建,也是传统browser.newPage()的默认行为;type: 'window':页面被创建为独立的操作系统级浏览器窗口。只有当type收窄为'window'时,windowBounds才有意义。
windowBounds:独立窗口的几何信息
windowBounds 本身是另一个公开接口 WindowBounds,其源码同样定义在 packages/puppeteer-core/src/api/Browser.ts#L239-L245:
export interface WindowBounds {
left?: number;
top?: number;
width?: number;
height?: number;
windowState?: WindowState;
}
各属性含义:
left/top:新窗口左上角在屏幕坐标系中的坐标(像素);width/height:新窗口的内容宽度与高度(像素);windowState:窗口状态枚举,取值为'normal' | 'minimized' | 'maximized' | 'fullscreen',类型定义见 packages/puppeteer-core/src/api/Browser.ts#L234。
这些几何属性都属于可选字段,你可以只指定其中的一部分;未指定的维度由浏览器按默认策略决定。
background:是否后台创建
background?: boolean 是所有分支共有的开关,源码注释明确指出其默认值为 false。设置为 true 时,新页面/窗口在后台完成创建,不会打断当前用户正在浏览的前台页面,适用于预加载、离屏抓取等不希望抢占焦点的自动化场景。
使用入口与代码示例
CreatePageOptions 是以下两个 API 的入口参数(两者签名都声明为 newPage(options?: CreatePageOptions): Promise<Page>):
Browser.newPage():在默认浏览器上下文中新建页面;BrowserContext.newPage():在指定浏览器上下文中新建页面(包括通过browser.createBrowserContext()创建的隔离上下文)。
默认:普通标签页
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
// 不传 options,等价于 { type: 'tab' },在当前窗口新建标签页
const tab = await browser.newPage();
await tab.goto('https://example.com');
独立窗口 + 指定几何信息
const windowPage = await browser.newPage({
type: 'window',
windowBounds: {
left: 100,
top: 50,
width: 900,
height: 700,
},
});
await windowPage.goto('https://example.com');
若希望新窗口打开后直接最大化,可将 windowState 一并传入:
const maximized = await browser.newPage({
type: 'window',
windowBounds: { windowState: 'maximized' },
});
后台创建页面
// 在后台预创建页面,避免打断当前前台操作
const backgroundPage = await browser.newPage({ background: true });
在指定 BrowserContext 中创建窗口
const context = await browser.createBrowserContext();
const pageInContext = await context.newPage({
type: 'window',
windowBounds: { width: 1024, height: 768 },
});
await context.close();
源码级底层映射:CDP 与 WebDriver BiDi 的差异实现
newPage(options) 在 Browser.ts 被声明为抽象方法,由 CDP 与 BiDi 两套协议实现分别落地,二者对同一份 CreatePageOptions 的解读方式既有对应关系也有差异。
CDP 实现:映射到 Target.createTarget
Chrome 系走 DevTools Protocol,CDP 实现位于 packages/puppeteer-core/src/cdp/BrowserContext.ts#L132-L135,最终汇聚到 CdpBrowser._createPageInContext(packages/puppeteer-core/src/cdp/Browser.ts#L414-L455),核心逻辑是将各字段逐一对齐到 Target.createTarget 参数:
const windowBounds =
options?.type === 'window' ? options.windowBounds : undefined;
const {targetId} = await this.#connection.send('Target.createTarget', {
url: 'about:blank',
browserContextId: contextId || undefined,
left: windowBounds?.left,
top: windowBounds?.top,
width: windowBounds?.width,
height: windowBounds?.height,
windowState: windowBounds?.windowState,
// Works around crbug.com/454825274.
newWindow: hasTargets && options?.type === 'window' ? true : undefined,
background: options?.background,
});
从该实现可以读出几个关键行为:
- 新建页面统一使用
about:blank作为初始 URL; windowBounds的left/top/width/height/windowState被逐项平铺透传给 CDP 命令;newWindow参数只有在「该上下文已存在其他 target 且 请求了type: 'window'」时才置为true,源码注释标明这是为了规避上游 Chromium 缺陷 crbug.com/454825274,而background原样透传给协议;- 创建后通过
waitForTarget等待目标初始化完成,再经target.page()取回Page实例。
因此 browser.newPage()(packages/puppeteer-core/src/cdp/Browser.ts#L410-L412)本质是对默认上下文 newPage(options) 的转发。
WebDriver BiDi 实现:区分创建类型并后置应用窗口边界
Firefox 等走 WebDriver BiDi 的实现位于 packages/puppeteer-core/src/bidi/BrowserContext.ts#L206-L242,逻辑与 CDP 有两点明显差异:
const type =
options?.type === 'window'
? Bidi.BrowsingContext.CreateType.Window
: Bidi.BrowsingContext.CreateType.Tab;
const context = await this.userContext.createBrowsingContext(type, {
background: options?.background,
});
// ...
if (options?.type === 'window' && options?.windowBounds !== undefined) {
try {
await this.browser().setWindowBounds(
context.windowId,
options.windowBounds,
);
} catch (error) {
// Tolerate not supporting `browser.setClientWindowState`. Only log it.
this.#logger?.(DEBUG_PREFIXES.error)?.(error);
}
}
- 创建类型被显式映射为 BiDi 的
CreateType.Window或CreateType.Tab; background在创建浏览上下文时作为参数传入;- 与 CDP 不同,BiDi 侧先创建出上下文与
Page,若指定了windowBounds,则通过browser.setWindowBounds(context.windowId, options.windowBounds)在创建之后设置窗口边界; - 该实现还尝试为新页面套用上下文配置的默认视口(
defaultViewport),并对不支持browsingContext.setViewport/browser.setClientWindowState的远端环境做了容错——异常仅记录日志而不会中断流程。
从源码结构看,windowBounds 能否生效受底层协议能力影响:CDP 通过创建时的 Target.createTarget 参数一步到位,而 BiDi 依赖创建后的 setWindowBounds,两者都体现了「窗口级能力仅在有真实浏览器窗口的环境下才有意义」这一前提。对于 headless 等无窗口场景,type: 'window' 与 windowBounds 的实际可视效果可能受限,建议先在你使用的浏览器与协议组合上做验证。
相关 API 与文档索引
CreatePageOptions 在 API 生态中与下列成员配套使用,可对照查阅:
- docs/api/puppeteer.browser.newpage.md:
Browser.newPage()方法文档; - docs/api/puppeteer.browsercontext.newpage.md:
BrowserContext.newPage()方法文档; - docs/api/puppeteer.windowbounds.md:
WindowBounds接口完整说明; - docs/api/puppeteer.windowstate.md:
windowState取值的枚举定义; - packages/puppeteer-core/src/api/BrowserContext.ts:抽象层中声明
newPage的基础 API; - docs/api/index.md:Puppeteer API 全集入口。
小结
CreatePageOptions 虽是一个体量很小的类型,却精确刻画了「在哪里、以什么形态、前台还是后台」这三个新建页面的核心决策维度:type 决定标签页或独立窗口,windowBounds 决定窗口几何与状态,background 决定是否抢占前台。结合 Browser.ts 的类型定义与 CDP、BiDi 两套源码实现,你可以据此编写出行为可预期、同时适配 Chrome 与 Firefox 协议栈的新建页面代码。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00