Home

Awesome

Svelte Router

Simple Svelte Router for Single Page Applications (SPA), inspired by Vue Router. Features include:

To see the details code documentation, please read the Code Documentation.

Notice

This project is not being actively maintained by the author of package. Any community contribution would be more than welcomed keep this project alive.

Quick Links

Table of Content

Installation via NPM or Yarn

npm install -D @spaceavocado/svelte-router
yarn add @spaceavocado/svelte-router -D

Webpack Setup

Please see the Svelte Webpack Template. Important setup in the webpack.config.js:

resolve: {
  // This alias is important to prevent svelte mismatch
  // between your code, and the 3rd party components.
  alias: {
    svelte: path.resolve('node_modules', 'svelte')
  },
  extensions: ['.mjs', '.js', '.svelte'],
  mainFields: ['svelte', 'browser', 'module', 'main']
},

module: {
  rules: [
    {
      test: /\.svelte$/,
      // Do not exclude: /(node_modules)/ since the router 
      // components are located in the node_modules
      use: {
        loader: 'svelte-loader',
        options: {
          emitCss: true,
          hotReload: true
        }
      }
    }
  ]
}

Webpack Boilerplate Project Template

For a quick start, you can use svelte-router-template - Webpack boilerplate template project for spaceavocado/svelte-router.

Live Preview.

Rollup Setup

rollup.config.js:

import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import svelte from 'rollup-plugin-svelte';

export default {
  input: './src/index.js',
  output: {
    file: './dist/bundle.js',
    format: 'iife'
  },
  plugins: [
    resolve(),
    commonjs({
      include: 'node_modules/**',
    }),
    svelte(),
    babel({
      exclude: 'node_modules/**',
    }),
  ]
}

Essentials

Note: All code below uses ES2015+.

Setup the Router

All we need to do is map our components to the routes and add root RouterView component, here's a basic example of app component uses as the main Svelte component.

index.js:

// The base component
import App from './app.svelte';

// Turn on the engine
new App({
  target: document.body,
});

app.svelve:

<script>
import createRouter from '@spaceavocado/svelte-router';
import RouterView from '@spaceavocado/svelte-router/component/view';

// View components
import ViewHome from './views/home.svelte';
import View404 from './views/404.svelte';

createRouter({
  routes: [
    { 
      path: '/',
      name: 'HOME',
      component: ViewHome,
    },
    {
      path: '*',
      component: View404,
    },
  ],
});
</script>

<RouterView />

This is an example of the minimalist plug & play setup of the Svelte Router. For more details:

Route Configuration

A route can be configure with these properties:

PropertyDescriptionType
pathA string that equals the path of the current route, always resolved as an absolute path. e.g. "/foo/bar". Please see Dynamic Route Configuration for advanced usage.string
redirectRedirection to different route, or to external site. Please see Route Redirection for advanced usage.boolean, object, function
nameThe name of the current route, optional.string
componentSvelte component. It could be be omitted if the route has nested routes.function
metaRoute meta object, meta is used a bucket for your custom data on route object.object
propsDeclaration of component properties passed to the component by the route. Please see Passing Props to Route Components for more details.boolean, object, function
childrenCollection of children/nested routes. Please see Nested Routes for more details.object[]
createRouter({
  routes: [
    { 
      path: '/',
      name: 'HOME',
      component: ViewHome,
      meta: {
        static: 5,
        dynamic: () => {return 5;},
      }
    },
    { 
      path: '/services',
      name: 'SERVICES',
      children: [
        { 
          path: '/',
          name: 'SERVICES_HOME',
          component: ViewServices,
        },
        { 
          path: '/design',
          name: 'SERVICES_DESIGN',
          component: ViewServicesDesign,
          props: {
            title: 'Services / Design',
          }
        }
      ]
    },
    { 
      path: '/users/:id(\\d+)',
      name: 'USER_PROFILE',
      component: ViewUserProfile,
      props: (route) => {
        return {
          userId: route.params.id,
        };
      },
    }
  ],
});

