Currently, there are two primary design patterns for web applications: multipage applications (MPAs) and single-page applications (SPAs). These patterns exhibit notable distinctions in their lifecycles.
In the case of MPAs, the entire page undergoes reloading whenever there is a request for new data. On the other hand, SPAs load all static files during the initial load and subsequently update the view with fetched data, without the need to reload the entire page.
Single-page applications (SPAs) are typically faster compared to multipage approaches and greatly enhance the user experience (UX). However, the dynamic nature of SPAs also presents a drawback. Since the application state is not tied to the URL, it becomes difficult to restore the same view when the page is reloaded.
In this blog, we will explore the process of building a single-page application using Svelte and incorporate a routing mechanism using svelte-spa-router.
Why use svelte-spa-router?
The svelte-spa-router utilizes hash-based paths, which means that the application views are stored within the URL fragment starting with the hash symbol (#).
For instance, if the SPA is contained in the App.svelte file, accessing the URL https://mywebsite.com/#/profile would display the user profile.
The fragment preceded by the hash (#/profile) is not sent to the server, eliminating the need for a backend server to process the request. On the other hand, traditional routes like /profile always require a server.
Svelte-spa-router is user-friendly, well-supported across modern browsers, and optimized for single-page applications due to its hash-based routing mechanism.
Setting up the Svelte app
We will use the official template of Svelte to scaffold a sample application via degit. Open your terminal and run the following command:
npx degit sveltejs/template svelte-spa-router-app
Next, modify your present working directory to the recently formed folder by executing the command cd svelte-spa-router-app. Proceed to install all the necessary packages by executing npm install.
Once the packages have been installed, initiate the development server by running npm run dev.
By default, Svelte applications run on port 5000. Therefore, open your browser and visit localhost:5000, where you should be able to observe the newly generated application.

For our router, we will utilize the svelte-spa-router package, which has an unpacked size of 60.9KB. To install it, simply execute the following command: npm install svelte-spa-router.
Additionally, we require a few small npm helper packages: url-slug, used for generating article URLs, and timeago.js, which aids in calculating the time elapsed since the articles were published.
To install both packages simultaneously, run the following command:
npm install url-slug timeago.js.
Creating components
Afterward, generate a fresh directory named “components” in the main project folder and insert distinct files within it: Card.svelte, Home.svelte, Article.svelte, and NotFound.svelte.
Access the Card.svelte file and incorporate the subsequent code snippet:
<script>
import { link } from "svelte-spa-router";
import urlSlug from "url-slug";
export let title, description, image, publishDate;
</script>
<div class="wrapper">
<a href={image} target="_blank">
<img src={image} alt="img" >
</a>
<div>
<h2 class="title"><a href={`/article/${urlSlug(title)}`} use:link>{title}</a></h2>
<p class="description">{description.substring(0, 180)}...</p>
<p>Published: {publishDate}</p>
</div>
</div>
<style>
.wrapper {
display: grid;
grid-template-columns: repeat(2, auto);
gap: 20px;
padding: 20px 0;
}
.title,
.description {
margin: 0 0 10px 0;
}
img {
border-radius: 5px;
max-width: 230px;
cursor: pointer;
}
@media only screen and (max-width: 600px) {
.wrapper {
grid-template-columns: 1fr;
}
img {
max-width: 100%;
}
}
</style>
The Card component is responsible for showcasing the articles within the landing section. To achieve this, we imported the required helper functions and exported the props (title, description, image, and publishDate) to be passed into the component when used within the app.
Next, we designed a layout for the card with two columns. The left column displays the cover image, while the right column contains the title, description, and publish date. We applied padding to the card and created a gap between the two columns to enhance the visual presentation.
Next, open Home.svelte
and include the following code:
<script>
import urlSlug from "url-slug";
import { format } from "timeago.js";
import Card from "./Card.svelte";
import { blogs } from "../data.js";
</script>
<h1>All your traveling tips in one place</h1>
{#each blogs as blog, i}
<Card title={blog.title} description={blog.content} image={blog.image} publishDate={format(blog.publishDate)}/>
{/each}
Now, open the file Article.svelte
and include the following code:
<script>
import urlSlug from "url-slug";
import { format } from "timeago.js";
import { blogs } from "../data.js";
import NotFound from "../components/NotFound.svelte";
export let params = {};
let article;
blogs.forEach((blog, index) => {
if (params.title === urlSlug(blog.title)) {
article = blog;
}
});
</script>
{#if article}
<div>
<h1>{article.title}</h1>
<p>Published: {format(article.publishDate)}</p>
<img src={article.image} alt="img">
<p>{article.content}</p>
</div>
{:else}
<NotFound/>
{/if}
<style>
img {
max-width: 100%;
}
p {
text-align: justify;
}
</style>
Finally, open NotFound.svelte
and include the following code:
<script>
import { link } from "svelte-spa-router";
</script>
<h1>We are sorry!</h1>
<p>The travel tips you are looking for do not exist.</p>
<img src="https://picsum.photos/id/685/800/400" alt="img">
<p>We still have other travel tips you might be interested in!</p>
<a href="/" use:link>
<h2>Take me home →</h2>
</a>
<style>
img {
width: 100%;
}
</style>
We will use the NotFound
component for all the routes that are not defined. For example, if someone tries to visit article/aa-bb-cc-dd
, the user will see the NotFound
view.
Creating the routing file in svelte-spa-router
In the svelte-spa-router library, routes are defined as objects that consist of keys representing the routes and values representing the corresponding components. Our intention is to create a router that covers various use cases, including direct routes, routes with parameters, and wildcards to handle remaining routes.
For direct routes, the syntax is /path. In this tutorial, we will keep it simple and use a single direct route, “/”, which will serve as the homepage. However, you can include as many direct routes as needed, such as /about, /contact, and more, based on your requirements.
To include specific parameters in your views and retrieve data accordingly, the syntax is /path/:parameter. In our application, we will utilize parameters to load the appropriate content for the article view, using the route /article/:title. It’s even possible to chain multiple parameters, such as /article/:date/:author.
Lastly, wildcards can be used to manage all routes. We will employ a wildcard “”, which will capture all non-existent routes and display a NotFound view to the user. Additionally, you can also include wildcards within the paths of defined routes, for example, /article/.
Now, let’s create a separate routes.js
file in the project root, import the components, and assign them to the routes:
import Home from "./components/Home.svelte";
import Article from "./components/Article.svelte";
import NotFound from "./components/NotFound.svelte";
export const routes = {
"/": Home,
"/article/:title": Article,
"*": NotFound
};
Using the Svelte router in the app
Open App.svelte
in the src
folder and include the following code:
<script>
import Router, { link } from "svelte-spa-router";
import { routes } from "./routes.js";
</script>
<main>
<h3><a href="/" use:link>TravelTheWorld.com</a></h3>
<Router {routes}/>
</main>
<style>
@import url("https://fonts.googleapis.com/css2?family=Montserrat&display=swap");
:global(body) {
margin: 0;
padding: 20px;
}
:global(a) {
text-decoration: none;
color: #551a8b;
}
main {
max-width: 800px;
margin: 0 auto;
font-family: "Montserrat", sans-serif;
}
</style>
Conclusion
In this blog post, we have gained knowledge about essential routing functionalities required for single-page applications. These include creating static routes, establishing routes with parameters, and implementing wildcards to handle non-existent routes.
To enhance the application, you have the option to incorporate additional components and assign them to new routes. If your intention is to scale the application, it is advisable to consider utilizing a content management system (CMS) or a separate database and authentication system.
Finally, for more such posts, please follow our LinkedIn page- FrontEnd Competency.