Modular plugin framework to teach puppeteer new tricks through plugins.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Enhanced browser launch and connection methods with integrated plugin lifecycle support, maintaining full compatibility with standard Puppeteer while adding plugin functionality.
Launch a new browser instance with automatic plugin lifecycle integration.
/**
* Launch a new browser instance with plugin lifecycle support
* All registered plugins with beforeLaunch methods are called in sequence
* @param options - Regular Puppeteer launch options (optional)
* @returns Promise resolving to Browser instance
*/
launch(options?: {
/** Whether to run browser in headless mode (default: true) */
headless?: boolean;
/** Path to a Chromium or Chrome executable */
executablePath?: string;
/** Additional arguments to pass to the browser instance */
args?: Array<string>;
/** Whether to ignore HTTPS errors during navigation */
ignoreHTTPSErrors?: boolean;
/** Slows down Puppeteer operations by specified milliseconds */
slowMo?: number;
/** Maximum time in milliseconds to wait for browser to start */
timeout?: number;
/** Whether to pipe browser process stdout and stderr */
dumpio?: boolean;
/** Path to a user data directory */
userDataDir?: string;
/** Close browser process on Ctrl-C (default: true) */
handleSIGINT?: boolean;
/** Close browser process on SIGTERM (default: true) */
handleSIGTERM?: boolean;
/** Close browser process on SIGHUP (default: true) */
handleSIGHUP?: boolean;
/** Additional environment variables to pass to browser */
env?: Object;
/** Connect to browser over a pipe instead of WebSocket */
pipe?: boolean;
/** Specify default viewport for each page */
defaultViewport?: {
width: number;
height: number;
deviceScaleFactor?: number;
isMobile?: boolean;
hasTouch?: boolean;
isLandscape?: boolean;
} | null;
}): Promise<Puppeteer.Browser>;Usage Examples:
const puppeteer = require('puppeteer-extra');
// Basic launch with plugins
const browser = await puppeteer.launch();
// Launch with custom options
const browser = await puppeteer.launch({
headless: false,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
defaultViewport: { width: 1280, height: 720 }
});
// Plugins can modify these options before launch
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch({ headless: true }); // Stealth plugin adds its argumentsConnect to an existing Chromium instance with plugin lifecycle support.
/**
* Connect to existing Chromium instance with plugin lifecycle support
* All registered plugins with beforeConnect methods are called in sequence
* @param options - Connection configuration options
* @returns Promise resolving to Browser instance
*/
connect(options?: {
/** WebSocket endpoint to connect to */
browserWSEndpoint: string;
/** Whether to ignore HTTPS errors during navigation (default: false) */
ignoreHTTPSErrors?: boolean;
/** Specify default viewport for each page */
defaultViewport?: {
width: number;
height: number;
deviceScaleFactor?: number;
isMobile?: boolean;
hasTouch?: boolean;
isLandscape?: boolean;
} | null;
/** Slows down Puppeteer operations by specified milliseconds */
slowMo?: number;
}): Promise<Puppeteer.Browser>;Usage Examples:
// Connect to existing browser instance
const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://localhost:9222/devtools/browser/...'
});
// Connect with custom options
const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://localhost:9222/devtools/browser/...',
ignoreHTTPSErrors: true,
defaultViewport: null // Use browser's default viewport
});The framework automatically manages plugin lifecycle during browser operations.
/**
* Plugin lifecycle methods called during browser operations
*/
interface BrowserLifecycle {
/** Called before launch with options that can be modified */
beforeLaunch?(options: Object): Object | Promise<Object>;
/** Called before connect with options that can be modified */
beforeConnect?(options: Object): Object | Promise<Object>;
/** Called after browser creation to bind event listeners */
_bindBrowserEvents?(browser: Puppeteer.Browser, opts: {
context: 'launch' | 'connect';
options: Object;
defaultArgs?: Array<string>;
}): void | Promise<void>;
}Plugin Integration Flow:
beforeLaunch/beforeConnect modify options_bindBrowserEvents set up event listenersUsage Examples:
// Example plugin that modifies launch options
class CustomArgsPlugin extends PuppeteerExtraPlugin {
constructor(customArgs = []) {
super();
this.name = 'custom-args';
this.customArgs = customArgs;
}
async beforeLaunch(options) {
options.args = options.args || [];
options.args.push(...this.customArgs);
return options;
}
}
// Plugin automatically integrates with launch
puppeteer.use(new CustomArgsPlugin(['--disable-dev-shm-usage']));
const browser = await puppeteer.launch(); // Custom args are automatically addedThe framework includes built-in workarounds for Puppeteer timing issues with page creation.
/**
* Internal page creation method patching
* Fixes timing issues where plugins can't modify page before first request
* Automatically navigates to about:blank after page creation
*/
_patchPageCreationMethods(browser: Puppeteer.Browser): void;Automatic Fixes:
targetcreated eventsUsage Examples:
// This patching happens automatically - no user code needed
const browser = await puppeteer.launch();
const page = await browser.newPage(); // Automatically patched for plugin compatibility
// Pages created through browser.newPage() work correctly with plugins
// Pages created implicitly (e.g., window.open) may still have timing issuesThe framework validates plugin requirements against launch/connect options.
/**
* Check plugin requirements against current options
* Warns user when plugins won't work as expected
*/
checkPluginRequirements(opts: {
context: 'launch' | 'connect';
options: Object;
defaultArgs?: Array<string>;
}): void;Validation Rules:
headless: trueconnect() methodUsage Examples:
// Plugin with headful requirement
class HeadfulPlugin extends PuppeteerExtraPlugin {
constructor() {
super();
this.name = 'headful-only';
this.requirements = new Set(['headful']);
}
}
puppeteer.use(new HeadfulPlugin());
const browser = await puppeteer.launch({ headless: true });
// Warning: Plugin 'headful-only' is not supported in headless mode.These methods are used internally by the framework for plugin management and lifecycle coordination.
/**
* Call plugins sequentially with the same values
* Plugins that expose the supplied property will be called
* @param prop - The plugin property/method to call
* @param values - Any number of values to pass to plugins
*/
callPlugins(prop: string, ...values: any[]): Promise<void>;
/**
* Call plugins sequentially and pass on a value (waterfall style)
* Plugins can modify the value or return an updated one
* @param prop - The plugin property/method to call
* @param value - Initial value to pass through plugins
* @returns Updated value after passing through all plugins
*/
callPluginsWithValue(prop: string, value: any): Promise<any>;
/**
* Get all plugins that feature a given property/method
* @param prop - Property name to search for
* @returns Array of plugins that have the specified property
*/
getPluginsByProp(prop: string): Array<PuppeteerExtraPlugin>;
/**
* Get the names of all registered plugins
* @returns Array of plugin names
*/
get pluginNames(): Array<string>;Plugin Call Flow Examples:
// Internal usage during launch
await this.callPluginsWithValue('beforeLaunch', options);
await this.callPlugins('_bindBrowserEvents', browser, opts);
// How plugins modify options in sequence
let modifiedOptions = options;
for (const plugin of this.getPluginsByProp('beforeLaunch')) {
const newValue = await plugin.beforeLaunch(modifiedOptions);
if (newValue) {
modifiedOptions = newValue;
}
}Install with Tessl CLI
npx tessl i tessl/npm-puppeteer-extra