Simple Svelte 3 app with router

Minh Turi
Minh Turi
Aug 14, 2019 · 5 min read

INTRODUCTION

Svelte is concise, elegant framework that makes you feel quite fresh over React and Vue. There is the video that the author Rich Harris spoke really well at Codecamp Iasi 2019.

[UPDATED 03/10/2019] I’ve refactored the code a bit so the structure of the project is neater. If you want to integrate my ready solution into your project to create SPA with some pages, you just need to copy 3 files: <Link>, <Route>, store/index.js and config the path in file router.js and change <App> a bit. The main idea is still the same so you can still follow this article enjoy the technical concept behind the scene. Give me a star on github if you like or use this project. Thanks :)

Svelte team has been working on other project called Sapper though it isn’t ready. Quote from main page:

Sapper, our Next.js-style app framework, is still in the middle of being updated to use Svelte 3.

and this

But in the meantime we think Svelte 3 is the best way to build web apps yet

So I decided to jump right into the Svelte template and start fooling around. You can easily use the template here.

Because there is no Svelte router built-in so I make this tutorial to educate myself mostly and hopefully others can find it helpful since Svelte is quite new in the front-end community.

It is inspired by Vue router and this great article How I Implemented my own SPA Routing System in Vanilla JS — Medium

IMPLEMENTATION

I will assume that you guys did some basic tutorials in Svelte main page (very well-written) and of course take them as references for this implementation.

The app is deadly simple with 2 pages: Home and About

Well, it behaves like you guess, click to link Home and you will be directed to Home page, click to link About and it will show About page.

There are 3 pieces of technology/concept that you should understand in order to create this router effect. You will see why we need them soon.

  • Web Browser History API: help the browser manipulate the history stack -> change url on current window, change url of history window in the history stack.
  • Store: as a single source of truth for Svelte 3 app -> used for identify which Page should be presented now.
  • <svelte:component />: allow you to assign name of component to a variable

So the idea is fairly simple: the app has a preserved div that will update the appropriate Page (Svelte component) based on current active link. That means if you click on link Home, content inside div#pageContent will be replaced by Home Component. On the other hand if you click on link About, content inside div#pageContent will be replaced by About Component.

~/ App.svelte (Root Component)<div id="pageContent"><!-- Page component updates here --></div>

I first created Home Component with a title: This is Home page and a clock to keep track how long the component has been launched.

~/ Home.svelte<script>import { onDestroy } from 'svelte';let seconds = 0;const interval = setInterval(() => {seconds = seconds + 1;}, 1000)onDestroy(() => {clearInterval(interval);})</script><style>h1 {color: purple;}</style><h1>This is Home page</h1><p>It's been running for {seconds} seconds</p>

and then About Component with only a title: This is About page

~/ About.svelte
<script>
</script>
<style>h1 {color: purple;}</style>
<h1>This is About page</h1>

Now, step 2 is creating router.js file as router index for the app.

~/ router.js
import Home from './Home.svelte';
import About from './About.svelte';import { writable } from 'svelte/store';const router = {'/': Home,'/home': Home,'/about': About}export default router;export const curRoute = writable('/home');

Forget the 3rd and final line of code for now, we have the router variable that is ready to be plugged in App.svelte (the Root Component).

Since the router links are plurals, I’m gonna create reusable RouterLink Component. It should be able to receive pathURL and corresponding Component through props. In this case the prop is page (a bit strange the way Svelte defines export as keyword for prop though it’s fairly short and easy to remember :)).

~/ RouterLink.svelte
<script>
import { curRoute } from './router.js';export let page = {path: '/home',name: 'Home'}function redirectTo(event){ // change current router path curRoute.set(event.target.pathname); // push the path into web browser history API window.history.pushState({path: page.path}, '', window.location.origin + page.path);}</script><style>a {text-transform: uppercase;text-decoration: underline;padding: 1rem;}</style>
<a href={page.path} on:click|preventDefault={redirectTo}>{page.name}</a>

In order to announce to App.svelte (Root Component) which pathURL and Page Component should be updated within dedicated div area, we can choose either to emit an event or use a store (imagine it as a single source of truth that any Svelte Component can subscribe and either access to the variable or even update it). Surprised by how simple store looks compared to Redux or Vuex, I choose the 2nd solution. If you look back to router.js file, you will see how a store variable curRoute is defined.

RouterLink.svelte now can import the store variable and update it every time user click on the link, it will immediately update at any Component subscribing curRoute variable.

Before update Root Component to fulfil the task you might notice besides setting new value to curRoute, there is another line of code for Web Browser History API. The reason we need it is that we are trying to mimic the behaviour as if with traditional dynamic web: if user click on the link, the address bar should change as well. And Web Browser History API is born for this task, by push new state, it will update the address bar and the history stack as well. History stack will help you navigate back and forth expectedly.

Ok, almost there, we just need to update App.svelte for an end.

<script>import router, { curRoute } from './router.js';import RouterLink from './RouterLink.svelte';import { onMount } from 'svelte';onMount(() => {  curRoute.set(window.location.pathname);  if (!history.state) {    window.history.replaceState({path: window.location.pathname}, '',   window.location.href)  }})function handlerBackNavigation(event){  curRoute.set(event.state.path)}</script><style></style><svelte:window on:popstate={handlerBackNavigation} /><RouterLink page={{path: '/home', name: 'Home'}} /><RouterLink page={{path: '/about', name: 'About'}} /><div id="pageContent"><!-- Page component updates here --><svelte:component this={router[$curRoute]} /></div>

Main important updates are 2 RouterLink Component for 2 pages and <svelte:component />. Well, just think that <svelte:component /> is helping us mount Svelte Components dynamically instead of writing down explicitly them, no more than that. The onMount and <svelte:window on:popstate={handlerBackNavigation} /> are just used for fixing navigation behaviour properly.

And that’s it :).

Well, this is my first ever Medium post. Hope you can learn something from it and sorry for my unprofessional writing at the moment ;). You can check the source code here on github. Cheer!

The Startup

Get smarter at building your thing. Join The Startup’s +792K followers.

Sign up for Top 10 Stories

By The Startup

Get smarter at building your thing. Subscribe to receive The Startup's top 10 most read stories — delivered straight into your inbox, once a week. Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Minh Turi

Written by

Minh Turi

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +792K followers.

Minh Turi

Written by

Minh Turi

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +792K followers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store