Skip to main content

Developing Without Server Restart

Developing with Sonamu is like this:
  1. Modify code
  2. Save (Cmd+S)
  3. Done! 👈 Instantly reflected
No need to refresh the browser, restart the server, or run build commands.

Actual Development Speed Difference

Without HMR (Traditional approach):
With HMR (Sonamu approach):
If you modify Entity/API 50 times a day?
  • Without HMR: 50 × 30 seconds = 25 minutes wasted
  • With HMR: 50 × 2 seconds = 1.7 minutes

Difference from Other Frameworks

What Makes Sonamu Special

Typical Node.js HMR:
  • Simply reloads files
  • Auto-generated code needs manual management
  • Multiple files need manual modification on Entity change
Sonamu HMR:
  • File reload + automatic Syncer execution
  • Entity change → All related code auto-generated/updated
  • All dependent files auto-reloaded
  • APIs auto-re-registered

Real Development Scenarios

Scenario 1: Adding Entity Field

Adding a nickname field to User Entity: Step 1: Add field in Sonamu UI
Step 2: Instantly on save
  • user.entity.ts auto-updated
  • user.types.ts types auto-generated
  • user.zod.ts Zod schema auto-generated
  • UserModel auto-reloaded
  • All UserApi methods auto-re-registered
  • Frontend UserService auto-updated
Step 3: Check console
Step 4: Test
⏱️ With HMR: 2 seconds ⏱️ Without HMR: 30 seconds (server restart + recompile)

Scenario 2: Modifying API Logic

Adding pagination and search to UserApi.list():
On save:
Testable immediately in Postman/Thunder Client!

Scenario 3: Adding Model Business Logic

Adding user active status check logic:
Save → 2 seconds later → Available in other APIs immediately:

Sonamu HMR’s Innovation: Syncer Integration

Typical Node.js HMR is simply “File changed? Let’s reload it.” But Sonamu is different.

Problem: The Auto-generated Code Dilemma

Sonamu auto-generates numerous code from Entities:
  • TypeScript type files (*.types.ts)
  • Zod schemas (*.zod.ts)
  • API route registration
  • Frontend Service classes
If Syncer and HMR operated separately:

Sonamu’s Solution

The Watcher batches file events and hands them to a single Syncer entry point (hmrAndSync), which splits the work into HMR and sync concerns:
Because order is guaranteed:
  1. Code generation completes fully
  2. Then reload begins
  3. Latest code is always loaded ✅
This is why Sonamu HMR is not just “fast” but safe and reliable.
The watcher coalesces change events with a 100ms global trailing debounce before invoking hmrAndSync once. Only one cycle runs at a time — cycles are serialized.

HMR Architecture

Key Components

Sonamu’s HMR system consists of three core components: 1. @sonamu-kit/hmr-hook A package forked from hot-hook and customized for Sonamu.
Uses Node.js’s Module Loader API to intercept the module loading process. 2. Dependency Tree Tracks dependencies between files in a tree structure:
When user.model.ts changes, 3 dependent files are also reloaded. Example: When user.model.ts changes, 3 dependent files (user.api.ts, post.api.ts, admin.api.ts) are also reloaded. 3. Watcher + Syncer syncer/watcher.ts (the chokidar glue) filters file events through a four-step first-pass guard, then queues them with a 100ms global batch and hands the collected events to the Syncer’s hmrAndSync in a single call:

HMR Process Details

When a developer modifies a file, the following process runs automatically:

1. File Change Detection

2. Module Invalidation

Removes ESM import cache for the changed file and traverses the Dependency Tree to remove caches for all dependent files.

3. Auto-generated Code Sync

When Entity or Model changes, Syncer auto-generates related code:
Generated files:
  • TypeScript type file (user.types.ts)
  • Zod schema (user.zod.ts)
  • Frontend Service (UserService.ts)

4. Module Reload

Invalidated modules have their caches removed, so the latest code is loaded.

5. API Re-registration

When a Model file changes, all APIs for that Model are re-registered:
Console output:

Differences from Original hot-hook

Sonamu’s @sonamu-kit/hmr-hook forked the original hot-hook with the following improvements:

1. Allow Variable-based Dynamic Import

Essential for Sonamu’s Entity-based structure where paths must be dynamically generated.

2. Allow Static Import Between Boundaries

Static imports allowed since references between Models are frequent.

3. Filesystem Watcher Disabled

The original uses its own file watcher, but Sonamu uses only Syncer’s watcher:
This precisely controls the order of code generation and module invalidation.

4. Improved Integration with ts-loader

Resolved path mismatches between compiled dist/*.js paths and original src/*.ts paths.

Performance Optimization

Selective Invalidation

Only the changed file and its dependencies are invalidated, preventing unnecessary reloads:

Checksum-based Change Detection

Only files with actual content changes are processed:
Even if a file is saved, no sync occurs if content is unchanged.

Graceful Shutdown Handling

Prevents process termination during sync operations:
Waits up to 20 seconds for sync completion even when receiving Nodemon restart signal.

Enabling HMR

Automatically enabled in development mode:
Can also be controlled via environment variables:
HMR is automatically disabled in production builds, and static builds are generated.

Development Tips

Check HMR Status

If It Seems Slow

If changes seem slow to reflect after file modification:
Improve import structure if there are too many dependencies.

Changes Requiring Restart

Server restart is required when modifying these files:
  • sonamu.config.ts - Configuration file
  • .env - Environment variables
  • package.json - Dependencies
These files are marked with import.meta.hot?.decline() and automatically require restart on change.