A modular plugin framework for Playwright to enable enhanced browser automation through plugins.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive plugin management system that handles plugin registration, dependency resolution, lifecycle management, and error handling. The PluginList class manages all aspects of plugin orchestration within Playwright Extra.
The core plugin management class that handles plugin registration, ordering, dependency resolution, and lifecycle event dispatch.
class PluginList {
readonly list: Plugin[];
readonly names: string[];
add(plugin: Plugin): boolean;
setDependencyDefaults(dependencyPath: string, opts: any): this;
setDependencyResolution(dependencyPath: string, pluginModule: CompatiblePluginModule): this;
onPluginError(plugin: Plugin, method: PluginMethodName, err: Error): void;
}Add a new plugin to the list after validating its structure and requirements.
/**
* Add a new plugin to the list (after checking if it's well-formed).
* @param plugin - Plugin instance to add
* @returns true if plugin was added successfully, false otherwise
*/
add(plugin: Plugin): boolean;Usage Examples:
import { chromium } from "playwright-extra";
import StealthPlugin from "puppeteer-extra-plugin-stealth";
const plugin = StealthPlugin();
// Plugin is automatically added when using .use()
chromium.use(plugin);
// Direct access to plugin manager
const wasAdded = chromium.plugins.add(plugin);
console.log(`Plugin added: ${wasAdded}`);Access registered plugins and their names.
/**
* Get a list of all registered plugins.
*/
readonly list: Plugin[];
/**
* Get the names of all registered plugins.
*/
readonly names: string[];Usage Examples:
import { chromium } from "playwright-extra";
// Check registered plugins
console.log(chromium.plugins.names); // ['stealth', 'recaptcha']
// Inspect plugin instances
chromium.plugins.list.forEach(plugin => {
console.log(`Plugin: ${plugin.name}`);
console.log(`Requirements: ${Array.from(plugin.requirements || [])}`);
});Configure default options for plugins that are implicitly required through the dependencies system.
/**
* Define default values for plugins implicitly required through the dependencies plugin stanza.
* @param dependencyPath - The string by which the dependency is listed (not the plugin name)
* @param opts - Default options to apply to the dependency
* @returns The PluginList instance for chaining
*/
setDependencyDefaults(dependencyPath: string, opts: any): this;Usage Examples:
import { chromium } from "playwright-extra";
import StealthPlugin from "puppeteer-extra-plugin-stealth";
chromium.use(StealthPlugin());
// Configure stealth sub-plugin defaults
chromium.plugins.setDependencyDefaults('stealth/evasions/webgl.vendor', {
vendor: 'Custom Vendor Name',
renderer: 'Custom Renderer Name'
});
// Configure user agent evasion defaults
chromium.plugins.setDependencyDefaults('stealth/evasions/user-agent-override', {
userAgent: 'Mozilla/5.0 (Custom Browser)'
});Define custom plugin modules for dependencies to avoid dynamic imports, which is useful for bundlers that have issues with dynamic imports.
/**
* Define custom plugin modules for plugins implicitly required through the dependencies plugin stanza.
* Using this will prevent dynamic imports from being used, which JS bundlers often have issues with.
* @param dependencyPath - The dependency path identifier
* @param pluginModule - The plugin module to use for this dependency
* @returns The PluginList instance for chaining
*/
setDependencyResolution(dependencyPath: string, pluginModule: CompatiblePluginModule): this;Usage Examples:
import { chromium } from "playwright-extra";
import StealthPlugin from "puppeteer-extra-plugin-stealth";
import WebGLVendorPlugin from "puppeteer-extra-plugin-stealth/evasions/webgl.vendor";
chromium.use(StealthPlugin());
// Provide explicit plugin modules to avoid dynamic imports
chromium.plugins.setDependencyResolution(
'stealth/evasions/webgl.vendor',
WebGLVendorPlugin
);Handle errors that occur during plugin method execution. This method can be overwritten to customize error handling behavior.
/**
* Error callback in case calling a plugin method throws an error. Can be overwritten.
* @param plugin - The plugin that caused the error
* @param method - The method name that was being executed
* @param err - The error that occurred
*/
onPluginError(plugin: Plugin, method: PluginMethodName, err: Error): void;Usage Examples:
import { chromium } from "playwright-extra";
// Customize error handling
chromium.plugins.onPluginError = (plugin, method, error) => {
console.error(`Plugin ${plugin.name} failed during ${method}:`, error);
// Could implement retry logic, disable plugin, etc.
if (error.message.includes('timeout')) {
console.log('Timeout error, continuing execution...');
} else {
throw error; // Re-throw critical errors
}
};The plugin manager handles dispatching lifecycle events to registered plugins.
Non-blocking dispatch (fires events without waiting):
dispatch<TMethod extends PluginMethodName>(
method: TMethod,
...args: Parameters<PluginMethodFn<TMethod>>
): void;Blocking dispatch (waits for all plugins, supports waterfall pattern):
async dispatchBlocking<TMethod extends PluginMethodName>(
method: TMethod,
...args: Parameters<PluginMethodFn<TMethod>>
): Promise<ReturnType<PluginMethodFn<TMethod>>>;Usage Examples:
// These methods are used internally by PlaywrightExtra
// but can be called directly for custom scenarios
const plugins = chromium.plugins;
// Dispatch non-blocking event
plugins.dispatch('onPageCreated', page);
// Dispatch blocking event with modification support
const modifiedOptions = await plugins.dispatchBlocking('beforeLaunch', options);The plugin manager automatically handles plugin ordering based on requirements and resolves plugin dependencies.
Plugin ordering - Plugins with runLast requirement are moved to the end:
// Plugin with runLast requirement will be executed last
const plugin = {
name: 'cleanup-plugin',
requirements: new Set(['runLast']),
// ... other plugin properties
};Dependency resolution - Plugins can declare dependencies that are automatically loaded:
// Plugin declaring dependencies
const plugin = {
name: 'parent-plugin',
dependencies: new Set(['stealth/evasions/webgl.vendor']),
// ... other plugin properties
};interface Plugin extends PuppeteerExtraPlugin {
_isPuppeteerExtraPlugin: boolean;
name: string;
noPuppeteerShim?: boolean;
requirements?: PluginRequirements;
dependencies?: PluginDependencies;
data?: PluginData[];
getDataFromPlugins?(name?: string): void;
plugins?: CompatiblePlugin[];
}
type PluginMethodName = keyof PluginLifecycleMethods;
type PluginMethodFn<TMethod extends PluginMethodName> =
TMethod extends keyof PluginLifecycleMethods
? PluginLifecycleMethods[TMethod]
: never;
type PluginRequirements = Set<'launch' | 'headful' | 'dataFromPlugins' | 'runLast'>;
type PluginDependencies = Set<string> | Map<string, any> | string[];
type CompatiblePluginModule = (...args: any[]) => CompatiblePlugin;
interface PluginData {
name: string | { [key: string]: any };
value: { [key: string]: any };
}Install with Tessl CLI
npx tessl i tessl/npm-playwright-extra