chore(agnostification): split up root Puppeteer class (#6504)

The `Puppeteer` class had two concerns:

* connect to an existing browser
* launch a new browser

The first of those concerns is needed in all environments, but the
second is only needed in Node.
https://github.com/puppeteer/puppeteer/pull/6484 landing enabled us to
pull the `Puppeteer` class apart into two:

1. `Puppeteer` which hosts the behaviour for connecting to existing
   browsers.
2. `PuppeteerNode`, which extends `Puppeteer` and also adds the ability
   to launch a new browser.

This is a non-breaking change, because Node users will still get an
instance of a class with all the methods they expect, but it'll be a
`PuppeteerNode` rather than `Puppeteer`. I don't expect this to cause
people any issues.

We also now have new files that are effectively the entry points for
Puppeteer:

* `node.ts`: the main entry point for Puppeteer on Node.
* `web.ts`: the main entry point for Puppeteer on the web.
* `node-puppeteer-core.ts`: for those using puppeteer-core (which only
  exists in Node, not on the web).
This commit is contained in:
Jack Franklin 2020-10-13 16:19:26 +01:00 committed by GitHub
parent f3086d7c97
commit e655bb6ca2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 549 additions and 281 deletions

View File

@ -25,5 +25,5 @@
* This means that we can publish to CJS and ESM whilst maintaining the expected
* import behaviour for CJS and ESM users.
*/
const puppeteerExport = require('./lib/cjs/puppeteer/index-core');
const puppeteerExport = require('./lib/cjs/puppeteer/node-puppeteer-core');
module.exports = puppeteerExport.default;

View File

@ -25,5 +25,5 @@
* This means that we can publish to CJS and ESM whilst maintaining the expected
* import behaviour for CJS and ESM users.
*/
const puppeteerExport = require('./lib/cjs/puppeteer/index');
const puppeteerExport = require('./lib/cjs/puppeteer/node');
module.exports = puppeteerExport.default;

View File

@ -4,7 +4,7 @@
## Browser class
A Browser is created when Puppeteer connects to a Chromium instance, either through [Puppeteer.launch()](./puppeteer.puppeteer.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md)<!-- -->.
A Browser is created when Puppeteer connects to a Chromium instance, either through [PuppeteerNode.launch()](./puppeteer.puppeteernode.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md)<!-- -->.
<b>Signature:</b>

View File

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [ConnectOptions](./puppeteer.connectoptions.md) &gt; [browserURL](./puppeteer.connectoptions.browserurl.md)
## ConnectOptions.browserURL property
<b>Signature:</b>
```typescript
browserURL?: string;
```

View File

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [ConnectOptions](./puppeteer.connectoptions.md) &gt; [browserWSEndpoint](./puppeteer.connectoptions.browserwsendpoint.md)
## ConnectOptions.browserWSEndpoint property
<b>Signature:</b>
```typescript
browserWSEndpoint?: string;
```

View File

@ -0,0 +1,22 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [ConnectOptions](./puppeteer.connectoptions.md)
## ConnectOptions interface
<b>Signature:</b>
```typescript
export interface ConnectOptions extends BrowserOptions
```
<b>Extends:</b> [BrowserOptions](./puppeteer.browseroptions.md)
## Properties
| Property | Type | Description |
| --- | --- | --- |
| [browserURL](./puppeteer.connectoptions.browserurl.md) | string | |
| [browserWSEndpoint](./puppeteer.connectoptions.browserwsendpoint.md) | string | |
| [product](./puppeteer.connectoptions.product.md) | [Product](./puppeteer.product.md) | |
| [transport](./puppeteer.connectoptions.transport.md) | ConnectionTransport | |

View File

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [ConnectOptions](./puppeteer.connectoptions.md) &gt; [product](./puppeteer.connectoptions.product.md)
## ConnectOptions.product property
<b>Signature:</b>
```typescript
product?: Product;
```

View File

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [ConnectOptions](./puppeteer.connectoptions.md) &gt; [transport](./puppeteer.connectoptions.transport.md)
## ConnectOptions.transport property
<b>Signature:</b>
```typescript
transport?: ConnectionTransport;
```

View File

@ -9,7 +9,7 @@
| Class | Description |
| --- | --- |
| [Accessibility](./puppeteer.accessibility.md) | The Accessibility class provides methods for inspecting Chromium's accessibility tree. The accessibility tree is used by assistive technology such as [screen readers](https://en.wikipedia.org/wiki/Screen_reader) or [switches](https://en.wikipedia.org/wiki/Switch_access)<!-- -->. |
| [Browser](./puppeteer.browser.md) | A Browser is created when Puppeteer connects to a Chromium instance, either through [Puppeteer.launch()](./puppeteer.puppeteer.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md)<!-- -->. |
| [Browser](./puppeteer.browser.md) | A Browser is created when Puppeteer connects to a Chromium instance, either through [PuppeteerNode.launch()](./puppeteer.puppeteernode.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md)<!-- -->. |
| [BrowserContext](./puppeteer.browsercontext.md) | BrowserContexts provide a way to operate multiple independent browser sessions. When a browser is launched, it has a single BrowserContext used by default. The method [Browser.newPage](./puppeteer.browser.newpage.md) creates a page in the default browser context. |
| [BrowserFetcher](./puppeteer.browserfetcher.md) | BrowserFetcher can download and manage different versions of Chromium and Firefox. |
| [CDPSession](./puppeteer.cdpsession.md) | The <code>CDPSession</code> instances are used to talk raw Chrome Devtools Protocol. |
@ -27,7 +27,8 @@
| [Keyboard](./puppeteer.keyboard.md) | Keyboard provides an api for managing a virtual keyboard. The high level api is [Keyboard.type()](./puppeteer.keyboard.type.md)<!-- -->, which takes raw characters and generates proper keydown, keypress/input, and keyup events on your page. |
| [Mouse](./puppeteer.mouse.md) | The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport. |
| [Page](./puppeteer.page.md) | Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. |
| [Puppeteer](./puppeteer.puppeteer.md) | The main Puppeteer class. Provides the [launch](./puppeteer.puppeteer.launch.md) method to launch a browser.<!-- -->When you <code>require</code> or <code>import</code> the Puppeteer npm package you get back an instance of this class. |
| [Puppeteer](./puppeteer.puppeteer.md) | The main Puppeteer class.<!-- -->IMPORTANT: if you are using Puppeteer in a Node environment, you will get an instance of [PuppeteerNode](./puppeteer.puppeteernode.md) when you import or require <code>puppeteer</code>. That class extends <code>Puppeteer</code>, so has all the methods documented below as well as all that are defined on [PuppeteerNode](./puppeteer.puppeteernode.md)<!-- -->. |
| [PuppeteerNode](./puppeteer.puppeteernode.md) | Extends the main [Puppeteer](./puppeteer.puppeteer.md) class with Node specific behaviour for fetching and downloading browsers.<!-- -->If you're using Puppeteer in a Node environment, this is the class you'll get when you run <code>require('puppeteer')</code> (or the equivalent ES <code>import</code>). |
| [SecurityDetails](./puppeteer.securitydetails.md) | The SecurityDetails class represents the security details of a response that was received over a secure connection. |
| [Target](./puppeteer.target.md) | |
| [TimeoutError](./puppeteer.timeouterror.md) | TimeoutError is emitted whenever certain operations are terminated due to timeout. |
@ -54,6 +55,7 @@
| [BrowserOptions](./puppeteer.browseroptions.md) | Generic browser options that can be passed when launching any browser. |
| [ChromeArgOptions](./puppeteer.chromeargoptions.md) | Launcher options that only apply to Chrome. |
| [ClickOptions](./puppeteer.clickoptions.md) | |
| [ConnectOptions](./puppeteer.connectoptions.md) | |
| [ConsoleMessageLocation](./puppeteer.consolemessagelocation.md) | |
| [ContinueRequestOverrides](./puppeteer.continuerequestoverrides.md) | |
| [CoverageEntry](./puppeteer.coverageentry.md) | The CoverageEntry class represents one entry of the coverage report. |

View File

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [Puppeteer](./puppeteer.puppeteer.md) &gt; [\_changedProduct](./puppeteer.puppeteer._changedproduct.md)
## Puppeteer.\_changedProduct property
<b>Signature:</b>
```typescript
protected _changedProduct: boolean;
```

View File

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [Puppeteer](./puppeteer.puppeteer.md) &gt; [\_isPuppeteerCore](./puppeteer.puppeteer._ispuppeteercore.md)
## Puppeteer.\_isPuppeteerCore property
<b>Signature:</b>
```typescript
protected _isPuppeteerCore: boolean;
```

View File

@ -9,19 +9,14 @@ This method attaches Puppeteer to an existing browser instance.
<b>Signature:</b>
```typescript
connect(options: BrowserOptions & {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
product?: Product;
}): Promise<Browser>;
connect(options: ConnectOptions): Promise<Browser>;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| options | [BrowserOptions](./puppeteer.browseroptions.md) &amp; { browserWSEndpoint?: string; browserURL?: string; transport?: ConnectionTransport; product?: [Product](./puppeteer.product.md)<!-- -->; } | Set of configurable options to set on the browser. |
| options | [ConnectOptions](./puppeteer.connectoptions.md) | Set of configurable options to set on the browser. |
<b>Returns:</b>

View File

@ -4,9 +4,9 @@
## Puppeteer class
The main Puppeteer class. Provides the [launch](./puppeteer.puppeteer.launch.md) method to launch a browser.
The main Puppeteer class.
When you `require` or `import` the Puppeteer npm package you get back an instance of this class.
IMPORTANT: if you are using Puppeteer in a Node environment, you will get an instance of [PuppeteerNode](./puppeteer.puppeteernode.md) when you import or require `puppeteer`<!-- -->. That class extends `Puppeteer`<!-- -->, so has all the methods documented below as well as all that are defined on [PuppeteerNode](./puppeteer.puppeteernode.md)<!-- -->.
<b>Signature:</b>
@ -18,31 +18,14 @@ export declare class Puppeteer
The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `Puppeteer` class.
## Example
The following is a typical example of using Puppeteer to drive automation:
```js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.google.com');
// other actions...
await browser.close();
})();
```
Once you have created a `page` you have access to a large API to interact with the page, navigate, or find certain elements in that page. The [\`page\` documentation](./puppeteer.page.md) lists all the available methods.
## Properties
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [\_changedProduct](./puppeteer.puppeteer._changedproduct.md) | | boolean | |
| [\_isPuppeteerCore](./puppeteer.puppeteer._ispuppeteercore.md) | | boolean | |
| [devices](./puppeteer.puppeteer.devices.md) | | [DevicesMap](./puppeteer.devicesmap.md) | |
| [errors](./puppeteer.puppeteer.errors.md) | | [PuppeteerErrors](./puppeteer.puppeteererrors.md) | |
| [product](./puppeteer.puppeteer.product.md) | | string | The name of the browser that is under automation (<code>&quot;chrome&quot;</code> or <code>&quot;firefox&quot;</code>) |
## Methods
@ -53,8 +36,4 @@ Once you have created a `page` you have access to a large API to interact with t
| [\_\_experimental\_registerCustomQueryHandler(name, queryHandler)](./puppeteer.puppeteer.__experimental_registercustomqueryhandler.md) | | Registers a [custom query handler](./puppeteer.customqueryhandler.md)<!-- -->. After registration, the handler can be used everywhere where a selector is expected by prepending the selection string with <code>&lt;name&gt;/</code>. The name is only allowed to consist of lower- and upper case latin letters. |
| [\_\_experimental\_unregisterCustomQueryHandler(name)](./puppeteer.puppeteer.__experimental_unregistercustomqueryhandler.md) | | |
| [connect(options)](./puppeteer.puppeteer.connect.md) | | This method attaches Puppeteer to an existing browser instance. |
| [createBrowserFetcher(options)](./puppeteer.puppeteer.createbrowserfetcher.md) | | |
| [defaultArgs(options)](./puppeteer.puppeteer.defaultargs.md) | | |
| [executablePath()](./puppeteer.puppeteer.executablepath.md) | | |
| [launch(options)](./puppeteer.puppeteer.launch.md) | | Launches puppeteer and launches a browser instance with given arguments and options when specified. |

View File

@ -0,0 +1,29 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [PuppeteerNode](./puppeteer.puppeteernode.md) &gt; [connect](./puppeteer.puppeteernode.connect.md)
## PuppeteerNode.connect() method
This method attaches Puppeteer to an existing browser instance.
<b>Signature:</b>
```typescript
connect(options: ConnectOptions): Promise<Browser>;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| options | [ConnectOptions](./puppeteer.connectoptions.md) | Set of configurable options to set on the browser. |
<b>Returns:</b>
Promise&lt;[Browser](./puppeteer.browser.md)<!-- -->&gt;
Promise which resolves to browser instance.
## Remarks

