UNPKG

@route-weaver/svelte

Version:
200 lines (142 loc) 5.96 kB
# @route-weaver/svelte [![npm version](https://badge.fury.io/js/%40route-weaver%2Fsvelte.svg)](https://badge.fury.io/js/%40route-weaver%2Fsvelte) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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