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:
Andrey Lushnikov
2018-09-05 22:59:14 +01:00
committed by GitHub
parent 7f9e276733
commit 28d92116b7
3 changed files with 48 additions and 22 deletions

View File

@@ -22,7 +22,7 @@ const {Connection} = require('./Connection');
const {Browser} = require('./Browser');
const readline = require('readline');
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 {TimeoutError} = require('./Errors');
@@ -95,10 +95,10 @@ class Launcher {
let chromeExecutable = executablePath;
if (!executablePath) {
const browserFetcher = new BrowserFetcher();
const revisionInfo = browserFetcher.revisionInfo(ChromiumRevision);
assert(revisionInfo.local, `Chromium revision is not downloaded. Run "npm install" or "yarn install"`);
chromeExecutable = revisionInfo.executablePath;
const {missingText, executablePath} = resolveExecutablePath();
if (missingText)
throw new Error(missingText);
chromeExecutable = executablePath;
}
const usePipe = chromeArguments.includes('--remote-debugging-pipe');
@@ -252,9 +252,7 @@ class Launcher {
* @return {string}
*/
static executablePath() {
const browserFetcher = new BrowserFetcher();
const revisionInfo = browserFetcher.revisionInfo(ChromiumRevision);
return revisionInfo.executablePath;
return resolveExecutablePath().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
* @property {boolean=} headless

View File

@@ -20,7 +20,11 @@ const {TimeoutError} = require('./Errors');
const debugError = require('debug')(`puppeteer:error`);
/** @type {?Map<string, boolean>} */
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 {
/**
* @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}
*/
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;
}