Dynamic Route Configuration

Route Redirection

To redirect a route, you can configure it like so:

// Redirect from /a to /b
{ 
  path: '/a',
  redirect: '/b',
}

// External site redirect
// Must start with 'http' or 'https'
{ 
  path: '/a',
  redirect: 'https://github.com/spaceavocado/svelte-router',
}

// Redirect to named route
{ 
  path: '/a',
  redirect: {
    name: 'ROUTE_NAME',
  },
}

// Dynamic redirecting
// "to" is Route Object
// Return value must be URL or a Route.
{ 
  path: '/a',
  redirect: (to) => {
    return {
      name: 'ROUTE_NAME',
    }
  },
}

Please see Route Object for more details.

Passing Props to Route Components

By default, props are not automatically passed to the route component, this could be change to:

Automatically Pass Route Params as Component Props

All route dynamic props are auto-passed to the component.

// app.svelte
{ 
  path: '/users/:id(\\d+)',
  name: 'USER_PROFILE',
  component: ViewUserProfile,
  props: true,
}

// ViewUserProfile.svelte
export let id;

Pass Custom Object as Component Props

// app.svelte
{ 
  path: '/',
  name: 'HOME',
  component: ViewHome,
  props: {
    title: 'Hello World',
  },
}

// ViewHome.svelte
export let title;

Use a Function to Resolve the Component Props

Please see Route Object for more details.

// app.svelte
{ 
  path: '/users/:id(\\d+)',
  name: 'USER_PROFILE',
  component: ViewUserProfile,
  props: (route) => {
    return {
      title: 'User Profile',
      id: route.params.id,
    }
  },
}

// ViewUserProfile.svelte
export let title;
export let id;

Auto Passed Route Prop

Route property of type Route Object is auto-passed to the route component.

component.svelte:

<script>
export let route;
</script>

Nested Routes

Router Link Component

<script>
import RouterLink from '@spaceavocado/svelte-router/component/link';

<!-- URL -->
<RouterLink to='/services/design'>Navigate by URL</RouterLink>

