A Svelte reactive rune that keep its value through pages and reloads
[ D E M O ]
With NPM
npm install --save-dev @macfja/svelte-persistent-runes
# or
yarn add --save-dev @macfja/svelte-persistent-runes
# or
pnpm add --save-dev @macfja/svelte-persistent-runes
# or
deno install --dev npm:@macfja/svelte-persistent-runes
Update your ./svelte.config.js
to add a new preprocessor:
import adapter from '@sveltejs/adapter-auto';
+import persist from "@macfja/svelte-persistent-runes/preprocessor"
const config = {
+ preprocess: [persist()],
kit: {
adapter: adapter()
}
};
export default config;
Replace your $state
with $persist
:
<script>
+import "@macfja/svelte-persistent-runes"
-let count = $state(0);
+let count = $persist(0, 'counter');
</script>
This library have 2 parts:
$persist
rune.You MUST add the preprocessor to use $persist
.
It's as simple as to add it in your Svelte configuration (svelte.config.js
) with the import of @macfja/svelte-persistent-runes/preprocessor
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import persist from "@macfja/svelte-persistent-runes/preprocessor"
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: [vitePreprocess(), persist()],
kit: {
adapter: adapter()
}
};
export default config;
Now that the preprocessor is added, you can use the $persist
rune instead of the $state
rune.
<script>
import "@macfja/svelte-persistent-runes"
let count = $persist(0, 'counter');
</script>
<div class="counter">
<button onclick={() => (count -= 1)} aria-label="Decrease the counter by one">-</button>
<div><strong>{count}</strong></div>
<button onclick={() => (count += 1)} aria-label="Increase the counter by one">+</button>
</div>
import "@macfja/svelte-persistent-runes"
export class Person {
name = $persist('John', 'user-name')
age = $persist(33, 'user-age')
greet(): string {
return `Hello ${this.name}`;
}
birthday(): string {
this.age += 1;
return `Happy birthday ${this.name}!`
}
}
export const currentUser = new Person()
[!IMPORTANT] You need to import
import "@macfja/svelte-persistent-runes"
to prevent Typescript to complain about the unknown function$persist
type PersistentRunesOptions = {
/**
* Convert the source data into its string representation
* @param input The source data
* @return The string representation of data
*/
serialize<T>(input: T): string;
/**
* Convert back the string representation into the source data
* @param input The string representation of the date
* @return The new data based on its string representation
*/
deserialize<T>(input: string): T;
/**
* Write data into the store
* @param key The storage key to write
* @param value The data to write
*/
storageWrite(key: string, value: string): void;
/**
* Read data from the storage
* @param key The storage key to read
* @returns The data or `undefined` if the data don't exist in the storage
*/
storageRead(key: string): string | undefined;
};
/**
* A reactive state, that can restore its state upon page reload
* @param initial The initial value of the state
* @param key The storage key of the state. Must be unique in your application
* @param options The persistence options (how and where)
*/
declare function $persist<T>(initial: T, key: string, options?: Partial<PersistentRunesOption>)
You can customize how and where the state value is persisted.
The $persist
runes take a third (and optional) parameter of type PersistentRunesOption
.
The options consist of 2 main part: the serializer and the storage. It can be defined as a plain object or as the result of the buildOptions
(impoerted from @macfja/svelte-persistent-runes/options
)
/**
* Create a `PersistentRunesOptions` from a serializer and a storage
* @param serializer The serializer to use (if `undefined` then `JsonSerializer` will be used)
* @param storage The storage to use (if `undefined` then `BrowserLocalStorage` will be used)
*/
declare function buildOptions(
serializer: PersistentRunesSerializer | undefined,
storage: PersistentRunesStorage | undefined
): PersistentRunesOptions;
The serializer part of the option are:
serialize
: This function is responsible for converting the original type into a stringdeserialize
: This function is responsible to convert back a string to the original typeThe library have several built-in serializer:
JsonSerializerFactory
: factory to create a JSON based serializerJsonSerializer
: A basic JSON serializer (no replacer, nor reviver)DevalueSerializerFactory
: factory to create a Devalue based serializerDevalueSerializer
: A basic Devalue serializer (no reducers, nor revivers)ESSerializerSerializerFactory
: factory to create a ESSerializer based serializerESSerializerSerializer
: A basic ESSerializer serializer (no SerializeOptions, nor classes)MacfjaSerializerFactory
: factory to create a @macfja/serializer based serializerMacfjaSerializer
: A basic @macfja/serializer serializer (no additional classes mapping)SuperJsonSerializer
: A superjson serializerNextJsonSerializerFactory
: factory to create a next-json based serializerNextJsonSerializerFactory
: A basic next-json serializer (no options, nor replacers, nor revivers)The storage part of the option are:
storageWrite
: This function is responsible to write data into the storagestorageRead
: This function is responsible to read data from the storageThe library have several built-in storage:
BrowserCookieStorageFactory
: factory to create a Cookie based storage (DOM API, browser only)BrowserCookieStorage
: A basic Cookie storage (no particular options, except for samesite: Strict
)BrowserLocalStorage
: a browser localStorage storage (DOM API, browser only)BrowserSessionStorage
: a browser sessionStorage storage (DOM API, browser only)addEncryptionStorage
: a wrapper function to add AES GCM encryption on stored data<script>
import "@macfja/svelte-persistent-runes"
import { buildOptions, MacfjaSerializer, BrowserSessionStorage } "@macfja/svelte-persistent-runes/options"
let count = $persist(0, 'counter', buildOptions(MacfjaSerializer, BrowserSessionStorage));
</script>
<div class="counter">
<button onclick={() => (count -= 1)} aria-label="Decrease the counter by one">-</button>
<div><strong>{count}</strong></div>
<button onclick={() => (count += 1)} aria-label="Increase the counter by one">+</button>
</div>
<script>
import "@macfja/svelte-persistent-runes"
import { buildOptions, SuperJsnoSerializer, BrowserLocalStorage, addEncryptionStorage } "@macfja/svelte-persistent-runes/options"
let count = $persist(0, 'counter', buildOptions(SuperJsnoSerializer, addEncryptionStorage(BrowserLocalStorage, '12345678901234567890123456879012'));
</script>
<div class="counter">
<button onclick={() => (count -= 1)} aria-label="Decrease the counter by one">-</button>
<div><strong>{count}</strong></div>
<button onclick={() => (count += 1)} aria-label="Increase the counter by one">+</button>
</div>