Plugin System Architecture
Scully’s plugin system is a sophisticated architecture that provides extensibility at every stage of the static site generation process. This guide explores how plugins are registered, discovered, configured, and executed.Core Concepts
Plugin Repository
At the heart of Scully’s plugin system is the plugin repository (pluginRepository.ts), which maintains a registry of all available plugins organized by type:
Plugin Types
Scully defines eleven plugin types, each serving a specific purpose:Plugin Registration
The registerPlugin Function
Plugins are registered using the registerPlugin function, which validates the plugin and adds it to the appropriate registry:
type: The plugin type (e.g., ‘router’, ‘postProcessByHtml’)name: Unique identifier for the pluginplugin: The plugin function implementationpluginOptions: Type-specific configuration (validator, priority, file extensions)options: Additional options likereplaceExistingPlugin
Registration Examples
Registering a Router Plugin
Registering a Post-Processing Plugin
Registering a File Handler Plugin
Type-Specific Registration
Different plugin types have unique registration requirements:Router Plugins
- Must provide a config validator function
- Validator checks route configuration for errors
File Handler Plugins
- Must specify supported file extensions
- Extensions determine which files the plugin processes
Route Process Plugins
- Can specify execution priority
- Higher priority plugins run first
Before All Plugins
- Can specify execution priority
- Lower priority values run first
Plugin Discovery
Scully provides utility functions to find and retrieve plugins from the registry:Finding a Plugin
Checking Plugin Existence
Fetching Multiple Plugins
Plugin Configuration
Setting Global Configuration
Plugins can have global configuration that applies to all usages:Setting Route-Specific Configuration
Plugins can have different configurations for different routes:Getting Plugin Configuration
Plugin Execution
Plugin Wrapper
All plugins are executed through a wrapper function (pluginWrap.ts) that provides:
- Error handling with try-catch
- Performance measurement
- Route-specific configuration injection
- Logging and error reporting
Execution Flow
- Mark Start: Performance tracking begins
- Config Injection: Route-specific config is injected if available
- Plugin Execution: The plugin function is called with appropriate arguments
- Error Handling: Errors are caught and logged
- Config Restoration: Global config is restored
- Mark Stop: Performance tracking ends
- Return Result: The plugin result is returned
Plugin Lifecycle
Plugins execute at specific points in Scully’s build lifecycle:Plugin Interfaces
Type Definitions
Advanced Features
Priority Control
For plugins that support priority (beforeAll, routeProcess):Replacing Existing Plugins
By default, registering a plugin with an existing name throws an error. You can override this:Direct Plugin Access
The wrapper stores a reference to the original plugin function:Built-in System Plugins
Scully automatically registers system plugins at startup (systemPlugins.ts):
asciidoc: File handler for .adoc fileshtml: File handler for .html filesmarkdown: File handler for .md filescontentFolder: Router plugin for content discoveryjson: Router plugin for JSON data sourcesignored: Router plugin for ignored routesseoHrefOptimise: Post-process plugin for SEO
Best Practices
Plugin Naming
- Use descriptive, kebab-case names:
'my-custom-plugin' - Avoid generic names that might conflict
- Use symbols only when necessary (deprecated)
Error Handling
- Always return promises (or use async functions)
- Handle errors gracefully within your plugin
- Provide meaningful error messages
- Consider whether errors should be fatal
Performance
- Keep plugins fast and efficient
- Avoid unnecessary processing
- Use caching when appropriate
- Monitor plugin timing data
Configuration
- Provide sensible defaults
- Validate configuration in router plugins
- Document all configuration options
- Support both global and route-specific config
Testing
- Test plugins in isolation
- Test with various route configurations
- Test error conditions
- Verify performance impact
Example: Complete Custom Plugin
Here’s a complete example showing all aspects of plugin creation:Troubleshooting
Plugin Not Found
If you see “Plugin not found” errors:- Ensure the plugin is imported in your
scully.config.ts - Verify the plugin name matches exactly
- Check that
registerPluginwas called
Configuration Issues
If plugin configuration isn’t working:- Call
setPluginConfigafter importing the plugin - Ensure configuration object matches expected interface
- Check for typos in plugin names
Performance Problems
If plugins are slow:- Review Scully’s performance output
- Optimize expensive operations
- Consider caching results
- Use route-specific configuration to limit processing
Next Steps
- Plugin Types Reference - Detailed docs for each plugin type
- Creating Custom Plugins - Step-by-step guide
- Built-in Plugins - Learn what’s available
- Community Plugins - Explore third-party plugins