View File

@ -1,8 +1,8 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [Puppeteer](./puppeteer.puppeteer.md) &gt; [createBrowserFetcher](./puppeteer.puppeteer.createbrowserfetcher.md)
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [PuppeteerNode](./puppeteer.puppeteernode.md) &gt; [createBrowserFetcher](./puppeteer.puppeteernode.createbrowserfetcher.md)
## Puppeteer.createBrowserFetcher() method
## PuppeteerNode.createBrowserFetcher() method
<b>Signature:</b>

View File

@ -1,8 +1,8 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [Puppeteer](./puppeteer.puppeteer.md) &gt; [defaultArgs](./puppeteer.puppeteer.defaultargs.md)
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [PuppeteerNode](./puppeteer.puppeteernode.md) &gt; [defaultArgs](./puppeteer.puppeteernode.defaultargs.md)
## Puppeteer.defaultArgs() method
## PuppeteerNode.defaultArgs() method
<b>Signature:</b>

View File

@ -1,8 +1,8 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [Puppeteer](./puppeteer.puppeteer.md) &gt; [executablePath](./puppeteer.puppeteer.executablepath.md)
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [PuppeteerNode](./puppeteer.puppeteernode.md) &gt; [executablePath](./puppeteer.puppeteernode.executablepath.md)
## Puppeteer.executablePath() method
## PuppeteerNode.executablePath() method
<b>Signature:</b>

