From 52af8c087cd5ddfa7cda547964f2565852e76287 Mon Sep 17 00:00:00 2001 From: Jack Franklin Date: Mon, 15 Feb 2021 10:34:33 +0000 Subject: [PATCH] fix: improve TS types for launching browsers This commit tidies up the quite confusing state of all the various types required to launch a browser. As we saw when upgrading DevTools (https://source.chromium.org/chromium/chromium/src/+/master:third_party/devtools-frontend/src/test/conductor/hooks.ts;l=77), we had to define our launch options variable like so: ```ts const opts: puppeteer.LaunchOptions & puppeteer.ChromeArgOptions & puppeteer.BrowserOptions = { ... }; ``` This commit fixes that by introducing `AllNodeLaunchOptions`, which is defined as the intersection of all the above types. Additionally, the types defined as `ChromeArgOptions` are actually used for launching both Chrome and Firefox, so I have renamed them to `BrowserArgOptions`, and therefore this change is breaking because anyone using `ChromeArgOptions` in their types will need to switch. BREAKING CHANGE: renamed type `ChromeArgOptions` to `BrowserLaunchArgumentOptions` BREAKING CHANGE: renamed type `BrowserOptions` to `BrowserConnectOptions` --- src/api-docs-entry.ts | 11 +++-- src/common/BrowserConnector.ts | 18 ++++++-- src/common/Puppeteer.ts | 4 +- src/node/LaunchOptions.ts | 84 +++++++++++++++++++++++++++++++++- src/node/Launcher.ts | 30 ++++-------- src/node/Puppeteer.ts | 13 ++++-- 6 files changed, 124 insertions(+), 36 deletions(-) diff --git a/src/api-docs-entry.ts b/src/api-docs-entry.ts index 2fb85cef92c89..7b9aadf00006c 100644 --- a/src/api-docs-entry.ts +++ b/src/api-docs-entry.ts @@ -14,8 +14,11 @@ * limitations under the License. */ -import { LaunchOptions, ChromeArgOptions } from './node/LaunchOptions.js'; -import { BrowserOptions } from './common/BrowserConnector.js'; +import { + LaunchOptions, + BrowserLaunchArgumentOptions, +} from './node/LaunchOptions.js'; +import { BrowserConnectOptions } from './common/BrowserConnector.js'; import { Product } from './common/Product.js'; import { Browser } from './common/Browser.js'; import { ConnectOptions } from './common/Puppeteer.js'; @@ -95,8 +98,8 @@ export * from 'devtools-protocol/types/protocol'; */ export declare function launch( options?: LaunchOptions & - ChromeArgOptions & - BrowserOptions & { + BrowserLaunchArgumentOptions & + BrowserConnectOptions & { product?: Product; extraPrefsFirefox?: Record; } diff --git a/src/common/BrowserConnector.ts b/src/common/BrowserConnector.ts index 5da9cbc144284..1aa7b91f78b1e 100644 --- a/src/common/BrowserConnector.ts +++ b/src/common/BrowserConnector.ts @@ -24,12 +24,24 @@ import { Viewport } from './PuppeteerViewport.js'; import { isNode } from '../environment.js'; /** - * Generic browser options that can be passed when launching any browser. + * Generic browser options that can be passed when launching any browser or when + * connecting to an existing browser instance. * @public */ -export interface BrowserOptions { +export interface BrowserConnectOptions { + /** + * Whether to ignore HTTPS errors during navigation. + * @defaultValue false + */ ignoreHTTPSErrors?: boolean; + /** + * Sets the viewport for each page. + */ defaultViewport?: Viewport; + /** + * Slows down Puppeteer operations by the specified amount of milliseconds to + * aid debugging. + */ slowMo?: number; } @@ -46,7 +58,7 @@ const getWebSocketTransportClass = async () => { * @internal */ export const connectToBrowser = async ( - options: BrowserOptions & { + options: BrowserConnectOptions & { browserWSEndpoint?: string; browserURL?: string; transport?: ConnectionTransport; diff --git a/src/common/Puppeteer.ts b/src/common/Puppeteer.ts index 6062c18624a5d..5a475c58442ba 100644 --- a/src/common/Puppeteer.ts +++ b/src/common/Puppeteer.ts @@ -25,7 +25,7 @@ import { CustomQueryHandler, } from './QueryHandler.js'; import { Product } from './Product.js'; -import { connectToBrowser, BrowserOptions } from './BrowserConnector.js'; +import { connectToBrowser, BrowserConnectOptions } from './BrowserConnector.js'; import { PredefinedNetworkConditions, networkConditions, @@ -39,7 +39,7 @@ export interface CommonPuppeteerSettings { isPuppeteerCore: boolean; } -export interface ConnectOptions extends BrowserOptions { +export interface ConnectOptions extends BrowserConnectOptions { browserWSEndpoint?: string; browserURL?: string; transport?: ConnectionTransport; diff --git a/src/node/LaunchOptions.ts b/src/node/LaunchOptions.ts index 0eb99b69808d5..306edd6eb94b0 100644 --- a/src/node/LaunchOptions.ts +++ b/src/node/LaunchOptions.ts @@ -13,16 +13,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +import { BrowserConnectOptions } from '../common/BrowserConnector.js'; +import { Product } from '../common/Product.js'; + /** * Launcher options that only apply to Chrome. * * @public */ -export interface ChromeArgOptions { +export interface BrowserLaunchArgumentOptions { + /** + * Whether to run the browser in headless mode. + * @defaultValue true + */ headless?: boolean; - args?: string[]; + /** + * Path to a user data directory. + * {@link https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md | see the Chromium docs} + * for more info. + */ userDataDir?: string; + /** + * Whether to auto-open a DevTools panel for each tab. If this is set to + * `true`, then `headless` will be set to `false` automatically. + * @defaultValue `false` + */ devtools?: boolean; + /** + * Additional command line arguments to pass to the browser instance. + */ + args?: string[]; } /** @@ -30,13 +51,72 @@ export interface ChromeArgOptions { * @public */ export interface LaunchOptions { + /** + * Path to a browser executable to use instead of the bundled Chromium. Note + * that Puppeteer is only guaranteed to work with the bundled Chromium, so use + * this setting at your own risk. + */ executablePath?: string; + /** + * If `true`, do not use `puppeteer.defaultArgs()` when creating a browser. If + * an array is provided, these args will be filtered out. Use this with care - + * you probably want the default arguments Puppeteer uses. + * @defaultValue false + */ ignoreDefaultArgs?: boolean | string[]; + /** + * Close the browser process on `Ctrl+C`. + * @defaultValue `true` + */ handleSIGINT?: boolean; + /** + * Close the browser process on `SIGTERM`. + * @defaultValue `true` + */ handleSIGTERM?: boolean; + /** + * Close the browser process on `SIGHUP`. + * @defaultValue `true` + */ handleSIGHUP?: boolean; + /** + * Maximum time in milliseconds to wait for the browser to start. + * Pass `0` to disable the timeout. + * @defaultValue 30000 (30 seconds). + */ timeout?: number; + /** + * If true, pipes the browser process stdout and stderr to `process.stdout` + * and `process.stderr`. + * @defaultValue false + */ dumpio?: boolean; + /** + * Specify environment variables that will be visible to the browser. + * @defaultValue The contents of `process.env`. + */ env?: Record; + /** + * Connect to a browser over a pipe instead of a WebSocket. + * @defaultValue false + */ pipe?: boolean; + /** + * Which browser to launch. + * @defaultValue `chrome` + */ + product?: Product; + /** + * {@link https://developer.mozilla.org/en-US/docs/Mozilla/Preferences/Preference_reference | Additional preferences } that can be passed when launching with Firefox. + */ + extraPrefsFirefox?: Record; } + +/** + * Utility type exposed to enable users to define options that can be passed to + * `puppeteer.launch` without having to list the set of all types. + * @public + */ +export type PuppeteerNodeLaunchOptions = BrowserLaunchArgumentOptions & + LaunchOptions & + BrowserConnectOptions; diff --git a/src/node/Launcher.ts b/src/node/Launcher.ts index bcfb28d5506a6..61ddbe74ca3e6 100644 --- a/src/node/Launcher.ts +++ b/src/node/Launcher.ts @@ -25,8 +25,10 @@ import { promisify } from 'util'; const mkdtempAsync = promisify(fs.mkdtemp); const writeFileAsync = promisify(fs.writeFile); -import { ChromeArgOptions, LaunchOptions } from './LaunchOptions.js'; -import { BrowserOptions } from '../common/BrowserConnector.js'; +import { + BrowserLaunchArgumentOptions, + PuppeteerNodeLaunchOptions, +} from './LaunchOptions.js'; import { Product } from '../common/Product.js'; /** @@ -34,9 +36,9 @@ import { Product } from '../common/Product.js'; * @public */ export interface ProductLauncher { - launch(object); + launch(object: PuppeteerNodeLaunchOptions); executablePath: () => string; - defaultArgs(object); + defaultArgs(object: BrowserLaunchArgumentOptions); product: Product; } @@ -58,9 +60,7 @@ class ChromeLauncher implements ProductLauncher { this._isPuppeteerCore = isPuppeteerCore; } - async launch( - options: LaunchOptions & ChromeArgOptions & BrowserOptions = {} - ): Promise { + async launch(options: PuppeteerNodeLaunchOptions = {}): Promise { const { ignoreDefaultArgs = false, args = [], @@ -152,11 +152,7 @@ class ChromeLauncher implements ProductLauncher { } } - /** - * @param {!Launcher.ChromeArgOptions=} options - * @returns {!Array} - */ - defaultArgs(options: ChromeArgOptions = {}): string[] { + defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] { const chromeArguments = [ '--disable-background-networking', '--enable-features=NetworkService,NetworkServiceInProcess', @@ -230,13 +226,7 @@ class FirefoxLauncher implements ProductLauncher { this._isPuppeteerCore = isPuppeteerCore; } - async launch( - options: LaunchOptions & - ChromeArgOptions & - BrowserOptions & { - extraPrefsFirefox?: { [x: string]: unknown }; - } = {} - ): Promise { + async launch(options: PuppeteerNodeLaunchOptions = {}): Promise { const { ignoreDefaultArgs = false, args = [], @@ -346,7 +336,7 @@ class FirefoxLauncher implements ProductLauncher { return 'firefox'; } - defaultArgs(options: ChromeArgOptions = {}): string[] { + defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] { const firefoxArguments = ['--no-remote', '--foreground']; if (os.platform().startsWith('win')) { firefoxArguments.push('--wait-for-browser'); diff --git a/src/node/Puppeteer.ts b/src/node/Puppeteer.ts index 924d2fa96e958..84170f89f0287 100644 --- a/src/node/Puppeteer.ts +++ b/src/node/Puppeteer.ts @@ -20,8 +20,11 @@ import { ConnectOptions, } from '../common/Puppeteer.js'; import { BrowserFetcher, BrowserFetcherOptions } from './BrowserFetcher.js'; -import { LaunchOptions, ChromeArgOptions } from './LaunchOptions.js'; -import { BrowserOptions } from '../common/BrowserConnector.js'; +import { + LaunchOptions, + BrowserLaunchArgumentOptions, +} from './LaunchOptions.js'; +import { BrowserConnectOptions } from '../common/BrowserConnector.js'; import { Browser } from '../common/Browser.js'; import Launcher, { ProductLauncher } from './Launcher.js'; import { PUPPETEER_REVISIONS } from '../revisions.js'; @@ -146,8 +149,8 @@ export class PuppeteerNode extends Puppeteer { */ launch( options: LaunchOptions & - ChromeArgOptions & - BrowserOptions & { + BrowserLaunchArgumentOptions & + BrowserConnectOptions & { product?: Product; extraPrefsFirefox?: Record; } = {} @@ -215,7 +218,7 @@ export class PuppeteerNode extends Puppeteer { * @param options - Set of configurable options to set on the browser. * @returns The default flags that Chromium will be launched with. */ - defaultArgs(options: ChromeArgOptions = {}): string[] { + defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] { return this._launcher.defaultArgs(options); }