mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat: support node-like environments (#8490)
This commit is contained in:
parent
353358a996
commit
f64ec2051b
@ -14,18 +14,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ConnectionTransport } from './ConnectionTransport.js';
|
import { debugError } from '../common/helper.js';
|
||||||
|
import { isNode } from '../environment.js';
|
||||||
|
import { assert } from './assert.js';
|
||||||
import {
|
import {
|
||||||
Browser,
|
Browser,
|
||||||
TargetFilterCallback,
|
|
||||||
IsPageTargetCallback,
|
IsPageTargetCallback,
|
||||||
|
TargetFilterCallback,
|
||||||
} from './Browser.js';
|
} from './Browser.js';
|
||||||
import { assert } from './assert.js';
|
|
||||||
import { debugError } from '../common/helper.js';
|
|
||||||
import { Connection } from './Connection.js';
|
import { Connection } from './Connection.js';
|
||||||
import { Viewport } from './PuppeteerViewport.js';
|
import { ConnectionTransport } from './ConnectionTransport.js';
|
||||||
import { isNode } from '../environment.js';
|
|
||||||
import { getFetch } from './fetch.js';
|
import { getFetch } from './fetch.js';
|
||||||
|
import { Viewport } from './PuppeteerViewport.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic browser options that can be passed when launching any browser or when
|
* Generic browser options that can be passed when launching any browser or when
|
||||||
|
@ -14,30 +14,29 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Protocol } from 'devtools-protocol';
|
||||||
import { assert } from './assert.js';
|
import { assert } from './assert.js';
|
||||||
import { helper, debugError } from './helper.js';
|
import { CDPSession } from './Connection.js';
|
||||||
|
import { TimeoutError } from './Errors.js';
|
||||||
|
import {
|
||||||
|
EvaluateFn,
|
||||||
|
EvaluateFnReturnType,
|
||||||
|
EvaluateHandleFn,
|
||||||
|
SerializableOrJSHandle,
|
||||||
|
UnwrapPromiseLike,
|
||||||
|
WrapElementHandle,
|
||||||
|
} from './EvalTypes.js';
|
||||||
|
import { ExecutionContext } from './ExecutionContext.js';
|
||||||
|
import { Frame, FrameManager } from './FrameManager.js';
|
||||||
|
import { debugError, helper } from './helper.js';
|
||||||
|
import { MouseButton } from './Input.js';
|
||||||
|
import { ElementHandle, JSHandle } from './JSHandle.js';
|
||||||
import {
|
import {
|
||||||
LifecycleWatcher,
|
LifecycleWatcher,
|
||||||
PuppeteerLifeCycleEvent,
|
PuppeteerLifeCycleEvent,
|
||||||
} from './LifecycleWatcher.js';
|
} from './LifecycleWatcher.js';
|
||||||
import { TimeoutError } from './Errors.js';
|
|
||||||
import { JSHandle, ElementHandle } from './JSHandle.js';
|
|
||||||
import { ExecutionContext } from './ExecutionContext.js';
|
|
||||||
import { TimeoutSettings } from './TimeoutSettings.js';
|
|
||||||
import { MouseButton } from './Input.js';
|
|
||||||
import { FrameManager, Frame } from './FrameManager.js';
|
|
||||||
import { getQueryHandlerAndSelector } from './QueryHandler.js';
|
import { getQueryHandlerAndSelector } from './QueryHandler.js';
|
||||||
import {
|
import { TimeoutSettings } from './TimeoutSettings.js';
|
||||||
SerializableOrJSHandle,
|
|
||||||
EvaluateHandleFn,
|
|
||||||
WrapElementHandle,
|
|
||||||
EvaluateFn,
|
|
||||||
EvaluateFnReturnType,
|
|
||||||
UnwrapPromiseLike,
|
|
||||||
} from './EvalTypes.js';
|
|
||||||
import { isNode } from '../environment.js';
|
|
||||||
import { Protocol } from 'devtools-protocol';
|
|
||||||
import { CDPSession } from './Connection.js';
|
|
||||||
|
|
||||||
// predicateQueryHandler and checkWaitForOptions are declared here so that
|
// predicateQueryHandler and checkWaitForOptions are declared here so that
|
||||||
// TypeScript knows about them when used in the predicate function below.
|
// TypeScript knows about them when used in the predicate function below.
|
||||||
@ -330,13 +329,18 @@ export class DOMWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (path !== null) {
|
if (path !== null) {
|
||||||
if (!isNode) {
|
let fs;
|
||||||
throw new Error(
|
try {
|
||||||
'Cannot pass a filepath to addScriptTag in the browser environment.'
|
fs = (await import('fs')).promises;
|
||||||
);
|
} catch (error) {
|
||||||
|
if (error instanceof TypeError) {
|
||||||
|
throw new Error(
|
||||||
|
'Can only pass a filepath to addScriptTag in a Node-like environment.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
const fs = await import('fs');
|
let contents = await fs.readFile(path, 'utf8');
|
||||||
let contents = await fs.promises.readFile(path, 'utf8');
|
|
||||||
contents += '//# sourceURL=' + path.replace(/\n/g, '');
|
contents += '//# sourceURL=' + path.replace(/\n/g, '');
|
||||||
const context = await this.executionContext();
|
const context = await this.executionContext();
|
||||||
const handle = await context.evaluateHandle(
|
const handle = await context.evaluateHandle(
|
||||||
@ -437,13 +441,19 @@ export class DOMWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (path !== null) {
|
if (path !== null) {
|
||||||
if (!isNode) {
|
let fs: typeof import('fs').promises;
|
||||||
throw new Error(
|
try {
|
||||||
'Cannot pass a filepath to addStyleTag in the browser environment.'
|
fs = (await import('fs')).promises;
|
||||||
);
|
} catch (error) {
|
||||||
|
if (error instanceof TypeError) {
|
||||||
|
throw new Error(
|
||||||
|
'Cannot pass a filepath to addStyleTag in the browser environment.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
const fs = await import('fs');
|
|
||||||
let contents = await fs.promises.readFile(path, 'utf8');
|
let contents = await fs.readFile(path, 'utf8');
|
||||||
contents += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/';
|
contents += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/';
|
||||||
const context = await this.executionContext();
|
const context = await this.executionContext();
|
||||||
const handle = await context.evaluateHandle(addStyleContent, contents);
|
const handle = await context.evaluateHandle(addStyleContent, contents);
|
||||||
|
@ -14,25 +14,24 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { assert } from './assert.js';
|
|
||||||
import { helper, debugError } from './helper.js';
|
|
||||||
import { ExecutionContext } from './ExecutionContext.js';
|
|
||||||
import { Page, ScreenshotOptions } from './Page.js';
|
|
||||||
import { CDPSession } from './Connection.js';
|
|
||||||
import { KeyInput } from './USKeyboardLayout.js';
|
|
||||||
import { FrameManager, Frame } from './FrameManager.js';
|
|
||||||
import { getQueryHandlerAndSelector } from './QueryHandler.js';
|
|
||||||
import { Protocol } from 'devtools-protocol';
|
import { Protocol } from 'devtools-protocol';
|
||||||
|
import { assert } from './assert.js';
|
||||||
|
import { CDPSession } from './Connection.js';
|
||||||
import {
|
import {
|
||||||
EvaluateFn,
|
EvaluateFn,
|
||||||
SerializableOrJSHandle,
|
|
||||||
EvaluateFnReturnType,
|
EvaluateFnReturnType,
|
||||||
EvaluateHandleFn,
|
EvaluateHandleFn,
|
||||||
WrapElementHandle,
|
SerializableOrJSHandle,
|
||||||
UnwrapPromiseLike,
|
UnwrapPromiseLike,
|
||||||
|
WrapElementHandle,
|
||||||
} from './EvalTypes.js';
|
} from './EvalTypes.js';
|
||||||
import { isNode } from '../environment.js';
|
import { ExecutionContext } from './ExecutionContext.js';
|
||||||
|
import { Frame, FrameManager } from './FrameManager.js';
|
||||||
|
import { debugError, helper } from './helper.js';
|
||||||
import { MouseButton } from './Input.js';
|
import { MouseButton } from './Input.js';
|
||||||
|
import { Page, ScreenshotOptions } from './Page.js';
|
||||||
|
import { getQueryHandlerAndSelector } from './QueryHandler.js';
|
||||||
|
import { KeyInput } from './USKeyboardLayout.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
@ -822,17 +821,18 @@ export class ElementHandle<
|
|||||||
'Multiple file uploads only work with <input type=file multiple>'
|
'Multiple file uploads only work with <input type=file multiple>'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isNode) {
|
|
||||||
throw new Error(
|
|
||||||
`JSHandle#uploadFile can only be used in Node environments.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
This import is only needed for `uploadFile`, so keep it scoped here to
|
|
||||||
avoid paying the cost unnecessarily.
|
|
||||||
*/
|
|
||||||
const path = await import('path');
|
|
||||||
// Locate all files and confirm that they exist.
|
// Locate all files and confirm that they exist.
|
||||||
|
let path: typeof import('path');
|
||||||
|
try {
|
||||||
|
path = await import('path');
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof TypeError) {
|
||||||
|
throw new Error(
|
||||||
|
`JSHandle#uploadFile can only be used in Node-like environments.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
const files = filePaths.map((filePath) => {
|
const files = filePaths.map((filePath) => {
|
||||||
if (path.isAbsolute(filePath)) {
|
if (path.isAbsolute(filePath)) {
|
||||||
return filePath;
|
return filePath;
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
import { Protocol } from 'devtools-protocol';
|
import { Protocol } from 'devtools-protocol';
|
||||||
import type { Readable } from 'stream';
|
import type { Readable } from 'stream';
|
||||||
import { isNode } from '../environment.js';
|
|
||||||
import { Accessibility } from './Accessibility.js';
|
import { Accessibility } from './Accessibility.js';
|
||||||
import { assert, assertNever } from './assert.js';
|
import { assert, assertNever } from './assert.js';
|
||||||
import { Browser, BrowserContext } from './Browser.js';
|
import { Browser, BrowserContext } from './Browser.js';
|
||||||
@ -2825,13 +2824,17 @@ export class Page extends EventEmitter {
|
|||||||
: Buffer.from(result.data, 'base64');
|
: Buffer.from(result.data, 'base64');
|
||||||
|
|
||||||
if (options.path) {
|
if (options.path) {
|
||||||
if (!isNode) {
|
try {
|
||||||
throw new Error(
|
const fs = (await import('fs')).promises;
|
||||||
'Screenshots can only be written to a file path in a Node environment.'
|
await fs.writeFile(options.path, buffer);
|
||||||
);
|
} catch (error) {
|
||||||
|
if (error instanceof TypeError) {
|
||||||
|
throw new Error(
|
||||||
|
'Screenshots can only be written to a file path in a Node-like environment.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
const fs = (await import('fs')).promises;
|
|
||||||
await fs.writeFile(options.path, buffer);
|
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
|
|
||||||
|
@ -14,9 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { isNode } from '../environment.js';
|
|
||||||
|
|
||||||
/* Use the global version if we're in the browser, else load the node-fetch module. */
|
/* Use the global version if we're in the browser, else load the node-fetch module. */
|
||||||
export const getFetch = async (): Promise<typeof fetch> => {
|
export const getFetch = async (): Promise<typeof fetch> => {
|
||||||
return isNode ? (await import('cross-fetch')).fetch : globalThis.fetch;
|
return globalThis.fetch || (await import('cross-fetch')).fetch;
|
||||||
};
|
};
|
||||||
|
@ -14,15 +14,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Readable } from 'stream';
|
|
||||||
|
|
||||||
import { TimeoutError } from './Errors.js';
|
|
||||||
import { debug } from './Debug.js';
|
|
||||||
import { CDPSession } from './Connection.js';
|
|
||||||
import { Protocol } from 'devtools-protocol';
|
import { Protocol } from 'devtools-protocol';
|
||||||
import { CommonEventEmitter } from './EventEmitter.js';
|
import type { Readable } from 'stream';
|
||||||
import { assert } from './assert.js';
|
|
||||||
import { isNode } from '../environment.js';
|
import { isNode } from '../environment.js';
|
||||||
|
import { assert } from './assert.js';
|
||||||
|
import { CDPSession } from './Connection.js';
|
||||||
|
import { debug } from './Debug.js';
|
||||||
|
import { TimeoutError } from './Errors.js';
|
||||||
|
import { CommonEventEmitter } from './EventEmitter.js';
|
||||||
|
|
||||||
export const debugError = debug('puppeteer:error');
|
export const debugError = debug('puppeteer:error');
|
||||||
|
|
||||||
@ -318,31 +317,34 @@ async function getReadableAsBuffer(
|
|||||||
readable: Readable,
|
readable: Readable,
|
||||||
path?: string
|
path?: string
|
||||||
): Promise<Buffer | null> {
|
): Promise<Buffer | null> {
|
||||||
if (!isNode && path) {
|
|
||||||
throw new Error('Cannot write to a path outside of Node.js environment.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const fs = isNode ? (await import('fs')).promises : null;
|
|
||||||
|
|
||||||
let fileHandle: import('fs').promises.FileHandle | undefined;
|
|
||||||
|
|
||||||
if (path && fs) {
|
|
||||||
fileHandle = await fs.open(path, 'w');
|
|
||||||
}
|
|
||||||
const buffers = [];
|
const buffers = [];
|
||||||
for await (const chunk of readable) {
|
if (path) {
|
||||||
buffers.push(chunk);
|
let fs: typeof import('fs').promises;
|
||||||
if (fileHandle && fs) {
|
try {
|
||||||
await fs.writeFile(fileHandle, chunk);
|
fs = (await import('fs')).promises;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof TypeError) {
|
||||||
|
throw new Error(
|
||||||
|
'Cannot write to a path outside of a Node-like environment.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
const fileHandle = await fs.open(path, 'w+');
|
||||||
|
for await (const chunk of readable) {
|
||||||
|
buffers.push(chunk);
|
||||||
|
await fileHandle.writeFile(chunk);
|
||||||
|
}
|
||||||
|
await fileHandle.close();
|
||||||
|
} else {
|
||||||
|
for await (const chunk of readable) {
|
||||||
|
buffers.push(chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path && fileHandle) await fileHandle.close();
|
|
||||||
let resultBuffer = null;
|
|
||||||
try {
|
try {
|
||||||
resultBuffer = Buffer.concat(buffers);
|
return Buffer.concat(buffers);
|
||||||
} finally {
|
} catch (error) {
|
||||||
return resultBuffer;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,8 +352,8 @@ async function getReadableFromProtocolStream(
|
|||||||
client: CDPSession,
|
client: CDPSession,
|
||||||
handle: string
|
handle: string
|
||||||
): Promise<Readable> {
|
): Promise<Readable> {
|
||||||
// TODO:
|
// TODO: Once Node 18 becomes the lowest supported version, we can migrate to
|
||||||
// This restriction can be lifted once https://github.com/nodejs/node/pull/39062 has landed
|
// ReadableStream.
|
||||||
if (!isNode) {
|
if (!isNode) {
|
||||||
throw new Error('Cannot create a stream outside of Node.js environment.');
|
throw new Error('Cannot create a stream outside of Node.js environment.');
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { initializePuppeteerNode } from './initialize-node.js';
|
|
||||||
import { isNode } from './environment.js';
|
import { isNode } from './environment.js';
|
||||||
|
import { initializePuppeteerNode } from './initialize-node.js';
|
||||||
|
|
||||||
if (!isNode) {
|
if (!isNode) {
|
||||||
throw new Error('Cannot run puppeteer-core outside of Node.js');
|
throw new Error('Cannot run puppeteer-core outside of Node.js');
|
||||||
|
@ -14,10 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { initializePuppeteerNode } from './initialize-node.js';
|
|
||||||
import { isNode } from './environment.js';
|
import { isNode } from './environment.js';
|
||||||
|
import { initializePuppeteerNode } from './initialize-node.js';
|
||||||
|
|
||||||
if (!isNode) {
|
if (!isNode) {
|
||||||
throw new Error('Trying to run Puppeteer-Node in a web environment.');
|
throw new Error('Trying to run Puppeteer-Node in a web environment.');
|
||||||
}
|
}
|
||||||
export default initializePuppeteerNode('puppeteer');
|
|
||||||
|
const puppeteer = initializePuppeteerNode('puppeteer');
|
||||||
|
export default puppeteer;
|
||||||
|
@ -14,11 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { initializePuppeteerWeb } from './initialize-web.js';
|
|
||||||
import { isNode } from './environment.js';
|
import { isNode } from './environment.js';
|
||||||
|
import { initializePuppeteerWeb } from './initialize-web.js';
|
||||||
|
|
||||||
if (isNode) {
|
if (isNode) {
|
||||||
throw new Error('Trying to run Puppeteer-Web in a Node environment');
|
throw new Error('Trying to run Puppeteer-Web in a Node environment');
|
||||||
}
|
}
|
||||||
|
|
||||||
export default initializePuppeteerWeb('puppeteer');
|
const puppeteer = initializePuppeteerWeb('puppeteer');
|
||||||
|
export default puppeteer;
|
||||||
|
Loading…
Reference in New Issue
Block a user