Hot Reload
Hot reload enables instant updates during development without restarting the server or losing application state.
Overview
The hot reload system works by:
- File Watcher - Monitors
.qfiles for changes - Parser - Re-parses modified files
- Diff Engine - Detects what changed
- WebSocket - Pushes updates to clients
- Client Runtime - Applies changes without full reload
Getting Started
Development Server
Start the development server with hot reload:
# Start with hot reload enabled
python src/cli/runner.py dev myapp.q
# Or with explicit flag
python src/cli/runner.py start --hot-reload
# Development mode (auto-enables hot reload)
python src/cli/runner.py start --debugBrowser Connection
The development server injects a WebSocket client:
<!-- Auto-injected in development mode -->
<script>
const ws = new WebSocket('ws://localhost:8080/__quantum_hot');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'reload') {
window.location.reload();
} else if (data.type === 'update') {
__quantumApplyUpdate(data.changes);
}
};
</script>How It Works
File Change Detection
The file watcher monitors:
.qfiles in the project- Component files in
components/ - Configuration files
[Watcher] File changed: app.q
[Parser] Re-parsing app.q
[Diff] Detected changes: 2 nodes modified
[WebSocket] Broadcasting update to 3 clientsChange Types
| Change Type | Hot Reload Action |
|---|---|
| UI text content | DOM update |
| Style attributes | CSS update |
| State variables | State sync |
| New components | Full reload |
| Route changes | Full reload |
| Function logic | Full reload |
Incremental Updates
For supported changes, only affected parts update:
<!-- Before -->
<ui:text>Hello World</ui:text>
<!-- After -->
<ui:text>Hello Quantum!</ui:text>Only the text node updates, not the entire page.
State Preservation
Preserving State During Reload
Application state persists across hot reloads:
<q:set name="counter" value="0" />
<q:set name="formData" value="{}" />When you change UI code:
- Current state is captured
- New UI is rendered
- State is restored
State Boundaries
Some changes require state reset:
| Change | State Preserved |
|---|---|
| UI layout | Yes |
| Text content | Yes |
| Styles | Yes |
| State variable names | No |
| Function signatures | No |
| Route structure | No |
Manual State Preservation
Mark state that should always persist:
<q:set name="userSession" value="{}" persist="session" hot-reload="preserve" />Configuration
quantum.config.yaml
development:
hot_reload:
enabled: true
port: 8081 # WebSocket port
delay: 100 # Debounce delay (ms)
full_reload: false # Always full reload?
watch:
paths:
- "."
- "components/"
ignore:
- "node_modules/"
- ".git/"
- "*.pyc"
extensions:
- ".q"
- ".yaml"Environment Variables
# Enable hot reload
export QUANTUM_HOT_RELOAD=true
# Set WebSocket port
export QUANTUM_HOT_PORT=8081
# Disable for production
export QUANTUM_HOT_RELOAD=falseWebSocket Protocol
Server Messages
// Component updated
{
"type": "update",
"file": "app.q",
"changes": [
{"path": "ui:text#title", "prop": "content", "value": "New Title"}
]
}
// Full reload required
{
"type": "reload",
"reason": "route-change"
}
// Error during reload
{
"type": "error",
"message": "Parse error on line 15",
"file": "app.q",
"line": 15
}
// Connection established
{
"type": "connected",
"version": "1.0.0"
}Client Handling
// Apply incremental updates
function __quantumApplyUpdate(changes) {
for (const change of changes) {
const el = document.querySelector(change.path);
if (el) {
if (change.prop === 'content') {
el.textContent = change.value;
} else if (change.prop === 'style') {
Object.assign(el.style, change.value);
} else if (change.prop === 'attribute') {
el.setAttribute(change.name, change.value);
}
}
}
}Error Handling
Parse Errors
When a file has errors, the browser shows an overlay:
--------------------------------------------
Quantum Hot Reload Error
--------------------------------------------
Parse error in app.q:15
Expected closing tag for <ui:vbox>
Found: </ui:hbox>
--------------------------------------------
Fix the error and save to continue
--------------------------------------------Runtime Errors
Runtime errors during hot reload:
// Error overlay
{
"type": "runtime-error",
"message": "Cannot read property 'value' of undefined",
"stack": "...",
"component": "UserForm"
}Recovery
After fixing errors:
- Save the file
- Hot reload retries automatically
- Error overlay dismisses
- Application continues
Performance
Debouncing
Multiple rapid saves are debounced:
Save 1 -> Wait 100ms
Save 2 -> Reset timer, Wait 100ms
Save 3 -> Reset timer, Wait 100ms
-> Reload oncePartial Updates
Only changed components re-render:
File changed: header.q
Affected components: Header
Unchanged: Main, Sidebar, Footer
-> Only Header re-rendersCaching
Parsed ASTs are cached:
Parse app.q -> Cache AST
Parse header.q -> Cache AST
Change header.q -> Re-parse only header.q
-> Use cached app.q ASTTroubleshooting
Hot reload not working
- Check WebSocket connection in browser console
- Verify file watcher is running
- Check for config errors
- Try restarting dev server
// Check connection in browser console
console.log('WebSocket state:', ws.readyState);
// 0 = CONNECTING, 1 = OPEN, 2 = CLOSING, 3 = CLOSEDState lost on reload
- Check if change requires full reload
- Use
persistattribute for important state - Mark state with
hot-reload="preserve"
Changes not detected
- Check watch paths in config
- Verify file extension is monitored
- Check ignore patterns
- Try saving file again
Performance issues
- Reduce watch scope
- Increase debounce delay
- Check for large file changes
- Disable source maps in development
Best Practices
Development Workflow
- Start in debug mode -
--debugauto-enables hot reload - Use specific watch paths - Don't watch entire filesystem
- Keep components small - Faster re-parsing
- Test state preservation - Verify critical state survives reload
File Organization
project/
app.q # Main application
components/
Header.q # Reusable components
Sidebar.q
Footer.q
pages/
Home.q # Page components
About.qSmall, focused files enable faster hot reloads.
Avoiding Full Reloads
Prefer changes that support incremental updates:
<!-- Good: Text change (incremental) -->
<ui:text>Updated text</ui:text>
<!-- Good: Style change (incremental) -->
<ui:panel padding="lg">
<!-- Triggers full reload: New component -->
<ui:panel>
<MyNewComponent /> <!-- Full reload -->
</ui:panel>Related
- CLI Commands - Development commands
- VS Code Extension - Editor integration
- Project Structure - File organization