Cordis HMR Full Reload vs Partial Reload: Understanding the Difference
Full reload restarts the entire Cordis process when external dependencies change, while partial reload only re-initializes specific plugins that explicitly accept hot updates via ctx.plugin.hot.accept().
Cordis HMR (Hot Module Replacement) provides two distinct reload strategies to balance development speed against application stability. Understanding when Cordis performs a full reload versus a partial reload helps developers optimize their plugin architecture for faster iteration cycles. This article examines the implementation details in the cordiverse/cordis repository to explain how the HMR service decides which strategy to apply.
How Cordis HMR Decides Between Full and Partial Reloads
The HMR service maintains three critical sets to determine the reload strategy: externals, accepted, and declined. In packages/hmr/src/index.ts (lines 58-74), the service initializes these tracking sets to categorize file changes as they occur. When a file change is detected, the watcher first checks if the modified file belongs to the externals set, which represents the dependency tree of the CLI worker entry point.
If the file is external, the service emits a full-process restart. Otherwise, the change enters the stashed set for dependency graph resolution. During the next tick (lines 112-124), the service resolves which files are accepted by plugins and emits a partial reload event containing only the affected modules.
Full Reload: When the Entire Process Restarts
A full reload occurs when changes affect files outside the project's explicitly managed source tree. This includes modifications to node_modules or any file not accepted by a plugin's HMR contract. When the HMR service detects a change in the externals set, it triggers an hmr/reload event with a flag indicating a full process restart.
This strategy serves as the safest fallback when a change could unpredictably affect module resolution or break the running environment. All plugins re-initialize, and the application state rebuilds from scratch, ensuring consistency at the cost of startup time.
Partial Reload: Granular Plugin Updates
Partial reload enables fine-grained updates without tearing down the entire application. Plugins opt into this behavior by calling ctx.plugin.hot.accept() in their initialization code. When a file change affects an accepted module, the HMR service (in packages/hmr/src/index.ts) emits an hmr/reload event containing a Map<Plugin, Reload> that specifies exactly which plugins need re-initialization.
This approach preserves the state of unaffected plugins while only reloading the changed code. Plugins can also decline updates using ctx.plugin.hot.decline(), adding files to the declined set to prevent them from triggering any reload.
Implementing Hot Acceptance in Plugins
To enable partial reloads for your plugin, register an acceptance handler using the Context API provided in packages/core/src/context.ts:
export default function myPlugin(ctx: Context) {
ctx.plugin('my-plugin', async (ctx) => {
// Plugin initialization logic
});
// Enable partial reload support
ctx.plugin.hot.accept(async (mod) => {
// `mod` contains the updated module
await ctx.refresh();
});
}
To explicitly prevent a file from triggering reloads:
ctx.plugin.hot.decline(() => {
// This file will not trigger HMR updates
});
Listening to HMR Events
The Cordis HMR system emits lifecycle events that plugins can monitor. The hmr/reload event provides details about which plugins were affected:
ctx.on('hmr/reload', (reloads: Map<Plugin, Reload>) => {
for (const [plugin, info] of reloads) {
console.log(`Plugin ${plugin.name} reloaded ${info.filename}`);
}
});
This event receives different payloads depending on the reload type. For partial reloads, it contains the specific plugin map. For full reloads, the flag indicates a complete process restart is imminent.
Summary
- Full reload restarts the entire Cordis process when external dependencies or non-accepted files change, ensuring complete state consistency.
- Partial reload reinitializes only specific plugins that have called
ctx.plugin.hot.accept(), preserving application state and providing faster iteration. - The decision logic resides in
packages/hmr/src/index.ts, which maintainsexternals,accepted, anddeclinedsets to categorize file changes. - Plugins control their reload behavior through the Context API using
hot.accept()andhot.decline()methods.
Frequently Asked Questions
What triggers a full reload in Cordis HMR?
A full reload triggers when modified files belong to the externals set, which includes the CLI worker's dependency tree and any files outside explicitly accepted modules. Changes in node_modules or files not covered by ctx.plugin.hot.accept() automatically force a complete process restart to ensure module resolution integrity.
How do I make my plugin support partial reloads?
Call ctx.plugin.hot.accept() during your plugin initialization, passing a callback that handles the updated module. This registers your plugin in the accepted set tracked by the HMR service in packages/hmr/src/index.ts. Without this explicit opt-in, your plugin dependencies default to the externals set, triggering full reloads on change.
Can I prevent a specific file change from triggering any reload?
Yes. Use ctx.plugin.hot.decline() to add files to the declined set. When the HMR service detects changes in declined files, it ignores them entirely, preventing both full and partial reloads. This is useful for configuration files or assets that reload independently of the Cordis plugin system.
Where is the HMR logic implemented in the Cordis source code?
The core HMR implementation lives in packages/hmr/src/index.ts, which defines the watcher logic, set management (lines 58-74), and reload resolution (lines 112-124). The Context API methods (hot.accept and hot.decline) are exposed through packages/core/src/context.ts, while module resolution relies on packages/loader/src/internal.ts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →