@route-weaver/svelte
Version:
Svelte stores for @route-weaver/core
200 lines (142 loc) • 5.96 kB
Markdown
# @route-weaver/svelte
[](https://badge.fury.io/js/%40route-weaver%2Fsvelte)
[](https://opensource.org/licenses/MIT)
The official Svelte integration for `route-weaver`. It exposes a set of reactive Svelte Stores that make it effortless to work with navigation data in your Svelte components with full typesafety.
## Why @route-weaver/svelte?
Svelte's simplicity is one of its greatest strengths, but when it comes to routing, developers often find themselves wrestling with string-based URLs, which are prone to typos and become a nightmare to refactor. `@route-weaver/svelte` solves this by bringing full typesafety to your routing, eliminating a whole class of common bugs and making your code more robust and maintainable. Say goodbye to broken links after a route change and hello to a development experience where your editor helps you write correct code.
## Installation
```bash
npm install @route-weaver/core @route-weaver/svelte
```
## Setup
Create a central file to initialize your stores. This keeps your routing logic organized and easy to import.
```typescript
// src/lib/routing.ts
import { createRouteWeaver } from '@route-weaver/core';
import { createRouteWeaverStores } from '@route-weaver/svelte';
const routeWeaver = createRouteWeaver({
home: { label: 'Home', path: '/' },
users: {
label: 'Users',
path: 'users',
children: {
view: { label: 'View User', path: ':id' },
},
},
});
const navInstance = routeWeaver.build({
main: ['home', 'users'],
});
export const {
navigation,
activeRoute,
breadcrumbs,
buildPath,
pathname,
} = createRouteWeaverStores(navInstance, routeWeaver);
```
In your main layout (`+layout.svelte`), keep the `pathname` store in sync with the page URL.
```svelte
<!-- src/routes/+layout.svelte -->
<script lang="ts">
import { page } from '$app/stores';
import { pathname } from '$lib/routing';
$: pathname.set($page.url.pathname);
</script>
<slot />
```
## Expanded API Reference
### `navigation`
* **Type**: `Readable<StructuredNavigation>`
* **Why and When to Use**: This store holds your entire navigation structure. Use its `get(groupName)` method to retrieve a specific navigation group for rendering menus or link lists.
* **Practical Example**:
```svelte
<script lang="ts">
import { navigation } from '$lib/routing';
const mainNav = navigation.get('main');
</script>
<nav>
{#each $mainNav as item}
<a href={item.fullPath}>{item.label}</a>
{/each}
</nav>
```
---
### `activeRoute`
* **Type**: `Readable<ActiveRoute | undefined>`
* **Why and When to Use**: A derived store that automatically updates to reflect the current route. Use it to display route-specific information, like a page title, or to access URL parameters.
* **Practical Example**:
```svelte
<script lang="ts">
import { activeRoute } from '$lib/routing';
</script>
{#if $activeRoute}
<h1>{$activeRoute.route.label}</h1>
{#if $activeRoute.params.id}
<p>Viewing user with ID: {$activeRoute.params.id}</p>
{/if}
{/if}
```
---
### `breadcrumbs`
* **Type**: `Readable<StructuredNavItem[]>`
* **Why and When to Use**: A derived store that provides a breadcrumb trail for the current route. Essential for building breadcrumb components that help with site navigation.
* **Practical Example**:
```svelte
<script lang="ts">
import { breadcrumbs } from '$lib/routing';
</script>
<nav>
{#each $breadcrumbs as crumb, i}
<a href={crumb.fullPath}>{crumb.label}</a>
{#if i < $breadcrumbs.length - 1}
<span> > </span>
{/if}
{/each}
</nav>
```
---
### `buildPath`
* **Type**: `Readable<function>`
* **Why and When to Use**: The core of typesafe link generation. This store holds the `buildPath` function. Always use this to create URLs to ensure they are valid and include the correct parameters, preventing 404 errors.
* **Practical Example**:
```svelte
<script lang="ts">
import { buildPath } from '$lib/routing';
const userProfileUrl = $buildPath('users.view', { id: '123' });
</script>
<a href={userProfileUrl}>View Profile</a>
```
---
### `pathname`
* **Type**: `Writable<string>`
* **Why and When to Use**: This writable store drives the reactivity of `activeRoute` and `breadcrumbs`. You must update it whenever the URL changes, typically in your root layout file by subscribing to SvelteKit's `page` store.
## Before and After: The Typesafety Advantage
### Before: The Wild West of String-Based Links
```svelte
<!-- This is not typesafe and will break silently if the route ever changes. -->
<a href="/users/123">View Profile</a>
```
This is a recipe for 404 errors. It's easy to make a typo, and there's no protection against refactoring mistakes.
### After: Compile-Time Confidence with Svelte Stores
```svelte
<script lang="ts">
import { buildPath } from '$lib/routing';
// ✅ Correct: Autocompletion for 'users.view' and 'id'.
const profilePath = $buildPath('users.view', { id: '123' });
// ❌ Compile-Time Error: 'userId' is not a valid parameter.
// const invalidPath = $buildPath('users.view', { userId: '123' });
// ❌ Compile-Time Error: 'post' is not a defined route.
// const nonExistentPath = $buildPath('post', { id: '123' });
</script>
<a href={profilePath}>View Profile</a>
```
If you change a route definition, your Svelte components will immediately show TypeScript errors.
## Live Examples
Explore interactive examples on CodeSandbox to see `@route-weaver/svelte` in action.
* **SvelteKit Setup**: [Link to CodeSandbox](https://codesandbox.io/p/sandbox/route-weaver-svelte-example-h4q9f8)
* **Client-Side Routing**: [Link to StackBlitz] (coming soon)
## Contributing
Contributions are welcome! Please see the main [CONTRIBUTING.md](../../CONTRIBUTING.md) file for more information.
## License
MIT