Svelte HMR Core Utilities
svelte-hmr provides the core logic and utilities for implementing Hot Module Replacement (HMR) in Svelte 3 and 4 applications. It is not an end-user bundler plugin itself, but rather a foundational package leveraged by bundler-specific plugins (e.g., for Rollup, Webpack, Vite) to enable seamless development experiences. The package is currently stable at version `0.16.0` and receives updates as Svelte itself evolves or HMR patterns improve, typically releasing patch and minor versions on an as-needed basis rather than a strict schedule. Key differentiators include its bundler-agnostic design, robust state preservation mechanisms (both component and local variable state), and intelligent CSS injection capabilities, offering a consistent HMR experience across different build tools without needing full page reloads.
Common errors
-
Cannot find module 'svelte-hmr' or its corresponding type declarations.
cause Attempting to import `svelte-hmr` directly into application source code.fix`svelte-hmr` is an underlying dependency for bundler plugins that enable HMR for Svelte. Its features are controlled via your bundler plugin's configuration (e.g., `svelte({ hot: true })` in Vite) or specific HMR comments within Svelte components. Direct imports are generally not required for application developers. -
HMR is not working: Full page reloads instead of hot updates on component changes.
cause HMR is not correctly enabled in the bundler plugin, or a fatal runtime error is preventing `svelte-hmr` from applying updates.fixEnsure your bundler's Svelte plugin has HMR explicitly enabled (e.g., `hot: true` or similar option). Check the browser console for JavaScript runtime errors that might cause `svelte-hmr` to trigger a full reload. Consider setting `hmrOptions: { optimistic: true }` in your bundler plugin config to allow `svelte-hmr` to attempt recovery from some errors, though this might mask underlying issues. -
Local state (e.g., component `let` variables) is not preserved across HMR updates in my Svelte components.
cause State preservation is not enabled either globally via bundler options or specifically for the component/variable.fixEnable `preserveLocalState: true` in your bundler plugin's HMR options (e.g., `hmrOptions: { preserveLocalState: true }`). Alternatively, use HMR directives within your Svelte components like `<!-- @hmr:keep-all -->` at the top of the component file, or `let myVar = 0; // @hmr:keep` for specific variables.
Warnings
- breaking The `noPreserveState` option was removed in version 0.12. Users should now use the `preserveLocalState` option or `preserveAllLocalStateKey` / `preserveLocalStateKey` directives for state preservation.
- breaking The default value for the `optimistic` option changed from `true` to `false` in version 0.14.12. This means that runtime errors during component initialization are now considered fatal to HMR by default, potentially triggering a full browser reload.
- gotcha `svelte-hmr` is an internal utility for bundler plugins, not an end-user package. It should not be directly imported or used in application code. Its functionalities are exposed through bundler-specific HMR plugins (e.g., `@sveltejs/vite-plugin-svelte`, `rollup-plugin-hot`).
- gotcha HMR comments like `@hmr:keep-all` must be correctly placed to be effective. They typically need to be at the top level of a `<script>` block or as the very first line of a component's markup.
- breaking Svelte 4 support was officially added in `svelte-hmr@0.15.2`. Older versions may have incompatible peer dependencies or exhibit incorrect behavior when used with Svelte 4 projects.
Install
-
npm install svelte-hmr -
yarn add svelte-hmr -
pnpm add svelte-hmr
Imports
- init
import { init } from 'svelte-hmr'; - resolveOptions
import { resolveOptions } from 'svelte-hmr/options'; - hotUpdate
import { hotUpdate } from 'svelte-hmr/loader';
Quickstart
<!-- src/App.svelte -->
<script lang="ts">
// @hmr:keep-all
// This comment directly influences svelte-hmr's state preservation logic.
let count: number = 0;
let textInput: string = 'Edit me!';
let showDetails: boolean = false;
function increment() {
count += 1;
}
function toggleDetails() {
showDetails = !showDetails;
}
</script>
<style>
div { padding: 1rem; border: 1px solid #eee; margin-bottom: 1rem; background-color: #f9f9f9; }
h1 { color: #333; }
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
margin-right: 10px;
}
input { padding: 8px; border: 1px solid #ccc; border-radius: 4px; }
</style>
<div>
<h1>HMR Demo Count: {count}</h1>
<p>Input text: <input type="text" bind:value={textInput} /></p>
<button on:click={increment}>Increment Count</button>
<button on:click={toggleDetails}>Toggle Details</button>
{#if showDetails}
<p>Details are visible!</p>
<p>Current input value will persist: "{textInput}"</p>
{:else}
<p>Details are hidden.</p>
{/if}
<p>
Modify this Svelte component (e.g., change text, add a new element) and save.
With a compatible HMR bundler setup (e.g., Vite with <code>@sveltejs/vite-plugin-svelte</code>),
<code>svelte-hmr</code> will update the component in place, preserving <code>count</code>,
<code>textInput</code>, and <code>showDetails</code> due to the <code>@hmr:keep-all</code> directive.
</p>
</div>