Developing Without Server Restart
Developing with Sonamu is like this:- Modify code
- Save (Cmd+S)
- Done! 👈 Instantly reflected
Actual Development Speed Difference
Without HMR (Traditional approach):- 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
- 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 anickname field to User Entity:
Step 1: Add field in Sonamu UI
user.entity.tsauto-updateduser.types.tstypes auto-generateduser.zod.tsZod schema auto-generatedUserModelauto-reloaded- All UserApi methods auto-re-registered
- Frontend
UserServiceauto-updated
Scenario 2: Modifying API Logic
Adding pagination and search toUserApi.list():
Scenario 3: Adding Model Business Logic
Adding user active status check logic: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
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:
- Code generation completes fully
- Then reload begins
- Latest code is always loaded ✅
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.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
3. Auto-generated Code Sync
When Entity or Model changes, Syncer auto-generates related code:- TypeScript type file (
user.types.ts) - Zod schema (
user.zod.ts) - Frontend Service (
UserService.ts)
4. Module Reload
5. API Re-registration
When a Model file changes, all APIs for that Model are re-registered: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
2. Allow Static Import Between Boundaries
3. Filesystem Watcher Disabled
The original uses its own file watcher, but Sonamu uses only Syncer’s watcher:4. Improved Integration with ts-loader
Resolved path mismatches between compileddist/*.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:Graceful Shutdown Handling
Prevents process termination during sync operations:Enabling HMR
Automatically enabled in development mode: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:Changes Requiring Restart
Server restart is required when modifying these files:sonamu.config.ts- Configuration file.env- Environment variablespackage.json- Dependencies
import.meta.hot?.decline() and automatically require restart on change.