View File

@ -1,8 +1,8 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [Puppeteer](./puppeteer.puppeteer.md) &gt; [launch](./puppeteer.puppeteer.launch.md)
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [PuppeteerNode](./puppeteer.puppeteernode.md) &gt; [launch](./puppeteer.puppeteernode.launch.md)
## Puppeteer.launch() method
## PuppeteerNode.launch() method
Launches puppeteer and launches a browser instance with given arguments and options when specified.
@ -10,7 +10,7 @@ Launches puppeteer and launches a browser instance with given arguments and opti
```typescript
launch(options?: LaunchOptions & ChromeArgOptions & BrowserOptions & {
product?: string;
product?: Product;
extraPrefsFirefox?: Record<string, unknown>;
}): Promise<Browser>;
```
@ -19,7 +19,7 @@ launch(options?: LaunchOptions & ChromeArgOptions & BrowserOptions & {
| Parameter | Type | Description |
| --- | --- | --- |
| options | [LaunchOptions](./puppeteer.launchoptions.md) &amp; [ChromeArgOptions](./puppeteer.chromeargoptions.md) &amp; [BrowserOptions](./puppeteer.browseroptions.md) &amp; { product?: string; extraPrefsFirefox?: Record&lt;string, unknown&gt;; } | Set of configurable options to set on the browser. |
| options | [LaunchOptions](./puppeteer.launchoptions.md) &amp; [ChromeArgOptions](./puppeteer.chromeargoptions.md) &amp; [BrowserOptions](./puppeteer.browseroptions.md) &amp; { product?: [Product](./puppeteer.product.md)<!-- -->; extraPrefsFirefox?: Record&lt;string, unknown&gt;; } | Set of configurable options to set on the browser. |
<b>Returns:</b>

View File

@ -0,0 +1,59 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [PuppeteerNode](./puppeteer.puppeteernode.md)
## PuppeteerNode class
Extends the main [Puppeteer](./puppeteer.puppeteer.md) class with Node specific behaviour for fetching and downloading browsers.
If you're using Puppeteer in a Node environment, this is the class you'll get when you run `require('puppeteer')` (or the equivalent ES `import`<!-- -->).
<b>Signature:</b>
```typescript
export declare class PuppeteerNode extends Puppeteer
```
<b>Extends:</b> [Puppeteer](./puppeteer.puppeteer.md)
## Remarks
The most common method to use is [launch](./puppeteer.puppeteernode.launch.md)<!-- -->, which is used to launch and connect to a new browser instance.
See [the main Puppeteer class](./puppeteer.puppeteer.md) for methods common to all environments, such as [Puppeteer.connect()](./puppeteer.puppeteer.connect.md)<!-- -->.
The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `PuppeteerNode` class.
## Example
The following is a typical example of using Puppeteer to drive automation:
```js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.google.com');
// other actions...
await browser.close();
})();
```
Once you have created a `page` you have access to a large API to interact with the page, navigate, or find certain elements in that page. The [\`page\` documentation](./puppeteer.page.md) lists all the available methods.
## Properties
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [product](./puppeteer.puppeteernode.product.md) | | string | The name of the browser that is under automation (<code>&quot;chrome&quot;</code> or <code>&quot;firefox&quot;</code>) |
## Methods
| Method | Modifiers | Description |
| --- | --- | --- |
| [connect(options)](./puppeteer.puppeteernode.connect.md) | | This method attaches Puppeteer to an existing browser instance. |
| [createBrowserFetcher(options)](./puppeteer.puppeteernode.createbrowserfetcher.md) | | |
| [defaultArgs(options)](./puppeteer.puppeteernode.defaultargs.md) | | |
| [executablePath()](./puppeteer.puppeteernode.executablepath.md) | | |
| [launch(options)](./puppeteer.puppeteernode.launch.md) | | Launches puppeteer and launches a browser instance with given arguments and options when specified. |

View File

@ -1,8 +1,8 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [Puppeteer](./puppeteer.puppeteer.md) &gt; [product](./puppeteer.puppeteer.product.md)
[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [PuppeteerNode](./puppeteer.puppeteernode.md) &gt; [product](./puppeteer.puppeteernode.product.md)
## Puppeteer.product property
## PuppeteerNode.product property
The name of the browser that is under automation (`"chrome"` or `"firefox"`<!-- -->)

View File

@ -15,5 +15,5 @@ export declare class TimeoutError extends CustomError
## Remarks
Example operations are [page.waitForSelector](./puppeteer.page.waitforselector.md) or [puppeteer.launch](./puppeteer.puppeteer.launch.md)<!-- -->.
Example operations are [page.waitForSelector](./puppeteer.page.waitforselector.md) or [puppeteer.launch](./puppeteer.puppeteernode.launch.md)<!-- -->.

View File

@ -19,8 +19,9 @@
* for. It is used by API Extractor to determine what parts of the system to
* document.
*
* We also have src/api.ts. This is used in `index.js` and by the legacy DocLint
* system. src/api-docs-entry.ts is ONLY used by API Extractor.
* The legacy DocLint system and the unit test coverage system use the list of
* modules defined in coverage-utils.js. src/api-docs-entry.ts is ONLY used by
* API Extractor.
*
* Once we have migrated to API Extractor and removed DocLint we can remove the
* duplication and use this file.
@ -28,6 +29,7 @@
export * from './common/Accessibility.js';
export * from './common/Browser.js';
export * from './node/BrowserFetcher.js';
export * from './node/Puppeteer.js';
export * from './common/Connection.js';
export * from './common/ConsoleMessage.js';
export * from './common/Coverage.js';

View File

@ -87,7 +87,7 @@ export const enum BrowserEmittedEvents {
/**
* A Browser is created when Puppeteer connects to a Chromium instance, either through
* {@link Puppeteer.launch} or {@link Puppeteer.connect}.
* {@link PuppeteerNode.launch} or {@link Puppeteer.connect}.
*
* @remarks
*

View File

@ -28,7 +28,7 @@ class CustomError extends Error {
* @remarks
*
* Example operations are {@link Page.waitForSelector | page.waitForSelector}
* or {@link Puppeteer.launch | puppeteer.launch}.
* or {@link PuppeteerNode.launch | puppeteer.launch}.
*
* @public
*/

View File

@ -13,13 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Launcher from '../node/Launcher.js';
import { LaunchOptions, ChromeArgOptions } from '../node/LaunchOptions.js';
import { ProductLauncher } from '../node/Launcher.js';
import {
BrowserFetcher,
BrowserFetcherOptions,
} from '../node/BrowserFetcher.js';
import { puppeteerErrors, PuppeteerErrors } from './Errors.js';
import { ConnectionTransport } from './ConnectionTransport.js';
import { devicesMap, DevicesMap } from './DeviceDescriptors.js';
@ -31,102 +24,42 @@ import {
clearCustomQueryHandlers,
CustomQueryHandler,
} from './QueryHandler.js';
import { PUPPETEER_REVISIONS } from '../revisions.js';
import { Product } from './Product.js';
import { connectToBrowser, BrowserOptions } from './BrowserConnector.js';
/**
* The main Puppeteer class. Provides the {@link Puppeteer.launch | launch}
* method to launch a browser.
*
* When you `require` or `import` the Puppeteer npm package you get back an
* instance of this class.
*
* @remarks
*
* @example
* The following is a typical example of using Puppeteer to drive automation:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com');
* // other actions...
* await browser.close();
* })();
* ```
*
* Once you have created a `page` you have access to a large API to interact
* with the page, navigate, or find certain elements in that page.
* The {@link Page | `page` documentation} lists all the available methods.
* Settings that are common to the Puppeteer class, regardless of enviroment.
* @internal
*/
export interface CommonPuppeteerSettings {
isPuppeteerCore: boolean;
}
export interface ConnectOptions extends BrowserOptions {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
product?: Product;
}
/**
* The main Puppeteer class.
*
* IMPORTANT: if you are using Puppeteer in a Node environment, you will get an
* instance of {@link PuppeteerNode} when you import or require `puppeteer`.
* That class extends `Puppeteer`, so has all the methods documented below as
* well as all that are defined on {@link PuppeteerNode}.
* @public
*/
export class Puppeteer {
// Will be undefined in a browser environment
private _projectRoot?: string;
private _isPuppeteerCore: boolean;
private _changedProduct = false;
private __productName: string;
private _lazyLauncher: ProductLauncher;
/**
* @internal
*/
_preferredRevision: string;
protected _isPuppeteerCore: boolean;
protected _changedProduct = false;
/**
* @internal
*/
constructor(
projectRoot: string,
preferredRevision: string,
isPuppeteerCore: boolean,
productName: string
) {
this._projectRoot = projectRoot;
this._preferredRevision = preferredRevision;
this._isPuppeteerCore = isPuppeteerCore;
// track changes to Launcher configuration via options or environment variables
this.__productName = productName;
}
/**
* Launches puppeteer and launches a browser instance with given arguments
* and options when specified.
*
* @remarks
*
* @example
* You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:
* ```js
* const browser = await puppeteer.launch({
* ignoreDefaultArgs: ['--mute-audio']
* });
* ```
*
* **NOTE** Puppeteer can also be used to control the Chrome browser,
* but it works best with the version of Chromium it is bundled with.
* There is no guarantee it will work with any other version.
* Use `executablePath` option with extreme caution.
* If Google Chrome (rather than Chromium) is preferred, a {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary} or {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} build is suggested.
* In `puppeteer.launch([options])`, any mention of Chromium also applies to Chrome.
* See {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} for a description of the differences between Chromium and Chrome. {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article} describes some differences for Linux users.
*
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
launch(
options: LaunchOptions &
ChromeArgOptions &
BrowserOptions & {
product?: string;
extraPrefsFirefox?: Record<string, unknown>;
} = {}
): Promise<Browser> {
if (options.product) this._productName = options.product;
return this._launcher.launch(options);
constructor(settings: CommonPuppeteerSettings) {
this._isPuppeteerCore = settings.isPuppeteerCore;
}
/**
@ -137,85 +70,10 @@ export class Puppeteer {
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
connect(
options: BrowserOptions & {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
product?: Product;
}
): Promise<Browser> {
if (options.product) this._productName = options.product;
connect(options: ConnectOptions): Promise<Browser> {
return connectToBrowser(options);
}
/**
* @internal
*/
get _productName(): string {
return this.__productName;
}
// don't need any TSDoc here - because the getter is internal the setter is too.
set _productName(name: string) {
if (this.__productName !== name) this._changedProduct = true;
this.__productName = name;
}
/**
* @remarks
*
* **NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH`
* and `PUPPETEER_CHROMIUM_REVISION` environment variables.
*
* @returns A path where Puppeteer expects to find the bundled browser.
* The browser binary might not be there if the download was skipped with
* the `PUPPETEER_SKIP_DOWNLOAD` environment variable.
*/
executablePath(): string {
return this._launcher.executablePath();
}
/**
* @internal
*/
get _launcher(): ProductLauncher {
if (
!this._lazyLauncher ||
this._lazyLauncher.product !== this._productName ||
this._changedProduct
) {
switch (this._productName) {
case 'firefox':
this._preferredRevision = PUPPETEER_REVISIONS.firefox;
break;
case 'chrome':
default:
this._preferredRevision = PUPPETEER_REVISIONS.chromium;
}
this._changedProduct = false;
this._lazyLauncher = Launcher(
this._projectRoot,
this._preferredRevision,
this._isPuppeteerCore,
this._productName
);
}
return this._lazyLauncher;
}
/**
* The name of the browser that is under automation (`"chrome"` or `"firefox"`)
*
* @remarks
* The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product`
* option in `puppeteer.launch([options])` and defaults to `chrome`.
* Firefox support is experimental.
*/
get product(): string {
return this._launcher.product;
}
/**
* @remarks
* A list of devices to be used with `page.emulate(options)`. Actual list of devices can be found in {@link https://github.com/puppeteer/puppeteer/blob/main/src/common/DeviceDescriptors.ts | src/common/DeviceDescriptors.ts}.
@ -267,24 +125,6 @@ export class Puppeteer {
return puppeteerErrors;
}
/**
*
* @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[] {
return this._launcher.defaultArgs(options);
}
/**
* @param options - Set of configurable options to specify the settings
* of the BrowserFetcher.
* @returns A new BrowserFetcher instance.
*/
createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher {
return new BrowserFetcher(this._projectRoot, options);
}
/**
* Registers a {@link CustomQueryHandler | custom query handler}. After
* registration, the handler can be used everywhere where a selector is

View File

@ -14,28 +14,30 @@
* limitations under the License.
*/
import { Puppeteer } from './common/Puppeteer.js';
import { PuppeteerNode } from './node/Puppeteer.js';
import { PUPPETEER_REVISIONS } from './revisions.js';
import pkgDir from 'pkg-dir';
import { Product } from './common/Product.js';
export const initializePuppeteerNode = (packageName: string): Puppeteer => {
export const initializePuppeteerNode = (packageName: string): PuppeteerNode => {
const puppeteerRootDirectory = pkgDir.sync(__dirname);
let preferredRevision = PUPPETEER_REVISIONS.chromium;
const isPuppeteerCore = packageName === 'puppeteer-core';
// puppeteer-core ignores environment variables
const product = isPuppeteerCore
const productName = isPuppeteerCore
? undefined
: process.env.PUPPETEER_PRODUCT ||
process.env.npm_config_puppeteer_product ||
process.env.npm_package_config_puppeteer_product;
if (!isPuppeteerCore && product === 'firefox')
if (!isPuppeteerCore && productName === 'firefox')
preferredRevision = PUPPETEER_REVISIONS.firefox;
return new Puppeteer(
puppeteerRootDirectory,
return new PuppeteerNode({
projectRoot: puppeteerRootDirectory,
preferredRevision,
isPuppeteerCore,
product
);
productName: productName as Product,
});
};

View File

@ -18,17 +18,7 @@ import { Puppeteer } from './common/Puppeteer.js';
export const initializePuppeteerWeb = (packageName: string): Puppeteer => {
const isPuppeteerCore = packageName === 'puppeteer-core';
// puppeteer-core ignores environment variables
return new Puppeteer(
// Product root directory is undefined as we're not concerned about
// downloading and installing browsers in the web environment.
undefined,
// Preferred revision is undefined as we use the browser we are running in.
undefined,
return new Puppeteer({
isPuppeteerCore,
// Preferred product is undefined as we use the browser we are
// running in.
undefined
);
});
};

View File

@ -16,10 +16,10 @@
import { initializePuppeteerNode } from './initialize-node.js';
import { isNode } from './environment.js';
import { initializePuppeteerWeb } from './initialize-web.js';
const initializeFunc = isNode
? initializePuppeteerNode
: initializePuppeteerWeb;
const puppeteer = initializeFunc('puppeteer');
if (!isNode) {
throw new Error('Cannot run puppeteer-core outside of Node.js');
}
const puppeteer = initializePuppeteerNode('puppeteer-core');
export default puppeteer;

View File

@ -16,10 +16,8 @@
import { initializePuppeteerNode } from './initialize-node.js';
import { isNode } from './environment.js';
import { initializePuppeteerWeb } from './initialize-web.js';
const initializeFunc = isNode
? initializePuppeteerNode
: initializePuppeteerWeb;
const puppeteer = initializeFunc('puppeteer-core');
export default puppeteer;
if (!isNode) {
throw new Error('Trying to run Puppeteer-Node in a web environment.');
}
export default initializePuppeteerNode('puppeteer');

230
src/node/Puppeteer.ts Normal file
View File

@ -0,0 +1,230 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
Puppeteer,
CommonPuppeteerSettings,
ConnectOptions,
} from '../common/Puppeteer.js';
import { BrowserFetcher, BrowserFetcherOptions } from './BrowserFetcher.js';
import { LaunchOptions, ChromeArgOptions } from './LaunchOptions.js';
import { BrowserOptions } from '../common/BrowserConnector.js';
import { Browser } from '../common/Browser.js';
import Launcher, { ProductLauncher } from './Launcher.js';
import { PUPPETEER_REVISIONS } from '../revisions.js';
import { Product } from '../common/Product.js';
/**
* Extends the main {@link Puppeteer} class with Node specific behaviour for fetching and
* downloading browsers.
*
* If you're using Puppeteer in a Node environment, this is the class you'll get
* when you run `require('puppeteer')` (or the equivalent ES `import`).
*
* @remarks
*
* The most common method to use is {@link PuppeteerNode.launch | launch}, which
* is used to launch and connect to a new browser instance.
*
* See {@link Puppeteer | the main Puppeteer class} for methods common to all
* environments, such as {@link Puppeteer.connect}.
*
* @example
* The following is a typical example of using Puppeteer to drive automation:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com');
* // other actions...
* await browser.close();
* })();
* ```
*
* Once you have created a `page` you have access to a large API to interact
* with the page, navigate, or find certain elements in that page.
* The {@link Page | `page` documentation} lists all the available methods.
*
* @public
*/
export class PuppeteerNode extends Puppeteer {
private _lazyLauncher: ProductLauncher;
private _projectRoot: string;
private __productName?: Product;
/**
* @internal
*/
_preferredRevision: string;
/**
* @internal
*/
constructor(
settings: {
projectRoot: string;
preferredRevision: string;
productName?: Product;
} & CommonPuppeteerSettings
) {
const {
projectRoot,
preferredRevision,
productName,
...commonSettings
} = settings;
super(commonSettings);
this._projectRoot = projectRoot;
this.__productName = productName;
this._preferredRevision = preferredRevision;
}
/**
* This method attaches Puppeteer to an existing browser instance.
*
* @remarks
*
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
connect(options: ConnectOptions): Promise<Browser> {
if (options.product) this._productName = options.product;
return super.connect(options);
}
/**
* @internal
*/
get _productName(): Product {
return this.__productName;
}
// don't need any TSDoc here - because the getter is internal the setter is too.
set _productName(name: Product) {
if (this.__productName !== name) this._changedProduct = true;
this.__productName = name;
}
/**
* Launches puppeteer and launches a browser instance with given arguments
* and options when specified.
*
* @remarks
*
* @example
* You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:
* ```js
* const browser = await puppeteer.launch({
* ignoreDefaultArgs: ['--mute-audio']
* });
* ```
*
* **NOTE** Puppeteer can also be used to control the Chrome browser,
* but it works best with the version of Chromium it is bundled with.
* There is no guarantee it will work with any other version.
* Use `executablePath` option with extreme caution.
* If Google Chrome (rather than Chromium) is preferred, a {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary} or {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} build is suggested.
* In `puppeteer.launch([options])`, any mention of Chromium also applies to Chrome.
* See {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} for a description of the differences between Chromium and Chrome. {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article} describes some differences for Linux users.
*
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
launch(
options: LaunchOptions &
ChromeArgOptions &
BrowserOptions & {
product?: Product;
extraPrefsFirefox?: Record<string, unknown>;
} = {}
): Promise<Browser> {
if (options.product) this._productName = options.product;
return this._launcher.launch(options);
}
/**
* @remarks
*
* **NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH`
* and `PUPPETEER_CHROMIUM_REVISION` environment variables.
*
* @returns A path where Puppeteer expects to find the bundled browser.
* The browser binary might not be there if the download was skipped with
* the `PUPPETEER_SKIP_DOWNLOAD` environment variable.
*/
executablePath(): string {
return this._launcher.executablePath();
}
/**
* @internal
*/
get _launcher(): ProductLauncher {
if (
!this._lazyLauncher ||
this._lazyLauncher.product !== this._productName ||
this._changedProduct
) {
switch (this._productName) {
case 'firefox':
this._preferredRevision = PUPPETEER_REVISIONS.firefox;
break;
case 'chrome':
default:
this._preferredRevision = PUPPETEER_REVISIONS.chromium;
}
this._changedProduct = false;
this._lazyLauncher = Launcher(
this._projectRoot,
this._preferredRevision,
this._isPuppeteerCore,
this._productName
);
}
return this._lazyLauncher;
}
/**
* The name of the browser that is under automation (`"chrome"` or `"firefox"`)
*
* @remarks
* The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product`
* option in `puppeteer.launch([options])` and defaults to `chrome`.
* Firefox support is experimental.
*/
get product(): string {
return this._launcher.product;
}
/**
*
* @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[] {
return this._launcher.defaultArgs(options);
}
/**
* @param options - Set of configurable options to specify the settings
* of the BrowserFetcher.
* @returns A new BrowserFetcher instance.
*/
createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher {
return new BrowserFetcher(this._projectRoot, options);
}
}

View File

@ -17,8 +17,9 @@
import os from 'os';
import https from 'https';
import ProgressBar from 'progress';
import puppeteer from '../index.js';
import puppeteer from '../node.js';
import { PUPPETEER_REVISIONS } from '../revisions.js';
import { PuppeteerNode } from './Puppeteer.js';
const supportedProducts = {
chrome: 'Chromium',
@ -39,7 +40,7 @@ export async function downloadBrowser() {
process.env.PUPPETEER_DOWNLOAD_PATH ||
process.env.npm_config_puppeteer_download_path ||
process.env.npm_package_config_puppeteer_download_path;
const browserFetcher = puppeteer.createBrowserFetcher({
const browserFetcher = (puppeteer as PuppeteerNode).createBrowserFetcher({
product,
host: downloadHost,
path: downloadPath,
@ -55,7 +56,8 @@ export async function downloadBrowser() {
PUPPETEER_REVISIONS.chromium
);
} else if (product === 'firefox') {
puppeteer._preferredRevision = PUPPETEER_REVISIONS.firefox;
(puppeteer as PuppeteerNode)._preferredRevision =
PUPPETEER_REVISIONS.firefox;
return getFirefoxNightlyVersion().catch((error) => {
console.error(error);
process.exit(1);

24
src/web.ts Normal file
View File

@ -0,0 +1,24 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { initializePuppeteerWeb } from './initialize-web.js';
import { isNode } from './environment.js';
if (isNode) {
throw new Error('Trying to run Puppeteer-Web in a Node environment');
}
export default initializePuppeteerWeb('puppeteer');

View File

@ -57,6 +57,7 @@ const MODULES_TO_CHECK_FOR_COVERAGE = {
Mouse: '../lib/cjs/puppeteer/common/Input',
Page: '../lib/cjs/puppeteer/common/Page',
Puppeteer: '../lib/cjs/puppeteer/common/Puppeteer',
PuppeteerNode: '../lib/cjs/puppeteer/node/Puppeteer',
HTTPRequest: '../lib/cjs/puppeteer/common/HTTPRequest',
HTTPResponse: '../lib/cjs/puppeteer/common/HTTPResponse',
SecurityDetails: '../lib/cjs/puppeteer/common/SecurityDetails',

View File

@ -459,6 +459,7 @@ describe('Launcher specs', function () {
it('falls back to launching chrome if there is an unknown product but logs a warning', async () => {
const { puppeteer } = getTestState();
const consoleStub = sinon.stub(console, 'warn');
// @ts-expect-error purposeful bad input
const browser = await puppeteer.launch({ product: 'SO_NOT_A_PRODUCT' });
const userAgent = await browser.userAgent();
await browser.close();

View File

@ -19,13 +19,13 @@ import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import sinon from 'sinon';
import puppeteer from '../lib/cjs/puppeteer/index.js';
import puppeteer from '../lib/cjs/puppeteer/node.js';
import {
Browser,
BrowserContext,
} from '../lib/cjs/puppeteer/common/Browser.js';
import { Page } from '../lib/cjs/puppeteer/common/Page.js';
import { Puppeteer } from '../lib/cjs/puppeteer/common/Puppeteer.js';
import { PuppeteerNode } from '../lib/cjs/puppeteer/node/Puppeteer.js';
import utils from './utils.js';
import rimraf from 'rimraf';
@ -126,7 +126,7 @@ interface PuppeteerTestState {
browser: Browser;
context: BrowserContext;
page: Page;
puppeteer: Puppeteer;
puppeteer: PuppeteerNode;
defaultBrowserOptions: {
[x: string]: any;
};

View File

@ -206,10 +206,25 @@ function compareDocumentations(actual, expected) {
const expectedClasses = Array.from(expected.classes.keys()).sort();
const classesDiff = diff(actualClasses, expectedClasses);
/* These have been moved onto PuppeteerNode but we want to document them under
* Puppeteer. See https://github.com/puppeteer/puppeteer/pull/6504 for details.
*/
const expectedPuppeteerClassMissingMethods = new Set([
'createBrowserFetcher',
'defaultArgs',
'executablePath',
'launch',
]);
for (const className of classesDiff.extra)
errors.push(`Non-existing class found: ${className}`);
for (const className of classesDiff.missing)
for (const className of classesDiff.missing) {
if (className === 'PuppeteerNode') {
continue;
}
errors.push(`Class not found: ${className}`);
}
for (const className of classesDiff.equal) {
const actualClass = actual.classes.get(className);
@ -219,6 +234,12 @@ function compareDocumentations(actual, expected) {
const methodDiff = diff(actualMethods, expectedMethods);
for (const methodName of methodDiff.extra) {
if (
expectedPuppeteerClassMissingMethods.has(methodName) &&
actualClass.name === 'Puppeteer'
) {
continue;
}
errors.push(`Non-existing method found: ${className}.${methodName}()`);
}
@ -282,8 +303,12 @@ function compareDocumentations(actual, expected) {
expectedClass.properties.keys()
).sort();
const propertyDiff = diff(actualProperties, expectedProperties);
for (const propertyName of propertyDiff.extra)
for (const propertyName of propertyDiff.extra) {
if (className === 'Puppeteer' && propertyName === 'product') {
continue;
}
errors.push(`Non-existing property found: ${className}.${propertyName}`);
}
for (const propertyName of propertyDiff.missing)
errors.push(`Property not found: ${className}.${propertyName}`);
@ -804,10 +829,10 @@ function compareDocumentations(actual, expected) {
},
],
[
'Method Puppeteer.connect() options.product',
'Method Puppeteer.connect() options',
{
actualName: 'string',
expectedName: 'Product',
actualName: 'Object',
expectedName: 'ConnectOptions',
},
],
]);
@ -854,6 +879,7 @@ function compareDocumentations(actual, expected) {
const skipPropertyChecksOnMethods = new Set([
'Method Page.deleteCookie() ...cookies',
'Method Page.setCookie() ...cookies',
'Method Puppeteer.connect() options',
]);
if (skipPropertyChecksOnMethods.has(source)) return;