Create the Perfect Sharable Rune in Svelte
Tags: svelte, sveltekit, webdev
Published: 2023-09-25 04:46:56


## Singleton Server Issue
When Svelte 5 comes out soon, it seems Runes (Signals) will share one of the old problems Stores had: it could be dangerous to share the signal on the server. I want get into the details here, but you can read [The Correct Way to Use Stores in SvelteKit](https://dev.to/jdgamble555/the-correct-way-to-use-stores-in-sveltekit-3h6i). 

Basically, you need to [use context](https://kit.svelte.dev/docs/state-management#using-stores-with-context) when handling shared stores in an outside script file. Otherwise your data could be seen by other users on the server, instead of just shared across one user.

## Get and Set

However, as [Fireship](https://x.com/fireship_dev/status/1704879390000369689?s=20) pointed out, there is another pain issue with runes. You have to use `get` and `set`, along with a `value` method, which is different from just using `$state`.

Let's say I want to do this:
### app.svelte
```js
<script>
let count = $state(0)
count++
</script>

<button type="button" on:click={() => count++}>
  Increment
</button>

<p>Count {count}</p>
```
[Demo](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAACj2OQQrCMBBFrxIGFy0KdV2SgrjyDMZFTacQTCchmQoSenfTVlz-x_t_JsNoHSZo7xmonxBauIQAJ-BPWEN6o2MsOfk5mpVokslEG7jT5JCF8TOxUOKQuGeszrWmDR2PxWz-qnzOzJ7Euqs07EmD8NQaZ81L5aoWqhO_7tLdyESckFg2u7yOhO66ncubtsgmFFq-m_xgR4sDtBxnXB7LF2buzObYAAAA)
___
No problem, as the count will work as expected. You can't set a value on a variable, as JavaScript will just end up reassigning it.  Svelte actually compiles to use methods under the hood (see JS Output tab). Therefore, trying to change how this works after compilation will require an actual method: `value`. This is exactly how [SolidJS Signals](https://www.solidjs.com/docs/latest), [Angular Signals](https://angular.io/guide/signals#angular-signals), [Qwik Signals](https://qwik.builder.io/docs/components/state/), [Preact Signals](https://preactjs.com/guide/v10/signals/), and [Vue Ref](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#ref) work normally; there is a `value` method.

Rich Harris had a [response to Fireship](https://www.youtube.com/watch?v=NR8L5m73dtE&t=1s), although I'm not really sure he solved [the problem](https://github.com/sveltejs/svelte/issues?q=is%3Aissue+is%3Aopen+rune). You still need to create the `get` and `set`, and return an object:

### app.svelte
```js
<script>
	import { count } from './rune.js'
	import Child from './Child.svelte'

	count.value++
	
</script>

<button type="button" on:click={() => count.value++}>
	Increment
</button>
<h1>Hello from Parent: {count.value}</h1>
<Child />
```
### rune.js
```js
let _rune = $state(0)

export const count = {
	get value() {
		return _rune
	},
	set value(newVal) {
		_rune = newVal
	}
}
```
### child.svelte
```js
<script>
	import { count } from './rune.js'

	count.value++
	
</script>

<h1>Hello from Child: {count.value}</h1>
```
[Demo](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAACq2ST0vDQBDFv8qyCG1pSfQakoJ40ZsnL65I3Ezt1s1s2J1UJeS7u380bVHEg5fADL95--ZNBr5RGhwv7geOdQu84Jddx1ec3rtQuD1oAl8701sZOqWTVnW0FihItZ2xxAYmTY_ERraxpmWzLLc9QrZzsyPoaqt0MwGxypJ6oDwXNbJ9rXtYLkNDYJkfHsPyqScyyIKzSvBUCc4MFlIr-VIN8wWr1uxEZ4w-b1BaaAGjZBr0_XJ7sb4GrU1ydVtbTxRsOBIYy9xDHk3u82jEp9GaRm0UNLwg66nVFF5Y_JDezh0np4HYYwBYxc4c1QTz80UQhLeYkDTo6DPKig3B-LMfiUb8arEhyAL1FpNQ6Iyr8HUTiPB6V-sJ_3owteOAwPH3JeKy__kP_OW6p8eIFn6-xXfnD-MH1LkG-scCAAA=)
___
But, as you probably don't immediately see, this will cause problems with sharing state on the server.

So... I propose a solution to both. Create a reusable component that can be shared *safely* on the server.

### app.svelte
```js
<script>
	import { rune } from './rune.js'
	import Child from './Child.svelte'

	let count = rune(0)

	count.value++
	
</script>

<button type="button" on:click={() => count.value++}>
	Increment
</button>
<h1>Hello from Parent: {count.value}</h1>
<Child />

```
### rune.js (reusable wrapper)
```js
import { getContext, hasContext, setContext } from "svelte"

export const rune = (
	startValue, 
	context = 'default'
) => {
	if (hasContext(context)) {
		return getContext(context)
	}
	let _state = $state(startValue)
	const _rune = {
		get value() {
			return _state
		},
		set value(v) {
			_state = v
		}
	}
	setContext(context, _rune)
	return _rune
}
```
### child.svelte
```js
<script>
	import { rune } from './rune.js'

	let count = rune()

	count.value++
	
</script>

<h1>Hello from Child: {count.value}</h1>
```
[Demo](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAACq1TTWvDMAz9K8IMmtDQsh1DUhi9bLeddplHyVJnTefYwVZKR8h_nz9SN6Vl7LBTLPn56elJ6UlVc6ZJ-tYTUTSMpOSxbUlC8Lu1gT4wjszEWnaqtJlMl6pucUUFxbpppULoQXWCwQCVkg3MFksbLvZ6NsGsdzXfBoCLFp7cogyOM4RSdgIhd3TRQ-wvXHJxKHjH5nOboCJbnkWI7KNDlAKs4pwSH1ECUqQlr8uvvI9iyFdwwTM4_c-iVKxhwlH6hyaf7e5XT4xz6eW-FMogUugnBEO2NCAD9W0tnRDjUiO3dVWzLUlRGVQSTLUdnV3d66mjwcVPhmspkB0xgV2hw1mH_MljOg6GEluYHR1BKYVGP4ocItufxkLhqxWcgLfSs-Qw27Kq6Dga8505vRtVBdG5bjSi49jfUlQMOyUmMgPE3g-nKW5MWbQa7twhOquIRxFG5mbUOVIbTnDORqFaqOf5fHJI_FcH_GHyIFQ-jOigS19pTrwEJ-lUyCaoGH4fpRv5P_4ht3b_r6t_ualO2e1FvW7offgB2UUbYPwDAAA=)
___
Now, if Rich Harris put this into the Svelte *core code* so that you didn't have to use `value` (just like `$state`), and it worked as expected compiling to js... that would be great... maybe a `$rune()`.

¯\\_(ツ)_/¯

Notice the second (optional) argument is needed for different runes you want to share (the name of your context). This would allow you to have more than one, and use it as you see fit. This would solve the problem SvelteKit never solved with stores.

## TypeScript and Final Thoughts
Svelte Team, if you're reading this, PLEASE PLEASE add a TypeScript version of [REPL](https://svelte.dev/repl/hello-world?version=4.2.1). This was paintful to write. Even Rich Harris finally mentioned the need for this on the Runes intro video. There are 1,222 questions alone on [StackOverflow](https://stackoverflow.com/search?q=svelte+typescript) regarding Typescript with Svelte. This would save developers time, easily sharing correctly typed code. Until then, we can use [SvelteLab](https://www.sveltelab.dev/?t=typescript), although not with Runes... yet.

Runes will be a gamechanger, as everyone agrees... just not quite on the implementation.

J

Currently finishing rebuild of [code.build](https://code.build)