Sapper Router Demo
Svelte looks very appealing, I have read through the examples and wanted to look at how routing works before going any further. Sapper is the framework for Svelte that handles routing, I am going to dip my toe in with a demo that is similar to the one I did for Aurelia in a previous post; a simple demo showing how nested routes work.
View the demo.
Install Sapper
At the time of writing Sapper is in early development so things are likely to change quickly, right now I am following the getting started guide which instructs as follows…
npx degit "sveltejs/sapper-template#rollup" sapper-router-demo
# or: npx degit "sveltejs/sapper-template#webpack" sapper-router-demo
cd sapper-router-demo
npm install
npm run dev
Marvellous, we are now up and running at localhost:3000
.
Cleanup
Note that for the sake of this demo I have removed the blog page generated by the Sapper project template and simplified the views so there are only titles allowing us to just concentrate on routes.
Nested Routes
See the documentation for nested routes.
In order to test out nested routes lets first add a new page called profile
.
- Within the
routes
directory add a new directory calledprofile
- Within the
profile
directory add a new file called_layout.svelte
This layout component will be applied to all child pages of profile
. In this file lets add a heading and slot.
src/routes/profile/_layout.svelte
<h2>Profile</h2>
<slot></slot>
We now have a new page that we need to show on the navigation bar. In the navigation component we need to add another link to our profile page as follows…
src/components/Nav.svelte
<li><a class="{segment === 'profile' ? 'selected' : ''}" href="profile">profile</a></li>
Now in the UI we have a profile link but if you click it the 404 page is displayed. That is because a layout alone will not get rendered, we need either an index.svelte
which will be loaded by default for the above link (href="profile"
) or we need to be explicit and point to another file/directory within the profile
directory, for example href="profile/account"
, this is a nested route.
Lets add some more nested pages to profile so we end up with the file tree below.
├── routes
│ ├── _error.svelte
│ ├── _layout.svelte
│ ├── about.svelte
│ ├── index.svelte
│ └── profile
│ ├── _layout.svelte
│ ├── account
│ │ ├── index.svelte
│ ├── email
│ │ └── index.svelte
│ └── notifications
│ └── index.svelte
- add a new directory called
account
insrc/routes/profile
- add a new directory called
email
insrc/routes/profile
- add a new directory called
notifications
insrc/routes/profile
Then in each of those directories add an index.svelte
file with a heading, for example in account
we will have…
src/routes/profile/account/index.svelte
<h2>Account</h2>
Now lets go back to our main navigation component and fix the 404 issue we were seeing. Modify the href
attribute to point to our account
page as follows.
src/components/Nav.svelte
<li><a class="{segment === 'profile' ? 'selected' : ''}" href="profile/account">profile</a></li>
Now when we click on the profile
link we navigate to /profile/account
and the index page is loaded by default and we see our Account heading displayed underneath the Profile heading.
But what about our other nested pages, how do we access those? We need to create another menu so we can access account
, email
and notifications
from within the profile page. Lets go back to profile layout and add some navigation.
src/routes/profile/_layout.svelte
<script>
export let segment;
</script>
<style>
.selected {
color: rgb(255, 62, 0);
}
</style>
<h1>Profile</h1>
<nav>
<ul>
<li>
<a class="{segment === 'account' ? 'selected' : ''}" href="profile/account/">account</a>
</li>
<li><a class="{segment === 'email' ? 'selected' : ''}" href="profile/email">email</a></li>
<li>
<a class="{segment === 'notifications' ? 'selected' : ''}" href="profile/notifications"
>notifications</a
>
</li>
</ul>
</nav>
<slot></slot>
Now when we refresh the page we see our profile page with nested routes account
, email
and notifications
. Note that above there is some simple styling for the currently selected menu item. We could of course style this menu further but right now lets leave it as is.
More Nesting
Lets add more nesting under profile/account
to show that we can keep nesting as much as we like - add username
and password
pages.
- add a new directory called
username
insrc/routes/profile/account
- add a new directory called
password
insrc/routes/profile/account
Then in each of those directories add an index.svelte
file with a heading, just as we did earlier.
Again, we need to create a menu for these nested pages so we need a _layout.svelte
file in src/routes/profile/account
. In this case we already have our index.svelte
file in the account
directory so we can just rename it to _layout.svelte
and add some navigation.
src/routes/profile/account/_layout.svelte
<script>
export let segment;
</script>
<style>
.selected {
color: rgb(255, 62, 0);
}
</style>
<h2>Account</h2>
<nav>
<ul>
<li>
<a class='{segment === "username" ? "selected" : ""}' href="profile/account/username"
>Username</a
>
</li>
<li>
<a class='{segment === "password" ? "selected" : ""}' href="profile/account/password"
>Password</a
>
</li>
</ul>
</nav>
<slot></slot>
Now when we click profile in the main menu we get a 404 due to renaming the file. To fix this we need to modify our profile
link in the main navigation component.
src/components/Nav.svelte
- <li><a class:selected='{segment === "profile"}' href='profile/account'>profile</a></li>
+ <li><a class="{segment === 'profile' ? 'selected' : ''}" href="profile/account/username">profile</a></li>
Now when we click on profile
in the main menu we see that we default to the username view - profile > account> username
.
There is one last modification to make in src/routes/profile/_layout.svelte
to make sure that when we click the account
link we navigate to our default account view which is username
.
src/routes/profile/_layout.svelte
<nav>
<ul>
- <li><a class="{segment === 'account' ? 'selected' : ''}" href="profile/account/">account</a></li>
+ <li><a class="{segment === 'account' ? 'selected' : ''}" href="profile/account/username">account</a></li>
<li><a class="{segment === 'email' ? 'selected' : ''}" href="profile/email">email</a></li>
<li><a class="{segment === 'notifications' ? 'selected' : ''}" href="profile/notifications">notifications</a></li>
</ul>
</nav>
Conclusion
There we have it, by following a few conventions we have nested routes in sapper.