Plugin dependency resolution
Why it matters
When Plugin B depends on Plugin A but the host loads plugins alphabetically or in undefined order, Plugin B crashes with a cryptic error whenever its load happens to precede Plugin A's. ISO 25010 maintainability.modularity requires that inter-component dependencies be explicit and resolvable; implicit alphabetical load order is the opposite of this. The failure is also non-deterministic across environments — it may work in development (where plugin directories happen to be in the right order) and fail in production after a deploy changes the filesystem state.
Severity rationale
Low because undeclared plugin dependencies produce ordering-dependent runtime crashes that appear only when load sequence happens to be wrong, making them hard to reproduce and hard to attribute.
Remediation
Support a dependencies field in plugin manifests and topologically sort the load order before initializing any plugin. Circular dependencies should produce an explicit error at startup, not a runtime crash.
function resolveLoadOrder(plugins: PluginManifest[]): PluginManifest[] {
const graph = new Map<string, string[]>();
for (const p of plugins) {
graph.set(p.name, Object.keys(p.dependencies ?? {}));
}
return topologicalSort(graph); // throws on cycles
}
Detection
-
ID:
dependency-resolution -
Severity:
low -
What to look for: Check whether the plugin system handles dependencies between plugins. When Plugin B depends on Plugin A, look for:
- A way for Plugin B to declare this dependency (in its manifest or registration)
- The host loading Plugin A before Plugin B (topological sort of plugin load order)
- The host refusing to load Plugin B if Plugin A is missing or incompatible
- The host providing a way for Plugin B to access Plugin A's exposed API Real-world examples:
- WordPress: plugins can check
is_plugin_active('plugin-a/plugin-a.php')but no formal dependency system - Fastify:
fastify-pluginwithdependenciesarray — enforced load order - VS Code:
"extensionDependencies": ["publisher.extension-id"]in package.json
-
Pass criteria: Count all plugin dependency declarations. Plugin-to-plugin dependencies can be declared and are resolved by the host. Dependent plugins load after their dependencies. Missing dependencies produce a clear error at load time (not a runtime crash).
-
Fail criteria: No dependency resolution — all plugins load independently. Plugin B that depends on Plugin A must handle the dependency itself (check at runtime, fail with a cryptic error, or assume Plugin A is loaded).
-
Skip (N/A) when: The plugin system has fewer than 5 plugins total and no plugin depends on another. Also skip for middleware systems where order is explicitly configured by the user (not declared by plugins).
-
Detail on fail:
"No dependency resolution exists. Plugins load in alphabetical directory order. Plugin B requires Plugin A's API but has no way to declare this. If Plugin A loads after Plugin B (because 'A' < 'B' alphabetically), Plugin B crashes with 'Cannot read property of undefined' when trying to access Plugin A's exports." -
Remediation: Dependency resolution prevents ordering bugs and gives clear errors when required plugins are missing.
// Topological sort for plugin load order: function resolveLoadOrder(plugins: PluginManifest[]): PluginManifest[] { const graph = new Map<string, string[]>(); for (const p of plugins) { graph.set(p.name, Object.keys(p.dependencies ?? {})); } return topologicalSort(graph); // throws on cycles }
External references
- iso-25010:2011 · maintainability.modularity — Modularity — explicit dependency declarations enable deterministic load ordering across a plugin graph
Taxons
History
- 2026-04-18·v1.0.0·Initial import from plugin-extension-architecture·automated