<!-- Location Object -->
<RouterLink to={{name: 'USER_DETAIL', params:{id: 5}}>Navigate by Location</RouterLink>

The route link is the base component for routing action. The route link renders a < a > DOM element with click action triggering route change. The active class is auto-resolved. Component parameters:

PropertyDescriptionType
tonavigation URL or navigation Location, please see Location Object for more details.string, Location
replaceReplace rather the than push into the history, defaults to false.boolean
exactThe default active class matching behavior is inclusive match, i.e. it matches if the URL starts with link url. In the exact mode, the url must be be the same (excluding query param and hash param). Defaults to false.boolean
clsLink base class name, defaults to ''.string
activeClassLink active class name, if not defined, it defaults to the active class defined on the router.string
disabledDisable navigation action, and set "disabled" css class. Defaults to false.boolean

Router Link Events

<script>
import RouterLink from '@spaceavocado/svelte-router/component/link';

// Navigation has been completed
function handleOnCompleted() {}

// Navigation has been aborted
function handleOnAborted() {}
</script>

<RouterLink to='/services/design' on:completed={handleOnCompleted} on:aborted={handleOnAborted}>Navigate by URL</RouterLink>

Router View Component

<script>
import RouterView from '@spaceavocado/svelte-router/component/view';
</script>

<RouterView />

Advanced

Programmatic Navigation

Besides the Router Link Component, the route could be changed like so:

import {router} from '@spaceavocado/svelte-router';

// URL
$router.push('/services/design');

// Location Object
$router.push({
  name: 'USER_DETAIL',
  params: {
    id: 5,
  },
  query: {
    code: 'system_code',
  },
  hash: 'sidebar',
});

Note: the router can be accessed after the createRouter function is executed, and it must be accessed as $router since it is Svelte read-able store object.

More information:

Navigation Guard

The navigation guards are primarily used to guard navigations either by redirecting it or canceling it.

Create a Navigation Guard

import {router} from '@spaceavocado/svelte-router';

// The guard callback is called when a navigation occurs,
// the next function must be called to continue the navigation.
$router.navigationGuard((from, to, next) => {
  next();
});

Note: the router can be accessed after the createRouter function is executed, and it must be accessed as $router since it is Svelte read-able store object.

"from, to" are Route Object.

Navigation Guard Next Action

Continue
next();

Move on to the next hook in the pipeline. If no hooks are left, the navigation is confirmed.

Abort
next(false);

Abort the current navigation.

Redirect
// URL
next('/services/design');

// Location Object
next({
  name: 'USER_DETAIL',
  params: {
    id: 5,
  },
  query: {
    code: 'system_code',
  },
  hash: 'sidebar',
});

Abort the current navigation and redirect to new navigation.

More information:

Error
next(new Error('internal error'));

Abort the current navigation, and trigger onError event on the router.

More information:

Lazy Loaded Component

View components could be loaded asynchronously, i.e. lazy loading, e.g:

app.svelve

<script>
import createRouter from '@spaceavocado/svelte-router';
import RouterView from '@spaceavocado/svelte-router/component/view';

// View components
import ViewHome from './views/home.svelte';
import View404 from './views/404.svelte';

// Webpack dynamic import
const asyncView = (view) => {
  return new Promise((resolve) => {
    const component = import(/* webpackChunkName: "view-[request]" */ `./view/${view}.svelte`);
    resolve(component);
  });
};

createRouter({
  routes: [
    { 
      path: '/',
      name: 'HOME',
      component: ViewHome,
    },
    {
      path: 'some-page',
      component: asyncView('some-page'),
    }
    {
      path: '*',
      component: View404,
    },
  ],
});
</script>

<RouterView />

Note: To load async component, the load function must return a Promise, and resolve must return a module object:

{
  // The default (default module export function) must the Svelte Component function
  // Please see the webpack example above.
  default: function(){}
}.

API

To see the details code documentation, please read the Code Documentation

Create Router

import createRouter from '@spaceavocado/svelte-router';

// Please see the opts below.
const routerOpts = {};

// Router is Svelte read-able store, therefore it must be
// accessed with $ prefix, e.g. $router.
// To access the router instance in other files, please see "Access Router Instance".
const router = createRouter(routerOpts);

Throws when the route options are invalid.

Router Options

PropertyDescriptionType
modeHistory mode. Supported values: 'HISTORY', 'HASH'.string
basenameThe base URL of the app, defaults to ''.string
hashTypeHash type. Relevant only for HISTORY_MODE.HASH. Supported values: 'PUSH', 'REPLACE'.string
routesrouter routes.object[]
activeClassCSS class applied on the active route link. Defaults to "active".string

Note: History modes could be accessed like so:

import {ROUTER_MODE} from '@spaceavocado/svelte-router';

Note: Hash types could be accessed like so:

import {HASH_TYPE} from '@spaceavocado/svelte-router';

More information:

Access Router Instance

import {router} from '@spaceavocado/svelte-router';

Note: It must be accessed as $router since it is the Svelte read-able store object, to resolved auto subscribe/unsubscribe.

Router Methods

All route methods are accessible on the router, please see Access Router Instance.

start

$router.start();

This method is auto-called by the root Router View Component; it handles the on page load route resolution.

push

Push to navigation.

$router.push(rawLocation, onComplete, onAbort);

Throws when the rawLocation is invalid or when the path is invalid.

Parameters:

NameDescriptionType
rawLocationraw path or location object.string, Location
onCompleteOn complete callback function. Optional.function
onAbortOn abort callback function. Optional.function

replace

Replace in navigation.

$router.replace(rawLocation, onComplete, onAbort);

Throws when the rawLocation is invalid or when the path is invalid.

Parameters:

NameDescriptionType
rawLocationraw path or location object.string, Location
onCompleteOn complete callback function. Optional.function
onAbortOn abort callback function. Optional.function

back

Go one step back in the navigation history.

$router.back();

forward

Go one step forward in the navigation history.

$router.forward();

go

Go to a specific history position in the navigation history.

$router.go(n);

Parameters:

NameDescriptionType
nnumber of steps to forward or backwards (negative number).number

routeURL

Generate route URL from the the raw location.

const url = $router.routeURL(rawLocation);

Parameters:

NameDescriptionType
rawLocationraw location object.Location

navigationGuard

Register a navigation guard which will be called whenever a navigation is triggered. All registered navigation guards are resolved in sequence. Navigation guard must call the next() function to continue the execution of navigation change. Please see Navigation Guard

const unregister = $router.navigationGuard(guard);

// To unregister the navigation guard:
unregister();
unregister = null;

Parameters:

NameDescriptionType
guardguard callback function with (from, to, next) signature. Please see Navigation Guard Next Actionfunction

"from, to" are Route Object.

onBeforeNavigation

Register a callback which will be called before execution of navigation guards.

const unregister = $router.onBeforeNavigation(callback);

// To unregister the event:
unregister();
unregister = null;

Parameters:

NameDescriptionType
callbackcallback function with fn(from, to) signature.function

"from, to" are Route Object.

onNavigationChanged

Register a callback which will be called when all navigation guards are resolved, and the final navigation change is resolved.

const unregister = $router.onNavigationChanged(callback);

// To unregister the event:
unregister();
unregister = null;

Parameters:

NameDescriptionType
callbackcallback function with fn(from, to) signature.function

"from, to" are Route Object.

onError

Register a callback which will be called when an error is caught during a route navigation.

const unregister = $router.onError(callback);

// To unregister the event:
unregister();
unregister = null;

Parameters:

NameDescriptionType
callbackcallback function with fn(error) signature.function

Location Object

PropertyDescriptionType
nameName of the route.string
paramsRoute params dictionary object, if the route has defined dynamic route parameters, this object is required, with valid params to resolve the route URL.object
queryRoute query dictionary object. Optional.object
hashRoute hash parameter. Optional.string
// Location object example
{
  name: 'USER_DETAIL',
  params: {
    id: 5,
  },
  query: {
    code: 'system_code',
  },
  hash: 'sidebar',
}

// Considering that USER_DETAIL is /user/:id(\\d+)
// the resolved URL will be:
// /user/5?code=system_code#sidebar

Route Object

PropertyDescriptionType
namename of the route.string
pathlocation path use to resolve the route.string
hashurl hash.string
fullPaththe full resolved URL including query and hash.string
paramsroute resolved params.object
queryquery parameters.object
metaroute meta.object
actionroute action.string
matchedresolved route records, please see Route Record Object In the case of nested route, it contains all matched routes, starting from root to the deepest route node.object[]

Route Record Object

PropertyDescriptionType
pathlocation path use to resolve the route.string
namename of the route.string
componentsvelte component.string
metaroute meta.string
paramsroute resolved params.string
propsprops passed to component, please see Passing Props to Route Components.boolean, object, function

Changes

To see the changes that were made in a given release, please lookup the tag on the releases page. The full changelog could be seen here changelog.md

About

This project was inspired by Vue Router, designed mainly to explore and test Svelte in SPA realm. Any feedback, contribution to this project is welcomed.

The project is in a beta phase, therefore there might be major changes in near future, the annotation should stay the same, though.

Contributing

When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.

Pull Request Process

  1. Fork it
  2. Create your feature branch (git checkout -b ft/new-feature-name)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin ft/new-feature-name)
  5. Create new Pull Request

Please make an issue first if the change is likely to increase.

License

Svelte Router is released under the MIT license. See LICENSE.txt.