Skip to content

feat(runner): add transitive hot-reload for ESM via custom loader#1354

Open
adelisle wants to merge 1 commit into
moleculerjs:masterfrom
adelisle:feat/esm-hot-reload
Open

feat(runner): add transitive hot-reload for ESM via custom loader#1354
adelisle wants to merge 1 commit into
moleculerjs:masterfrom
adelisle:feat/esm-hot-reload

Conversation

@adelisle
Copy link
Copy Markdown

@adelisle adelisle commented May 4, 2026

📝 Description

Adds hot-reload support to the ESM runner with auto-detection of transitive dependency changes (parity with the CJS runner).

The ESM runner now registers a dedicated loader
(src/runner-esm-loader.mjs) via module.register(). The loader tracks every resolved user file and the parent → child import relationships seen in its resolve hook, building a reverse dependency graph. When a file changes, the loader bumps a per-file version counter for that file and every transitive importer; the next import() produces a fresh ?v=<n> URL so Node re-evaluates the whole chain.

The HotReload middleware was extended to support pluggable strategies (CJS keeps the existing require.cache / module.children walker; ESM uses the loader). When the runner exposes a non-Node module graph, the middleware enumerates user files via getAllUserFiles() and, on change, resolves which services to reload via getImporters() — only the affected services are reloaded.

Other changes:

  • --hot no longer clobbers a hotReload: { ... } config object (CJS and ESM runners).
  • HotReload watcher callback debounced (leading edge, 100ms) to dedupe the multiple change events fs.watch fires per save on Linux.
  • runner.d.ts: new ReloadStrategy interface.
  • test/e2e/scenarios/hot-reload-{cjs,esm}/: new e2e scenarios validating service-file reload, 1-hop transitive dep reload, and 3-hop chain (A → B → C → service) reload for both module systems.

🎯 Relevant issues

💎 Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

🚦 How Has This Been Tested?

  • npm test and npm run test:e2e have been run without errors.
  • HMR tests have been added to the E2E test suite.

🏁 Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have commented my code, particularly in hard-to-understand areas

This was made with the help of AI through GitHub Copilot.

Adds hot-reload support to the ESM runner with auto-detection of
transitive dependency changes (parity with the CJS runner).

The ESM runner now registers a dedicated loader
(`src/runner-esm-loader.mjs`) via `module.register()`. The loader
tracks every resolved user file and the parent → child import
relationships seen in its `resolve` hook, building a reverse
dependency graph. When a file changes, the loader bumps a per-file
version counter for that file and every transitive importer; the next
`import()` produces a fresh `?v=<n>` URL so Node re-evaluates the
whole chain.

The HotReload middleware was extended to support pluggable strategies
(CJS keeps the existing `require.cache` / `module.children` walker;
ESM uses the loader). When the runner exposes a non-Node module graph,
the middleware enumerates user files via `getAllUserFiles()` and, on
change, resolves which services to reload via `getImporters()` — only
the affected services are reloaded.

Other changes:
- `--hot` no longer clobbers a `hotReload: { ... }` config object
  (CJS and ESM runners).
- HotReload watcher callback debounced (leading edge, 100ms) to dedupe
  the multiple `change` events `fs.watch` fires per save on Linux.
- `runner.d.ts`: new `ReloadStrategy` interface.
- `test/e2e/scenarios/hot-reload-{cjs,esm}/`: new e2e scenarios
  validating service-file reload, 1-hop transitive dep reload, and
  3-hop chain (`A → B → C → service`) reload for both module systems.

Co-authored-by: Copilot <copilot@github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hot reload doesn't work in ESM

1 participant