feat(puppeteer): support convenience env variables (#3190)
We had (and still have) a ton of pull requests to support PUPPETEER_EXECUTABLE_PATH and PUPPETEER_CHROMIUM_REVISION in puppeteer launcher. We were hesitant before since env variables are not scoped and thus don't make a good interface for a library. Now, since we determined `puppeteer-core` as a library and `puppeteer` as our end-user product, it's safe to satisfy our user needs. This patch: - teaches PUPPETEER_EXECUTABLE_PATH and PUPPETEER_CHROMIUM_REVISION env variables to control how Puppeteer launches browser - makes sure these variables play no role in `puppeteer-core` package.
This commit is contained in:
parent
7f9e276733
commit
28d92116b7
14
docs/api.md
14
docs/api.md
@ -342,12 +342,13 @@ However, you should use `puppeteer-core` if:
|
|||||||
### Environment Variables
|
### Environment Variables
|
||||||
|
|
||||||
Puppeteer looks for certain [environment variables](https://en.wikipedia.org/wiki/Environment_variable) to aid its operations.
|
Puppeteer looks for certain [environment variables](https://en.wikipedia.org/wiki/Environment_variable) to aid its operations.
|
||||||
If puppeteer doesn't find them in the environment, a lowercased variant of these variables will be used from the [npm config](https://docs.npmjs.com/cli/config).
|
If Puppeteer doesn't find them in the environment during the installation step, a lowercased variant of these variables will be used from the [npm config](https://docs.npmjs.com/cli/config).
|
||||||
|
|
||||||
- `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` - defines HTTP proxy settings that are used to download and run Chromium.
|
- `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` - defines HTTP proxy settings that are used to download and run Chromium.
|
||||||
- `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD` - do not download bundled Chromium during installation step.
|
- `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD` - do not download bundled Chromium during installation step.
|
||||||
- `PUPPETEER_DOWNLOAD_HOST` - overwrite host part of URL that is used to download Chromium
|
- `PUPPETEER_DOWNLOAD_HOST` - overwrite host part of URL that is used to download Chromium
|
||||||
- `PUPPETEER_CHROMIUM_REVISION` - specify a certain version of chrome you'd like puppeteer to use during the installation step.
|
- `PUPPETEER_CHROMIUM_REVISION` - specify a certain version of Chromium you'd like Puppeteer to use. See [puppeteer.launch([options])](#puppeteerlaunchoptions) on how executable path is inferred. **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/GoogleChrome/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
|
||||||
|
- `PUPPETEER_EXECUTABLE_PATH` - specify an executable path to be used in `puppeteer.launch`. See [puppeteer.launch([options])](#puppeteerlaunchoptions) on how the executable path is inferred. **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/GoogleChrome/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
|
||||||
|
|
||||||
> **NOTE** PUPPETEER_* env variables are not accounted for in the [`puppeteer-core`](https://www.npmjs.com/package/puppeteer-core) package.
|
> **NOTE** PUPPETEER_* env variables are not accounted for in the [`puppeteer-core`](https://www.npmjs.com/package/puppeteer-core) package.
|
||||||
|
|
||||||
@ -462,7 +463,7 @@ The default flags that Chromium will be launched with.
|
|||||||
- `options` <[Object]> Set of configurable options to set on the browser. Can have the following fields:
|
- `options` <[Object]> Set of configurable options to set on the browser. Can have the following fields:
|
||||||
- `ignoreHTTPSErrors` <[boolean]> Whether to ignore HTTPS errors during navigation. Defaults to `false`.
|
- `ignoreHTTPSErrors` <[boolean]> Whether to ignore HTTPS errors during navigation. Defaults to `false`.
|
||||||
- `headless` <[boolean]> Whether to run browser in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). Defaults to `true` unless the `devtools` option is `true`.
|
- `headless` <[boolean]> Whether to run browser in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). Defaults to `true` unless the `devtools` option is `true`.
|
||||||
- `executablePath` <[string]> Path to a Chromium or Chrome executable to run instead of the bundled Chromium. If `executablePath` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
|
- `executablePath` <[string]> Path to a Chromium or Chrome executable to run instead of the bundled Chromium. If `executablePath` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/GoogleChrome/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
|
||||||
- `slowMo` <[number]> Slows down Puppeteer operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
- `slowMo` <[number]> Slows down Puppeteer operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
||||||
- `defaultViewport` <?[Object]> Sets a consistent viewport for each page. Defaults to an 800x600 viewport. `null` disables the default viewport.
|
- `defaultViewport` <?[Object]> Sets a consistent viewport for each page. Defaults to an 800x600 viewport. `null` disables the default viewport.
|
||||||
- `width` <[number]> page width in pixels.
|
- `width` <[number]> page width in pixels.
|
||||||
@ -484,13 +485,8 @@ The default flags that Chromium will be launched with.
|
|||||||
- `pipe` <[boolean]> Connects to the browser over a pipe instead of a WebSocket. Defaults to `false`.
|
- `pipe` <[boolean]> Connects to the browser over a pipe instead of a WebSocket. Defaults to `false`.
|
||||||
- returns: <[Promise]<[Browser]>> Promise which resolves to browser instance.
|
- returns: <[Promise]<[Browser]>> Promise which resolves to browser instance.
|
||||||
|
|
||||||
The method combines 3 steps:
|
|
||||||
1. Infer a set of flags to launch Chromium with using `puppeteer.defaultArgs()`.
|
|
||||||
2. Launch a browser and start managing its process according to `executablePath`, `handleSIGINT`, `dumpio` and other options.
|
|
||||||
3. Create an instance of [Browser] class and initialize it with regards to `defaultViewport`, `slowMo` and `ignoreHTTPSErrors`.
|
|
||||||
|
|
||||||
`ignoreDefaultArgs` option can be used to customize behavior on the (1) step. For example, to filter out
|
You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:
|
||||||
`--mute-audio` from default arguments:
|
|
||||||
```js
|
```js
|
||||||
const browser = await puppeteer.launch({
|
const browser = await puppeteer.launch({
|
||||||
ignoreDefaultArgs: ['--mute-audio']
|
ignoreDefaultArgs: ['--mute-audio']
|
||||||
|
@ -22,7 +22,7 @@ const {Connection} = require('./Connection');
|
|||||||
const {Browser} = require('./Browser');
|
const {Browser} = require('./Browser');
|
||||||
const readline = require('readline');
|
const readline = require('readline');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const {helper, assert, debugError} = require('./helper');
|
const {helper, debugError} = require('./helper');
|
||||||
const ChromiumRevision = require(path.join(helper.projectRoot(), 'package.json')).puppeteer.chromium_revision;
|
const ChromiumRevision = require(path.join(helper.projectRoot(), 'package.json')).puppeteer.chromium_revision;
|
||||||
const {TimeoutError} = require('./Errors');
|
const {TimeoutError} = require('./Errors');
|
||||||
|
|
||||||
@ -95,10 +95,10 @@ class Launcher {
|
|||||||
|
|
||||||
let chromeExecutable = executablePath;
|
let chromeExecutable = executablePath;
|
||||||
if (!executablePath) {
|
if (!executablePath) {
|
||||||
const browserFetcher = new BrowserFetcher();
|
const {missingText, executablePath} = resolveExecutablePath();
|
||||||
const revisionInfo = browserFetcher.revisionInfo(ChromiumRevision);
|
if (missingText)
|
||||||
assert(revisionInfo.local, `Chromium revision is not downloaded. Run "npm install" or "yarn install"`);
|
throw new Error(missingText);
|
||||||
chromeExecutable = revisionInfo.executablePath;
|
chromeExecutable = executablePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const usePipe = chromeArguments.includes('--remote-debugging-pipe');
|
const usePipe = chromeArguments.includes('--remote-debugging-pipe');
|
||||||
@ -252,9 +252,7 @@ class Launcher {
|
|||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
static executablePath() {
|
static executablePath() {
|
||||||
const browserFetcher = new BrowserFetcher();
|
return resolveExecutablePath().executablePath;
|
||||||
const revisionInfo = browserFetcher.revisionInfo(ChromiumRevision);
|
|
||||||
return revisionInfo.executablePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -330,6 +328,27 @@ function waitForWSEndpoint(chromeProcess, timeout) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {{executablePath: string, missingText: ?string}}
|
||||||
|
*/
|
||||||
|
function resolveExecutablePath() {
|
||||||
|
const executablePath = helper.getEnv('PUPPETEER_EXECUTABLE_PATH');
|
||||||
|
if (executablePath) {
|
||||||
|
const missingText = !fs.existsSync(executablePath) ? 'Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: ' + executablePath : null;
|
||||||
|
return { executablePath, missingText };
|
||||||
|
}
|
||||||
|
const browserFetcher = new BrowserFetcher();
|
||||||
|
const revision = helper.getEnv('PUPPETEER_CHROMIUM_REVISION');
|
||||||
|
if (revision) {
|
||||||
|
const revisionInfo = browserFetcher.revisionInfo(revision);
|
||||||
|
const missingText = !revisionInfo.local ? 'Tried to use PUPPETEER_CHROMIUM_REVISION env variable to launch browser but did not find executable at: ' + revisionInfo.executablePath : null;
|
||||||
|
return {executablePath: revisionInfo.executablePath, missingText};
|
||||||
|
}
|
||||||
|
const revisionInfo = browserFetcher.revisionInfo(ChromiumRevision);
|
||||||
|
const missingText = !revisionInfo.local ? `Chromium revision is not downloaded. Run "npm install" or "yarn install"` : null;
|
||||||
|
return {executablePath: revisionInfo.executablePath, missingText};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} ChromeArgOptions
|
* @typedef {Object} ChromeArgOptions
|
||||||
* @property {boolean=} headless
|
* @property {boolean=} headless
|
||||||
|
@ -20,7 +20,11 @@ const {TimeoutError} = require('./Errors');
|
|||||||
const debugError = require('debug')(`puppeteer:error`);
|
const debugError = require('debug')(`puppeteer:error`);
|
||||||
/** @type {?Map<string, boolean>} */
|
/** @type {?Map<string, boolean>} */
|
||||||
let apiCoverage = null;
|
let apiCoverage = null;
|
||||||
let projectRoot = null;
|
|
||||||
|
// Project root will be different for node6-transpiled code.
|
||||||
|
const projectRoot = fs.existsSync(path.join(__dirname, '..', 'package.json')) ? path.join(__dirname, '..') : path.join(__dirname, '..', '..');
|
||||||
|
const packageJson = require(path.join(projectRoot, 'package.json'));
|
||||||
|
|
||||||
class Helper {
|
class Helper {
|
||||||
/**
|
/**
|
||||||
* @param {Function|string} fun
|
* @param {Function|string} fun
|
||||||
@ -45,14 +49,21 @@ class Helper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @return {(string|undefined)}
|
||||||
|
*/
|
||||||
|
static getEnv(name) {
|
||||||
|
// Ignore all PUPPETEER_* env variables in puppeteer-core package.
|
||||||
|
if (name.startsWith('PUPPETEER_') && packageJson.name === 'puppeteer-core')
|
||||||
|
return undefined;
|
||||||
|
return process.env[name];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
static projectRoot() {
|
static projectRoot() {
|
||||||
if (!projectRoot) {
|
|
||||||
// Project root will be different for node6-transpiled code.
|
|
||||||
projectRoot = fs.existsSync(path.join(__dirname, '..', 'package.json')) ? path.join(__dirname, '..') : path.join(__dirname, '..', '..');
|
|
||||||
}
|
|
||||||
return projectRoot;
|
return projectRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user