feat!: deprecate createBrowserFetcher in favor of BrowserFetcher (#9079)

This PR deprecates the `createBrowserFetcher` API and requests users to
import the `BrowserFetcher` directly.

Fixed: #8999
This commit is contained in:
jrandolf 2022-10-10 17:51:18 +02:00 committed by GitHub
parent 1847704789
commit 7294dfe9c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 207 additions and 168 deletions

View File

@ -0,0 +1,21 @@
---
sidebar_label: BrowserFetcher.(constructor)
---
# BrowserFetcher.(constructor)
Constructs a browser fetcher for the given options.
**Signature:**
```typescript
class BrowserFetcher {
constructor(options?: BrowserFetcherOptions);
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------------------------------------------------------------- | ----------------- |
| options | [BrowserFetcherOptions](./puppeteer.browserfetcheroptions.md) | <i>(Optional)</i> |

View File

@ -14,23 +14,25 @@ export declare class BrowserFetcher
## Remarks ## Remarks
BrowserFetcher operates on revision strings that specify a precise version of Chromium, e.g. `"533271"`. Revision strings can be obtained from [omahaproxy.appspot.com](http://omahaproxy.appspot.com/). In the Firefox case, BrowserFetcher downloads Firefox Nightly and operates on version numbers such as `"75"`. BrowserFetcher is not designed to work concurrently with other instances of BrowserFetcher that share the same downloads directory.
The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `BrowserFetcher` class.
## Example ## Example
An example of using BrowserFetcher to download a specific version of Chromium and running Puppeteer against it: An example of using BrowserFetcher to download a specific version of Chromium and running Puppeteer against it:
```ts ```ts
const browserFetcher = puppeteer.createBrowserFetcher(); const browserFetcher = new BrowserFetcher();
const revisionInfo = await browserFetcher.download('533271'); const revisionInfo = await browserFetcher.download('533271');
const browser = await puppeteer.launch({ const browser = await puppeteer.launch({
executablePath: revisionInfo.executablePath, executablePath: revisionInfo.executablePath,
}); });
``` ```
**NOTE** BrowserFetcher is not designed to work concurrently with other instances of BrowserFetcher that share the same downloads directory. ## Constructors
| Constructor | Modifiers | Description |
| --------------------------------------------------------------------- | --------- | --------------------------------------------------- |
| [(constructor)(options)](./puppeteer.browserfetcher._constructor_.md) | | Constructs a browser fetcher for the given options. |
## Methods ## Methods

View File

@ -4,6 +4,8 @@ sidebar_label: BrowserFetcherOptions.host
# BrowserFetcherOptions.host property # BrowserFetcherOptions.host property
Determines the host that will be used for downloading.
**Signature:** **Signature:**
```typescript ```typescript

View File

@ -12,9 +12,9 @@ export interface BrowserFetcherOptions
## Properties ## Properties
| Property | Modifiers | Type | Description | | Property | Modifiers | Type | Description |
| ---------------------------------------------------------- | --------- | ----------------------------------- | ----------------- | | ---------------------------------------------------------- | --------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------ |
| [host?](./puppeteer.browserfetcheroptions.host.md) | | string | <i>(Optional)</i> | | [host?](./puppeteer.browserfetcheroptions.host.md) | | string | <i>(Optional)</i> Determines the host that will be used for downloading. |
| [path?](./puppeteer.browserfetcheroptions.path.md) | | string | <i>(Optional)</i> | | [path?](./puppeteer.browserfetcheroptions.path.md) | | string | <i>(Optional)</i> Determines the path to download browsers to. |
| [platform?](./puppeteer.browserfetcheroptions.platform.md) | | [Platform](./puppeteer.platform.md) | <i>(Optional)</i> | | [platform?](./puppeteer.browserfetcheroptions.platform.md) | | [Platform](./puppeteer.platform.md) | <i>(Optional)</i> Determines which platform the browser will be suited for. |
| [product?](./puppeteer.browserfetcheroptions.product.md) | | string | <i>(Optional)</i> | | [product?](./puppeteer.browserfetcheroptions.product.md) | | 'chrome' \| 'firefox' | <i>(Optional)</i> Determines which product the [BrowserFetcher](./puppeteer.browserfetcher.md) is for. |

View File

@ -4,6 +4,8 @@ sidebar_label: BrowserFetcherOptions.path
# BrowserFetcherOptions.path property # BrowserFetcherOptions.path property
Determines the path to download browsers to.
**Signature:** **Signature:**
```typescript ```typescript

View File

@ -4,6 +4,8 @@ sidebar_label: BrowserFetcherOptions.platform
# BrowserFetcherOptions.platform property # BrowserFetcherOptions.platform property
Determines which platform the browser will be suited for.
**Signature:** **Signature:**
```typescript ```typescript

View File

@ -4,10 +4,12 @@ sidebar_label: BrowserFetcherOptions.product
# BrowserFetcherOptions.product property # BrowserFetcherOptions.product property
Determines which product the [BrowserFetcher](./puppeteer.browserfetcher.md) is for.
**Signature:** **Signature:**
```typescript ```typescript
interface BrowserFetcherOptions { interface BrowserFetcherOptions {
product?: string; product?: 'chrome' | 'firefox';
} }
``` ```

View File

@ -4,6 +4,10 @@ sidebar_label: createBrowserFetcher
# createBrowserFetcher variable # createBrowserFetcher variable
> Warning: This API is now obsolete.
>
> Import [BrowserFetcher](./puppeteer.browserfetcher.md) directly and use the constructor.
**Signature:** **Signature:**
```typescript ```typescript

View File

@ -4,6 +4,10 @@ sidebar_label: PuppeteerNode.createBrowserFetcher
# PuppeteerNode.createBrowserFetcher() method # PuppeteerNode.createBrowserFetcher() method
> Warning: This API is now obsolete.
>
> Import [BrowserFetcher](./puppeteer.browserfetcher.md) directly and use the constructor.
**Signature:** **Signature:**
```typescript ```typescript

View File

@ -14,9 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
import * as childProcess from 'child_process'; import {exec as execChildProcess} from 'child_process';
import extractZip from 'extract-zip'; import extractZip from 'extract-zip';
import * as fs from 'fs'; import {createReadStream, createWriteStream, existsSync} from 'fs';
import {chmod, mkdir, readdir, unlink} from 'fs/promises';
import * as http from 'http'; import * as http from 'http';
import * as https from 'https'; import * as https from 'https';
import createHttpsProxyAgent, { import createHttpsProxyAgent, {
@ -69,6 +70,8 @@ const browserConfig = {
}, },
} as const; } as const;
const exec = promisify(execChildProcess);
/** /**
* Supported platforms. * Supported platforms.
* *
@ -117,11 +120,11 @@ function downloadURL(
} }
function handleArm64(): void { function handleArm64(): void {
let exists = fs.existsSync('/usr/bin/chromium-browser'); let exists = existsSync('/usr/bin/chromium-browser');
if (exists) { if (exists) {
return; return;
} }
exists = fs.existsSync('/usr/bin/chromium'); exists = existsSync('/usr/bin/chromium');
if (exists) { if (exists) {
return; return;
} }
@ -134,27 +137,32 @@ function handleArm64(): void {
throw new Error(); throw new Error();
} }
const readdirAsync = promisify(fs.readdir.bind(fs));
const mkdirAsync = promisify(fs.mkdir.bind(fs));
const unlinkAsync = promisify(fs.unlink.bind(fs));
const chmodAsync = promisify(fs.chmod.bind(fs));
function existsAsync(filePath: string): Promise<boolean> {
return new Promise(resolve => {
fs.access(filePath, err => {
return resolve(!err);
});
});
}
/** /**
* @public * @public
*/ */
export interface BrowserFetcherOptions { export interface BrowserFetcherOptions {
/**
* Determines which platform the browser will be suited for.
*/
platform?: Platform; platform?: Platform;
product?: string; /**
* Determines which product the {@link BrowserFetcher} is for.
*
* @defaultValue `"chrome"`
*/
product?: 'chrome' | 'firefox';
/**
* Determines the path to download browsers to.
*/
path?: string; path?: string;
/**
* Determines the host that will be used for downloading.
*/
host?: string; host?: string;
/**
* @internal
*/
projectRoot?: string;
} }
/** /**
@ -168,29 +176,38 @@ export interface BrowserFetcherRevisionInfo {
revision: string; revision: string;
product: string; product: string;
} }
/** /**
* BrowserFetcher can download and manage different versions of Chromium and Firefox. * BrowserFetcher can download and manage different versions of Chromium and
* Firefox.
* *
* @remarks * @remarks
* BrowserFetcher operates on revision strings that specify a precise version of Chromium, e.g. `"533271"`. Revision strings can be obtained from {@link http://omahaproxy.appspot.com/ | omahaproxy.appspot.com}. * BrowserFetcher operates on revision strings that specify a precise version of
* In the Firefox case, BrowserFetcher downloads Firefox Nightly and * Chromium, e.g. `"533271"`. Revision strings can be obtained from
* operates on version numbers such as `"75"`. * {@link http://omahaproxy.appspot.com/ | omahaproxy.appspot.com}. For Firefox,
* BrowserFetcher downloads Firefox Nightly and operates on version numbers such
* as `"75"`.
*
* @remarks
* The default constructed fetcher will always be for Chromium unless otherwise
* specified.
*
* @remarks
* BrowserFetcher is not designed to work concurrently with other instances of
* BrowserFetcher that share the same downloads directory.
* *
* @example * @example
* An example of using BrowserFetcher to download a specific version of Chromium * An example of using BrowserFetcher to download a specific version of Chromium
* and running Puppeteer against it: * and running Puppeteer against it:
* *
* ```ts * ```ts
* const browserFetcher = puppeteer.createBrowserFetcher(); * const browserFetcher = new BrowserFetcher();
* const revisionInfo = await browserFetcher.download('533271'); * const revisionInfo = await browserFetcher.download('533271');
* const browser = await puppeteer.launch({ * const browser = await puppeteer.launch({
* executablePath: revisionInfo.executablePath, * executablePath: revisionInfo.executablePath,
* }); * });
* ``` * ```
* *
* **NOTE** BrowserFetcher is not designed to work concurrently with other
* instances of BrowserFetcher that share the same downloads directory.
*
* @public * @public
*/ */
@ -201,9 +218,9 @@ export class BrowserFetcher {
#platform: Platform; #platform: Platform;
/** /**
* @internal * Constructs a browser fetcher for the given options.
*/ */
constructor(projectRoot: string, options: BrowserFetcherOptions = {}) { constructor(options: BrowserFetcherOptions = {}) {
this.#product = (options.product || 'chrome').toLowerCase() as Product; this.#product = (options.product || 'chrome').toLowerCase() as Product;
assert( assert(
this.#product === 'chrome' || this.#product === 'firefox', this.#product === 'chrome' || this.#product === 'firefox',
@ -212,7 +229,7 @@ export class BrowserFetcher {
this.#downloadsFolder = this.#downloadsFolder =
options.path || options.path ||
path.join(projectRoot, browserConfig[this.#product].destination); path.join(options.projectRoot!, browserConfig[this.#product].destination);
this.#downloadHost = options.host || browserConfig[this.#product].host; this.#downloadHost = options.host || browserConfig[this.#product].host;
if (options.platform) { if (options.platform) {
@ -240,7 +257,7 @@ export class BrowserFetcher {
this.#platform = this.#platform =
os.arch() === 'x64' || os.arch() === 'x64' ||
// Windows 11 for ARM supports x64 emulation // Windows 11 for ARM supports x64 emulation
(os.arch() === 'arm64' && _isWindows11(os.release())) (os.arch() === 'arm64' && isWindows11(os.release()))
? 'win64' ? 'win64'
: 'win32'; : 'win32';
return; return;
@ -333,11 +350,11 @@ export class BrowserFetcher {
assert(fileName, `A malformed download URL was found: ${url}.`); assert(fileName, `A malformed download URL was found: ${url}.`);
const archivePath = path.join(this.#downloadsFolder, fileName); const archivePath = path.join(this.#downloadsFolder, fileName);
const outputPath = this.#getFolderPath(revision); const outputPath = this.#getFolderPath(revision);
if (await existsAsync(outputPath)) { if (existsSync(outputPath)) {
return this.revisionInfo(revision); return this.revisionInfo(revision);
} }
if (!(await existsAsync(this.#downloadsFolder))) { if (!existsSync(this.#downloadsFolder)) {
await mkdirAsync(this.#downloadsFolder); await mkdir(this.#downloadsFolder);
} }
// Use system Chromium builds on Linux ARM devices // Use system Chromium builds on Linux ARM devices
@ -349,13 +366,13 @@ export class BrowserFetcher {
await _downloadFile(url, archivePath, progressCallback); await _downloadFile(url, archivePath, progressCallback);
await install(archivePath, outputPath); await install(archivePath, outputPath);
} finally { } finally {
if (await existsAsync(archivePath)) { if (existsSync(archivePath)) {
await unlinkAsync(archivePath); await unlink(archivePath);
} }
} }
const revisionInfo = this.revisionInfo(revision); const revisionInfo = this.revisionInfo(revision);
if (revisionInfo) { if (revisionInfo) {
await chmodAsync(revisionInfo.executablePath, 0o755); await chmod(revisionInfo.executablePath, 0o755);
} }
return revisionInfo; return revisionInfo;
} }
@ -367,10 +384,10 @@ export class BrowserFetcher {
* available locally on disk. * available locally on disk.
*/ */
async localRevisions(): Promise<string[]> { async localRevisions(): Promise<string[]> {
if (!(await existsAsync(this.#downloadsFolder))) { if (!existsSync(this.#downloadsFolder)) {
return []; return [];
} }
const fileNames = await readdirAsync(this.#downloadsFolder); const fileNames = await readdir(this.#downloadsFolder);
return fileNames return fileNames
.map(fileName => { .map(fileName => {
return parseFolderPath(this.#product, fileName); return parseFolderPath(this.#product, fileName);
@ -397,7 +414,7 @@ export class BrowserFetcher {
async remove(revision: string): Promise<void> { async remove(revision: string): Promise<void> {
const folderPath = this.#getFolderPath(revision); const folderPath = this.#getFolderPath(revision);
assert( assert(
await existsAsync(folderPath), existsSync(folderPath),
`Failed to remove: revision ${revision} is not downloaded` `Failed to remove: revision ${revision} is not downloaded`
); );
await new Promise(fulfill => { await new Promise(fulfill => {
@ -412,57 +429,66 @@ export class BrowserFetcher {
revisionInfo(revision: string): BrowserFetcherRevisionInfo { revisionInfo(revision: string): BrowserFetcherRevisionInfo {
const folderPath = this.#getFolderPath(revision); const folderPath = this.#getFolderPath(revision);
let executablePath = ''; let executablePath = '';
if (this.#product === 'chrome') { switch (this.#product) {
if (this.#platform === 'mac' || this.#platform === 'mac_arm') { case 'chrome':
executablePath = path.join( switch (this.#platform) {
folderPath, case 'mac':
archiveName(this.#product, this.#platform, revision), case 'mac_arm':
'Chromium.app', executablePath = path.join(
'Contents', folderPath,
'MacOS', archiveName(this.#product, this.#platform, revision),
'Chromium' 'Chromium.app',
); 'Contents',
} else if (this.#platform === 'linux') { 'MacOS',
executablePath = path.join( 'Chromium'
folderPath, );
archiveName(this.#product, this.#platform, revision), break;
'chrome' case 'linux':
); executablePath = path.join(
} else if (this.#platform === 'win32' || this.#platform === 'win64') { folderPath,
executablePath = path.join( archiveName(this.#product, this.#platform, revision),
folderPath, 'chrome'
archiveName(this.#product, this.#platform, revision), );
'chrome.exe' break;
); case 'win32':
} else { case 'win64':
throw new Error('Unsupported platform: ' + this.#platform); executablePath = path.join(
} folderPath,
} else if (this.#product === 'firefox') { archiveName(this.#product, this.#platform, revision),
if (this.#platform === 'mac' || this.#platform === 'mac_arm') { 'chrome.exe'
executablePath = path.join( );
folderPath, break;
'Firefox Nightly.app', }
'Contents', break;
'MacOS', case 'firefox':
'firefox' switch (this.#platform) {
); case 'mac':
} else if (this.#platform === 'linux') { case 'mac_arm':
executablePath = path.join(folderPath, 'firefox', 'firefox'); executablePath = path.join(
} else if (this.#platform === 'win32' || this.#platform === 'win64') { folderPath,
executablePath = path.join(folderPath, 'firefox', 'firefox.exe'); 'Firefox Nightly.app',
} else { 'Contents',
throw new Error('Unsupported platform: ' + this.#platform); 'MacOS',
} 'firefox'
} else { );
throw new Error('Unsupported product: ' + this.#product); break;
case 'linux':
executablePath = path.join(folderPath, 'firefox', 'firefox');
break;
case 'win32':
case 'win64':
executablePath = path.join(folderPath, 'firefox', 'firefox.exe');
break;
}
} }
const url = downloadURL( const url = downloadURL(
this.#product, this.#product,
this.#platform, this.#platform,
this.#downloadHost, this.#downloadHost,
revision revision
); );
const local = fs.existsSync(folderPath); const local = existsSync(folderPath);
debugFetcher({ debugFetcher({
revision, revision,
executablePath, executablePath,
@ -506,7 +532,7 @@ function parseFolderPath(
* Windows 11 is identified by 10.0.22000 or greater * Windows 11 is identified by 10.0.22000 or greater
* @internal * @internal
*/ */
function _isWindows11(version: string): boolean { function isWindows11(version: string): boolean {
const parts = version.split('.'); const parts = version.split('.');
if (parts.length > 2) { if (parts.length > 2) {
const major = parseInt(parts[0] as string, 10); const major = parseInt(parts[0] as string, 10);
@ -550,7 +576,7 @@ function _downloadFile(
reject(error); reject(error);
return; return;
} }
const file = fs.createWriteStream(destinationPath); const file = createWriteStream(destinationPath);
file.on('finish', () => { file.on('finish', () => {
return fulfill(); return fulfill();
}); });
@ -574,16 +600,15 @@ function _downloadFile(
} }
} }
function install(archivePath: string, folderPath: string): Promise<unknown> { async function install(archivePath: string, folderPath: string): Promise<void> {
debugFetcher(`Installing ${archivePath} to ${folderPath}`); debugFetcher(`Installing ${archivePath} to ${folderPath}`);
if (archivePath.endsWith('.zip')) { if (archivePath.endsWith('.zip')) {
return extractZip(archivePath, {dir: folderPath}); await extractZip(archivePath, {dir: folderPath});
} else if (archivePath.endsWith('.tar.bz2')) { } else if (archivePath.endsWith('.tar.bz2')) {
return _extractTar(archivePath, folderPath); await extractTar(archivePath, folderPath);
} else if (archivePath.endsWith('.dmg')) { } else if (archivePath.endsWith('.dmg')) {
return mkdirAsync(folderPath).then(() => { await mkdir(folderPath);
return _installDMG(archivePath, folderPath); await installDMG(archivePath, folderPath);
});
} else { } else {
throw new Error(`Unsupported archive format: ${archivePath}`); throw new Error(`Unsupported archive format: ${archivePath}`);
} }
@ -592,12 +617,12 @@ function install(archivePath: string, folderPath: string): Promise<unknown> {
/** /**
* @internal * @internal
*/ */
function _extractTar(tarPath: string, folderPath: string): Promise<unknown> { function extractTar(tarPath: string, folderPath: string): Promise<void> {
return new Promise((fulfill, reject) => { return new Promise((fulfill, reject) => {
const tarStream = tar.extract(folderPath); const tarStream = tar.extract(folderPath);
tarStream.on('error', reject); tarStream.on('error', reject);
tarStream.on('finish', fulfill); tarStream.on('finish', fulfill);
const readStream = fs.createReadStream(tarPath); const readStream = createReadStream(tarPath);
readStream.pipe(bzip()).pipe(tarStream); readStream.pipe(bzip()).pipe(tarStream);
}); });
} }
@ -605,56 +630,33 @@ function _extractTar(tarPath: string, folderPath: string): Promise<unknown> {
/** /**
* @internal * @internal
*/ */
function _installDMG(dmgPath: string, folderPath: string): Promise<void> { async function installDMG(dmgPath: string, folderPath: string): Promise<void> {
let mountPath: string | undefined; const {stdout} = await exec(
`hdiutil attach -nobrowse -noautoopen "${dmgPath}"`
);
return new Promise<void>((fulfill, reject): void => { const volumes = stdout.match(/\/Volumes\/(.*)/m);
const mountCommand = `hdiutil attach -nobrowse -noautoopen "${dmgPath}"`; if (!volumes) {
childProcess.exec(mountCommand, (err, stdout) => { throw new Error(`Could not find volume path in ${stdout}`);
if (err) { }
return reject(err); const mountPath = volumes[0]!;
}
const volumes = stdout.match(/\/Volumes\/(.*)/m); try {
if (!volumes) { const fileNames = await readdir(mountPath);
return reject(new Error(`Could not find volume path in ${stdout}`)); const appName = fileNames.find(item => {
} return typeof item === 'string' && item.endsWith('.app');
mountPath = volumes[0]!;
readdirAsync(mountPath)
.then(fileNames => {
const appName = fileNames.find(item => {
return typeof item === 'string' && item.endsWith('.app');
});
if (!appName) {
return reject(new Error(`Cannot find app in ${mountPath}`));
}
const copyPath = path.join(mountPath!, appName);
debugFetcher(`Copying ${copyPath} to ${folderPath}`);
childProcess.exec(`cp -R "${copyPath}" "${folderPath}"`, err => {
if (err) {
reject(err);
} else {
fulfill();
}
});
})
.catch(reject);
});
})
.catch(error => {
console.error(error);
})
.finally((): void => {
if (!mountPath) {
return;
}
const unmountCommand = `hdiutil detach "${mountPath}" -quiet`;
debugFetcher(`Unmounting ${mountPath}`);
childProcess.exec(unmountCommand, err => {
if (err) {
console.error(`Error unmounting dmg: ${err}`);
}
});
}); });
if (!appName) {
throw new Error(`Cannot find app in ${mountPath}`);
}
const mountedPath = path.join(mountPath!, appName);
debugFetcher(`Copying ${mountedPath} to ${folderPath}`);
await exec(`cp -R "${mountedPath}" "${folderPath}"`);
} finally {
debugFetcher(`Unmounting ${mountPath}`);
await exec(`hdiutil detach "${mountPath}" -quiet`);
}
} }
function httpRequest( function httpRequest(
@ -675,11 +677,7 @@ function httpRequest(
let options: Options = { let options: Options = {
...urlParsed, ...urlParsed,
method, method,
headers: keepAlive headers: keepAlive ? {Connection: 'keep-alive'} : undefined,
? {
Connection: 'keep-alive',
}
: undefined,
}; };
const proxyURL = getProxyForUrl(url); const proxyURL = getProxyForUrl(url);

View File

@ -221,7 +221,8 @@ export class FirefoxLauncher implements ProductLauncher {
'_projectRoot is undefined. Unable to create a BrowserFetcher.' '_projectRoot is undefined. Unable to create a BrowserFetcher.'
); );
} }
const browserFetcher = new BrowserFetcher(this._projectRoot, { const browserFetcher = new BrowserFetcher({
projectRoot: this._projectRoot,
product: this.product, product: this.product,
}); });
const localRevisions = await browserFetcher.localRevisions(); const localRevisions = await browserFetcher.localRevisions();

View File

@ -160,7 +160,8 @@ export function resolveExecutablePath(
'_projectRoot is undefined. Unable to create a BrowserFetcher.' '_projectRoot is undefined. Unable to create a BrowserFetcher.'
); );
} }
const browserFetcher = new BrowserFetcher(_projectRoot, { const browserFetcher = new BrowserFetcher({
projectRoot: _projectRoot,
product: product, product: product,
path: downloadPath, path: downloadPath,
}); });

View File

@ -234,16 +234,13 @@ export class PuppeteerNode extends Puppeteer {
} }
/** /**
* @deprecated Import {@link BrowserFetcher} directly and use the constructor.
*
* @param options - Set of configurable options to specify the settings of the * @param options - Set of configurable options to specify the settings of the
* BrowserFetcher. * BrowserFetcher.
* @returns A new BrowserFetcher instance. * @returns A new BrowserFetcher instance.
*/ */
createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher { createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher {
if (!this.#projectRoot) { return new BrowserFetcher({...options, projectRoot: this.#projectRoot});
throw new Error(
'_projectRoot is undefined. Unable to create a BrowserFetcher.'
);
}
return new BrowserFetcher(this.#projectRoot, options);
} }
} }

View File

@ -19,6 +19,7 @@ export * from './common/Device.js';
export * from './common/Errors.js'; export * from './common/Errors.js';
export * from './common/PredefinedNetworkConditions.js'; export * from './common/PredefinedNetworkConditions.js';
export * from './common/Puppeteer.js'; export * from './common/Puppeteer.js';
export * from './node/BrowserFetcher.js';
/** /**
* @deprecated Use the query handler API defined on {@link Puppeteer} * @deprecated Use the query handler API defined on {@link Puppeteer}
@ -39,6 +40,7 @@ const puppeteer = new PuppeteerNode({
export const { export const {
connect, connect,
/** @deprecated Import {@link BrowserFetcher} directly and use the constructor. */
createBrowserFetcher, createBrowserFetcher,
defaultArgs, defaultArgs,
executablePath, executablePath,

View File

@ -59,7 +59,7 @@ export async function downloadBrowser(): Promise<void> {
process.env['PUPPETEER_DOWNLOAD_PATH'] || process.env['PUPPETEER_DOWNLOAD_PATH'] ||
process.env['npm_config_puppeteer_download_path'] || process.env['npm_config_puppeteer_download_path'] ||
process.env['npm_package_config_puppeteer_download_path']; process.env['npm_package_config_puppeteer_download_path'];
const browserFetcher = (puppeteer as PuppeteerNode).createBrowserFetcher({ const browserFetcher = puppeteer.createBrowserFetcher({
product, product,
host: downloadHost, host: downloadHost,
path: downloadPath, path: downloadPath,

View File

@ -19,11 +19,11 @@ export * from 'puppeteer-core/internal/common/Device.js';
export * from 'puppeteer-core/internal/common/Errors.js'; export * from 'puppeteer-core/internal/common/Errors.js';
export * from 'puppeteer-core/internal/common/PredefinedNetworkConditions.js'; export * from 'puppeteer-core/internal/common/PredefinedNetworkConditions.js';
export * from 'puppeteer-core/internal/common/Puppeteer.js'; export * from 'puppeteer-core/internal/common/Puppeteer.js';
export * from 'puppeteer-core/internal/node/BrowserFetcher.js';
/** /**
* @deprecated Use the query handler API defined on {@link Puppeteer} * @deprecated Use the query handler API defined on {@link Puppeteer}
*/ */
export * from 'puppeteer-core/internal/common/QueryHandler.js'; export * from 'puppeteer-core/internal/common/QueryHandler.js';
export {BrowserFetcher} from 'puppeteer-core/internal/node/BrowserFetcher.js';
export {LaunchOptions} from 'puppeteer-core/internal/node/LaunchOptions.js'; export {LaunchOptions} from 'puppeteer-core/internal/node/LaunchOptions.js';
import {Product} from 'puppeteer-core'; import {Product} from 'puppeteer-core';
@ -57,6 +57,7 @@ const puppeteer = new PuppeteerNode({
export const { export const {
connect, connect,
/** @deprecated Import {@link BrowserFetcher} directly and use the constructor. */
createBrowserFetcher, createBrowserFetcher,
defaultArgs, defaultArgs,
executablePath, executablePath,