vite-hmr
Vite Hot Module Replacement patterns
What this skill does
# Vite HMR Skill
Patterns for Hot Module Replacement in Vite.
## HMR API
### Basic Usage
```typescript
// Check if HMR is available
if (import.meta.hot) {
// HMR code here
}
// Accept updates to this module
if (import.meta.hot) {
import.meta.hot.accept()
}
// Accept updates to dependencies
if (import.meta.hot) {
import.meta.hot.accept('./module.js', (newModule) => {
console.log('Module updated:', newModule)
})
}
// Accept multiple dependencies
if (import.meta.hot) {
import.meta.hot.accept(['./a.js', './b.js'], ([a, b]) => {
// Handle updates
})
}
```
### Module Disposal
```typescript
if (import.meta.hot) {
// Cleanup before module is replaced
import.meta.hot.dispose((data) => {
// data can be used to pass state to the new module
data.savedState = getCurrentState()
// Cleanup side effects
clearInterval(intervalId)
socket.disconnect()
})
}
// Access disposed data in new module
if (import.meta.hot) {
import.meta.hot.accept()
// Restore state from previous version
if (import.meta.hot.data.savedState) {
restoreState(import.meta.hot.data.savedState)
}
}
```
### Decline Updates
```typescript
// Decline HMR, trigger full reload
if (import.meta.hot) {
import.meta.hot.decline()
}
```
### Invalidate
```typescript
if (import.meta.hot) {
// Force parent module to re-import this module
import.meta.hot.invalidate()
}
```
## State Preservation
### Preserving Component State
```typescript
// Custom state preservation
let state = { count: 0 }
if (import.meta.hot) {
// Restore state from previous version
if (import.meta.hot.data.state) {
state = import.meta.hot.data.state
}
import.meta.hot.accept()
// Save state before disposal
import.meta.hot.dispose((data) => {
data.state = state
})
}
export function increment() {
state.count++
}
```
### Store Preservation
```typescript
// For global stores like Zustand
import { create } from 'zustand'
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}))
// Preserve store across HMR
if (import.meta.hot) {
if (import.meta.hot.data.store) {
useStore.setState(import.meta.hot.data.store.getState())
}
import.meta.hot.dispose((data) => {
data.store = useStore
})
}
export default useStore
```
## Custom Events
### Sending Events
```typescript
// From server/plugin
server.ws.send({
type: 'custom',
event: 'my-event',
data: { message: 'Hello' },
})
```
### Receiving Events
```typescript
if (import.meta.hot) {
import.meta.hot.on('my-event', (data) => {
console.log('Received:', data.message)
})
}
```
### Full Page Reload
```typescript
if (import.meta.hot) {
import.meta.hot.on('vite:beforeFullReload', (payload) => {
console.log('About to full reload:', payload)
})
}
```
## React Fast Refresh
### Setup
```typescript
// vite.config.ts
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
react({
fastRefresh: true, // Enabled by default
}),
],
})
```
### Preserving State
```tsx
// State is automatically preserved in function components
function Counter() {
const [count, setCount] = useState(0)
// count value is preserved during HMR
return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}
```
### Opt-Out of Fast Refresh
```tsx
// Add this comment to prevent Fast Refresh
// @refresh reset
function Component() {
// Component will fully remount on changes
}
```
## HMR Boundaries
### Understanding Boundaries
```typescript
// Parent.tsx imports Child.tsx
// When Child.tsx changes:
// 1. Vite tries to apply HMR to Child.tsx
// 2. If Child accepts, only Child updates
// 3. If not, Parent is checked
// 4. Chain continues until boundary is found
// 5. If no boundary, full reload
// React Fast Refresh creates boundaries at component level
```
### Custom Boundaries
```typescript
// Mark module as HMR boundary
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// Handle update manually
updateComponent(newModule.default)
})
}
```
## Debugging HMR
### Verbose Logging
```typescript
// In browser console
localStorage.debug = 'vite:*'
// Or specific
localStorage.debug = 'vite:hmr'
```
### HMR Events
```typescript
if (import.meta.hot) {
// Before update is applied
import.meta.hot.on('vite:beforeUpdate', (payload) => {
console.log('Before update:', payload)
})
// After update is applied
import.meta.hot.on('vite:afterUpdate', (payload) => {
console.log('After update:', payload)
})
// Before full reload
import.meta.hot.on('vite:beforeFullReload', (payload) => {
console.log('Before reload:', payload)
})
// Before prune (unused modules removed)
import.meta.hot.on('vite:beforePrune', (payload) => {
console.log('Before prune:', payload)
})
// Invalidate
import.meta.hot.on('vite:invalidate', (payload) => {
console.log('Invalidate:', payload)
})
// Error
import.meta.hot.on('vite:error', (payload) => {
console.error('HMR error:', payload)
})
}
```
## Common Issues
### State Reset
```typescript
// Issue: State resets on save
// Solution: Ensure proper HMR boundaries
// BAD: Anonymous arrow functions
export default () => <div />
// GOOD: Named function components
export default function MyComponent() {
return <div />
}
```
### Side Effects
```typescript
// Issue: Side effects run multiple times
// Solution: Cleanup in dispose
let interval: number
function startPolling() {
interval = setInterval(fetchData, 1000)
}
if (import.meta.hot) {
import.meta.hot.dispose(() => {
clearInterval(interval)
})
}
startPolling()
```
### CSS Not Updating
```typescript
// Issue: CSS changes not reflecting
// Vite handles CSS HMR automatically
// If issues, check for:
// 1. CSS modules naming
// 2. PostCSS config errors
// 3. Imported in multiple places
```
## Integration
Used by:
- `frontend-developer` agent
- `fullstack-developer` agent
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.