How to Configure Single Page Routing with Svelte and Express.js
By: Lee Mcgowan
Tags: JavaScript, Expressjs, Svelte, Programming, Web Development

How to Configure Single Page Routing with Svelte and Express.js

Learn how to avoid ‘page not found’ errors when using client-side-routing and hot reload

Photo by Oliver Roos on Unsplash

This tutorial is for anyone who creates single-page-apps and wants to know how to configure routing properly on the server side. It will use Svelte as the framework, but the techniques here will work for any app using client side routing.

The Problem

Client-side routing solutions like svelte-routing work great, but they will break if you try to refresh your page when using them, and this means that it’s impossible to use hot reloading. This is because all routing logic is performed on the client, and when you initially load a page, say localhost:5000/home , the client code isn’t yet loaded. This means that your browser will attempt to find the file home.html at localhost:5000 but it won’t be there, because it’s a single page app. It only has index.html .

Here’s an example.

The code above creates a simple Svelte app and uses svelte-routing as the routing solution. It then creates a Route for the Home component and a link to navigate for it. The Home component only returns a p tag that says ‘Hello, this is the homepage’.

When I load up this app, I see the root page.

And when I click Home , I am routed to the Home page.

The problem arises when I attempt to navigate to localhost:5000/home directly, or when I refresh the page. If I do that, I’ll see a blank page, or a Not Found error.

The Solution

To solve this problem, we need a way of intercepting the HTTP calls to localhost:5000 and then redirecting them all back to index.html . When we do this, the server will return the root page, which will load all of our code, and then the routing will kick into action and display the home page.

We can do this by creating an express server to serve our app, so let’s do that.

First, install express, by running npm i express and then create a file, server.js at the root of your project. Add the following boilerplate to create the server.

var express = require('express')

var app = express() app.listen(3000, () => {

console.log("App listening on port 3000")

})

Now, we need to do two things. We need to configure a static directory which will tell express where it can find our html & js files. Then we need to intercept all http calls and route them back to index.html.

The static directory for Svelte will be the public directory because that’s where all of the built files are placed. This is standard so will probably be the same for other frameworks, but obviously make sure you check.

To define a static folder in express, we do this:

app.use(express.static('public'))

So add that to server.js

var express = require('express')

var app = express() app.use(express.static('public')) app.listen(3000, () => {

console.log("App listening on port 3000")

})

Now, if you run your server with node server.js , you should actually see your application loaded in the browser. However, we still haven’t solved the problem.

Now we need to re-write all http calls to index.html . This is straightforward, and looks like the following.

app.get('*', (req, res) => {

res.sendFile(__dirname + "/public/index.html")

})

The asterisk character intercepts all calls, and then we tell the server to return the index.html file from the public folder. We use __dirname to get the fully qualified path.

If you run your server now, you should be able to navigate directly to localhost:5000/home . There is still one problem, though.

Hot Reloading

One of the benefits of this was that it would enable hot reloading. However, now that we aren’t using Svelte’s npm run dev to run our app, we aren’t getting the benefit of that. Currently, we’d need to stop the server, compile the app and restart it again to make hot-reloading work. This is a pain to do manually, but we can automate it relatively easily.

There’s a nice little npm package called concurrently . The last step of our process is to install this with npm i concurrently and then create a script in our package.json to run both our server and our hot-reloading. Here’s how that looks for svelte (it will be almost identical for other frameworks).

"scripts": {

"build": "rollup -c",

"dev": "rollup -c -w",

"start": "sirv public",

"serve": "concurrently \"node server.js\" \"npm run dev\" "

},