Skip to content

spaceavocado/svelte-router

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Svelte Router

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

  • Nested route/view mapping.
  • Modular, component-based router configuration.
  • Route params, query, wildcards (powered by path-to-regexp).
  • Navigation guards for navigation control.
  • Links with automatic active CSS classes.
  • HTML5 history mode or hash mode (powered by history).

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:

Property Description Type
path A 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
redirect Redirection to different route, or to external site. Please see Route Redirection for advanced usage. boolean, object, function
name The name of the current route, optional. string
component Svelte component. It could be be omitted if the route has nested routes. function
meta Route meta object, meta is used a bucket for your custom data on route object. object
props Declaration of component properties passed to the component by the route. Please see Passing Props to Route Components for more details. boolean, object, function
children Collection 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

  • The route path could contain dynamic parameters, e.g. path: '/users/:id'. Please see path-to-regexp for more information how to configure the name, optional, etc,. parameters.
  • Special case is path: '*' which means any URL, this route should be the last route in your routes definition.
  • All resolved dynamic parameters are accessible on the resolved route object.

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

  • Please see Route Configuration for the base information about the routes configuration.
  • Nested route has access to its own parameters and all parent's route parameters:
    { 
      path: '/users/:id(\\d+)',
      children: [
        {
          path: '/',
          name: 'USER_DETAIL',
          component: ViewUserDetail,
        },
        {
          path: '/message/:msgId(\\d+)',
          name: 'USER_MESSAGE',
          component: ViewUserMessageDetail,
        }
      ],
    },
    {
      path: '/services',
      component: ViewServices,
      children: [
        path: '/design',
        component: ViewServicesDesign,
      ]
    }
    
    // Resolved USER_MESSAGE route will have access to 
    // id, and msgId params.
  • The component could be omitted if the route has nested routes (please see the example above), it this case ViewRouter component will be used to pass through the components, please see Router View for more details.
  • If the route has nested routes, and it has defined component, than the component must internally use Router View component to pass though the routed view components on it's own nested routes.
  • All routes should start with trailing slash.

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:

Property Description Type
to navigation URL or navigation Location, please see Location Object for more details. string, Location
replace Replace rather the than push into the history, defaults to false. boolean
exact The 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
cls Link base class name, defaults to ''. string
activeClass Link active class name, if not defined, it defaults to the active class defined on the router. string
disabled Disable 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 />
  • The route view acts as SLOT for resolved route component, i.e. it will be replaced run-time with the component defined on the given route.
  • For nested routes, if the parent route (the one having nested routes) has defined it's own component, the component must use internally ViewRouter component to pass through the nested route components. If the component is not defined on the parent route, it auto pass through.

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

Property Description Type
mode History mode. Supported values: 'HISTORY', 'HASH'. string
basename The base URL of the app, defaults to ''. string
hashType Hash type. Relevant only for HISTORY_MODE.HASH. Supported values: 'PUSH', 'REPLACE'. string
routes router routes. object[]
activeClass CSS 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:

Name Description Type
rawLocation raw path or location object. string, Location
onComplete On complete callback function. Optional. function
onAbort On 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:

Name Description Type
rawLocation raw path or location object. string, Location
onComplete On complete callback function. Optional. function
onAbort On 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:

Name Description Type
n number of steps to forward or backwards (negative number). number

routeURL

Generate route URL from the the raw location.

const url = $router.routeURL(rawLocation);

Parameters:

Name Description Type
rawLocation raw 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:

Name Description Type
guard guard callback function with (from, to, next) signature. Please see Navigation Guard Next Action function

"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:

Name Description Type
callback callback 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:

Name Description Type
callback callback 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:

Name Description Type
callback callback function with fn(error) signature. function

Location Object

Property Description Type
name Name of the route. string
params Route params dictionary object, if the route has defined dynamic route parameters, this object is required, with valid params to resolve the route URL. object
query Route query dictionary object. Optional. object
hash Route 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

Property Description Type
name name of the route. string
path location path use to resolve the route. string
hash url hash. string
fullPath the full resolved URL including query and hash. string
params route resolved params. object
query query parameters. object
meta route meta. object
action route action. string
matched resolved 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

Property Description Type
path location path use to resolve the route. string
name name of the route. string
component svelte component. string
meta route meta. string
params route resolved params. string
props props 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.