Single Page Applications#
Single Page Applications (SPAs) are a modern and popular style of web apps where a single page is served to a user. When a user interacts with an SPA, the single page is dynamically updated with new data and markup without doing a full-page browser refresh to load a different page. This usually gives SPAs a more reactive and user-friendly feel.
A SPA can have multiple routes and URLs, but if you watch closely, you will notice that the browser does not do a full refresh (no loading icon on the tab) when navigating between routes.
Frameworks like Svelte, React and Vue have made building SPAs much easier for developers and their high performance improves the user experience as well.
Even though SPAs are based on a single HTML page, a frontend SPA router can be used to handle different URLs in the browser and mimic the experience of navigating around a web application between (virtual) pages.
Svelte-Router-SPA#
As discussed in the first module, we will have routes for a home page, lunch menu admin pages and a lunch menu display page.
In the next steps, we will configure a route for each of the above pages. Go ahead and install svelte-router-spa
. You can read the documentation at https://github.com/jorgegorka/svelte-router and while you are there, you can also star the repository.
$ npm install svelte-router-spa
Then create a school-lunch/frontend/src/routes.js
file.

In the routes.js
file we import a .svelte
file for each route. When a user navigates to one of our routes, the svelte-spa-router
will handle the request and load the appropriate Svelte file. This happens on the client side and is what differentiates an SPA from a server-side rendered (SSR) application.
Add the following imports and routes to routes.js
:
import Home from './views/public/Home.svelte'
import LunchMenuView from './views/public/LunchMenuView.svelte'
import LunchMenuAdmin from './views/admin/LunchMenuAdmin.svelte'
const routes = [
{ name: '/', component: Home },
{ name: '/lunch-menu', component: LunchMenuView },
{ name: '/admin/manage-menus', component: LunchMenuAdmin },
]
export { routes }
In the above file, we imported three .svelte
files that don't exist yet. We will create those files and directories in the next section.
Svelte Files#
Svelte files, with the extension .svelte
, are used to create components, which are the building blocks of a Svelte application.
A component can be large, such as a whole page or small, such as a date picker or a table. Components can also be made up of other components. We will talk more about components later.
Svelte files are made up of three sections.
The
<script>
section holds all the JavaScript for the component, such as state and event handlers.The
<style>
section holds the CSS styles needed by the component.The main markup section which is where all the HTML markup goes.
During a build, the Svelte framework compiles everything together in a JavaScript bundle. Then when the user loads a page with the bundle, Svelte renders the appropriate components in the user's browser.
Previously, we imported three Svelte files in routes.js
and we organized them under the directories admin and public.
Create those files and directories now under a views
directory in your frontend/src
directory. To create the files you can ctrl + click or right-click on the directory name in VSCode's explorer panel, click New File and name it with the .svelte
extension. Start very simple with just a div
and an h1
element describing the page. For example, the Home.svelte
file should look like this:
<div>
<h1 class="title is-4">Home</h1>
</div>
The project files should look like this now:

At this point, we have set up routes.js
and created the Svelte files for each page, but we haven't wired up the router with the main application file.
Open up App.svelte
and import the Router
component and the routes.js
file and add them to the markup. You can remove the existing boilerplate code from App.svelte
.
<script>
import { Router } from 'svelte-router-spa'
import { routes } from './routes'
</script>
<main>
<Router {routes} />
</main>
Lastly, as per the svelte-router-spa
documentation, we need to change the start script in package.json
from sirv public
to sirv public -s
, like this:
"scripts": {
"build": "npx eslint ./src && vite build",
"dev": "npx eslint ./src && vite",
"start": "sirv public -s"
},
Testing the Router#
Since we updated package.json
, we need to recycle our local dev server. From the command line hit ctrl c
to stop the local frontend development server and then run npm run dev
again to restart it.
Next, open up your browser and navigate to http://localhost:5000/. The SPA router should kick in and you should see the home page from the Home component.

After this, update the browser address bar to http://localhost:5000/admin/manage-menus. Now you should see the LunchMenuAdmin.svelte
component. Test all of the routes in this manner to confirm that routing is set up correctly.

Svelte Dynamic Markup#
Let's cover one more Svelte concept before completing this lesson. Building dynamic HTML with Svelte is accomplished by using curly braces directly in HTML.
Open LunchMenuAdmin.svelte
and add a <script>
section with a myDate
variable. Then use {myDate}
with curly braces to add the variable to the markup. Svelte will handle building the HTML for the browser.
Here's an example that will render a current Unix timestamp from a new Date
object:
<script>
let myDate = new Date().getTime()
</script>
<div>
<h1 class="title is-4">Lunch Menu Administration / {myDate}</h1>
</div>
Test this in the browser and you should see something like the following:

We don't really want a Unix timestamp in our page header, so replace the myDate
variable with a variable called schoolName
. In a future module, we'll turn this simple header into navigational breadcrumbs, but this will suffice for now.
<script>
let schoolName = 'Test School'
</script>
<div>
<h1 class="title is-4">Lunch Menu Administration / {schoolName}</h1>
</div>
Recap#
Great work! We've created a routes.js
file and defined our routes. Each route points to a Svelte file. We also wired up the router and routes in our main App.svelte file.
In the next lesson we will create an AdminLayout
that will be a parent component for all Admin components.