Skip to main content
The findPlugin function retrieves a previously registered plugin by name and optionally by type. Use it when you need to access plugin configuration or call a plugin directly.

Signature

function findPlugin(
  name: string | symbol,
  type?: PluginTypes,
  errorOnNotfound?: boolean
): PluginFunction

Parameters

name
string | symbol
required
The unique identifier of the plugin to find. This should match the name used when registering the plugin.
type
PluginTypes
The plugin type to search within. If omitted, searches all plugin types. Must be one of:
  • 'router'
  • 'render' or 'postProcessByHtml'
  • 'postProcessByDom'
  • 'fileHandler'
  • 'routeProcess'
  • 'allDone'
  • 'beforeAll'
  • 'routeDiscoveryDone'
  • 'enterprise'
  • 'scullySystem'
errorOnNotfound
boolean
default:"true"
Whether to exit the process if the plugin is not found. When true, the process exits with code 15. When false, returns undefined.

Return Value

Returns the plugin function if found, or undefined if not found (when errorOnNotfound is false).

Basic Usage

import { findPlugin } from '@scullyio/scully';

// Find a router plugin
const jsonPlugin = findPlugin('json', 'router');

// Find a render plugin
const customRender = findPlugin('customRender', 'postProcessByHtml');

// Find a plugin without specifying type (searches all types)
const myPlugin = findPlugin('myPlugin');

Using with Plugin Configuration

Combine with getConfig to retrieve plugin configuration:
import { findPlugin, getConfig } from '@scullyio/scully';

const plugin = findPlugin('json', 'router');
const config = getConfig(plugin);

console.log('Plugin config:', config);

Accessing Plugins Directly

Plugins are wrapped when registered. To access the original plugin function:
import { findPlugin } from '@scullyio/scully';

const plugin = findPlugin('myPlugin', 'router');

// Access the original unwrapped plugin
const originalPlugin = plugin['accessPluginDirectly'];

Error Handling

Plugin Not Found

By default, if a plugin is not found, Scully exits with an error:
// This will exit the process if 'nonexistent' is not found
const plugin = findPlugin('nonexistent', 'router');
To handle missing plugins gracefully:
// This returns undefined instead of exiting
const plugin = findPlugin('nonexistent', 'router', false);

if (!plugin) {
  console.log('Plugin not found, using default behavior');
}

Multiple Plugins with Same Name

If a plugin name exists in multiple types and you don’t specify a type:
// This will exit with an error if 'myPlugin' exists as both
// a router plugin and a render plugin
const plugin = findPlugin('myPlugin');

// Always specify the type to avoid ambiguity
const routerPlugin = findPlugin('myPlugin', 'router');
const renderPlugin = findPlugin('myPlugin', 'postProcessByHtml');

Use Cases

Calling Plugins Programmatically

import { findPlugin } from '@scullyio/scully';

const customPlugin = async (html, route) => {
  // Find and call another plugin
  const helperPlugin = findPlugin('helper', 'postProcessByHtml');
  const processedHtml = await helperPlugin(html, route);
  
  // Continue processing
  return processedHtml.replace(/foo/g, 'bar');
};

Checking Plugin Availability

import { findPlugin } from '@scullyio/scully';

function isPluginAvailable(name: string, type: PluginTypes): boolean {
  const plugin = findPlugin(name, type, false);
  return plugin !== undefined;
}

if (isPluginAvailable('critical-css', 'postProcessByHtml')) {
  console.log('Critical CSS plugin is available');
}

Dynamic Plugin Selection

import { findPlugin, HandledRoute } from '@scullyio/scully';

const dynamicRender = async (html: string, route: HandledRoute) => {
  // Choose plugin based on route configuration
  const pluginName = route.config?.renderPlugin || 'defaultRender';
  const plugin = findPlugin(pluginName, 'postProcessByHtml', false);
  
  if (plugin) {
    return await plugin(html, route);
  }
  
  return html;
};

Working with the Render System

The renderRoute system uses findPlugin internally to find and execute plugins:
import { findPlugin, routeRenderer } from '@scullyio/scully';

// Find the route renderer plugin (typically 'routeRenderer')
const renderer = findPlugin(routeRenderer);

// Execute rendering for a route
const html = await renderer(route);

Best Practices

Specifying the type avoids ambiguity and makes your code more maintainable:
// Good: Explicit type
const plugin = findPlugin('json', 'router');

// Avoid: Searches all types
const plugin = findPlugin('json');
When a plugin is optional, use errorOnNotfound: false:
const optionalPlugin = findPlugin('optional', 'postProcessByHtml', false);

if (optionalPlugin) {
  html = await optionalPlugin(html, route);
}
If you’re calling findPlugin frequently, cache the result:
let cachedPlugin;

const myPlugin = async (html, route) => {
  if (!cachedPlugin) {
    cachedPlugin = findPlugin('helper', 'postProcessByHtml');
  }
  return await cachedPlugin(html, route);
};

Implementation Details

The function searches for plugins using the following logic:
  1. If a type is specified, searches only within that plugin type
  2. If no type is specified, searches all plugin types
  3. The deprecated 'render' type is automatically mapped to 'postProcessByHtml'
  4. Returns the first matching plugin found
  5. Logs an error and exits if multiple matches are found without a type specified
Plugins are stored in a wrapped form. The wrapper tracks plugin execution and handles errors. Use the accessPluginDirectly property to access the original unwrapped function if needed.

Source Reference

Source: libs/scully/src/lib/pluginManagement/pluginConfig.ts:56

registerPlugin

Register a new plugin with Scully

getConfig

Get configuration data for a plugin

Plugin Types

Learn about different plugin types

Plugin System

Understanding Scully’s plugin architecture

Build docs developers (and LLMs) love