svelte SPA with TypeScript, Routes and SCSS
svelte
is one of the newer JavaScript-Frameworks out there. Although I do not tend to jump on the hype train, the “compile time” approach svelte
uses is really promising referring to performance and size. Here is how to start a project with TypeScript
, Routes and SCSS
…
Introduction
This tutorial is based on information I gathered during my research and project work and summarizes setting up features, I’d personally like to use. It is a basic project setup for advanced users, not for beginners and neither a replacement for the official documentation nor a guide that describes all best practises. It contains:
TypeScript
integration for svelte projectsSCSS
integration (CSS with superpowers)routify
integration, which can be used to better organize your project’s filesystem structure and code
Why svelte
?
svelte
is fast and small - ideal for smaller to medium-sized projects in my opinion. Instead of being stuffed with features at runtime, it converts the code and templates to native javascript at compile time, which results in delivering only vanilla JavaScript code, that is absolutely necessary. The support of Web-Components and a pretty fast boilerplate is a bonus.
Preparations
Before you start with svelte
, you have to install Node.js
(node
, npm
, npx
). You’ll find further instructions on the homepage.
Step 1: Project setup
These are the basic steps to set up a new svelte project (shamelessly stolen from the official homepage):
SVELTE_PROJECT_NAME="my-svelte-project"
npx degit sveltejs/template "${SVELTE_PROJECT_NAME}"
cd "${SVELTE_PROJECT_NAME}"
# setup TypeScript (this step is optional, but I like to use it)
node scripts/setupTypeScript.js
npm install
npm run dev
Now you should see a URL to open the “Hello World!”, probably http://localhost:5000 .
Note: To actually use TypeScript in the project, you have to use
<script lang="ts">
instead of<script>
Step 2: SPA routing with routify
The package routify
(@roxi/routify
) allows client side SPA routing for svelte
. It is also “compile time”, which means that the filesystem structure will be precompiled to routes and not determined at runtime - which is awesome and follows the svelte
design principles.
Dependencies
Install the following dependencies:
Note: This is different from the official instructions, because I had errors. If it does not work for you, you may also follow the official ones.
npm i -D @roxi/routify npm-run-all svelte-preprocess
Update package.json
Next, update the package.json
- to use routify
, you also need to update the scripts
section and set "dynamicImports": false
:
{
"...": "...",
"scripts": {
"dev": "run-p dev:*",
"dev:rollup": "rollup -c -w",
"dev:routify": "routify",
"build": "routify -b && rollup -c",
"...":"..."
},
"routify": {
"dynamicImports": false
}
}
Integrate routify
filesystem structure
To integrate routify
, you need to modify the App.svelte
and create some new templates in the pages
directory. Since it is “compile time” routing, a directory .routify
will be generated automatically, containing all your precompiled routes. This is what you also need to import. There are two ways of routing:
- Default (route name as URI, e.g. https://my-ap.dev/contact, which may require some rewrite rule on the webserver)
- Hash-based (puts the route name after the hash-tag, e.g. https://my-ap.dev/#/contact, which does not require a rewrite rule and should work everywhere)
<!-- src/App.svelte -->
<script lang="ts">
import { Router } from "@roxi/routify";
import { routes } from "../.routify/routes";
</script>
<!-- Hash-based routing
<Router config={{useHash: true}} {routes} />
-->
<Router {routes} />
The file _layout.svelte
is a meta-template, that will be used to render everything, that was in App.svelte
before. <slot/>
is the destination for all page templates.
<!-- src/pages/_layout.svelte -->
<div class="container">
<slot/>
</div>
To ensure, everything is working before getting into detail, we add the route name index
to our page template.
<!-- src/pages/index.svelte -->
index
Don’t forget to restart npm run dev
. You could now check http://localhost:5000
again, if it is showing the index text. Since /.routify/
is auto generated, we can add it to our .gitignore
# .gitignore
# ...
/.routify/
Step 3: SCSS
support
While this should be easy, in svelte
you might run in to problems using SCSS
. One way I got everything working was to start with installing these dependencies:
npm i -D node-sass postcss sass rollup-plugin-scss
Then add the following SCSS
files:
/* scss/__vars.scss */
$bodyBackground: silver;
/* scss/main.scss */
@import '_vars';
body {
background: $bodyBackground;
}
To have an entry point for loading the SCSS
files, I created a template only for this purpose:
<!-- src/GlobalScssImports.svelte -->
<style lang="scss" global>
@import "scss/main.scss";
</style>
And included it into the App.svelte
:
<!-- src/App.svelte -->
<script>
import { Router } from "@roxi/routify";
import { routes } from "../.routify/routes";
import GlobalCssImports from "./GlobalScssImports.svelte";
</script>
<GlobalCssImports/>
<Router config={{useHash: true}} {routes} />
Restart npm run dev
again. Refresh, now you should see a page with background:silver;
on http://localhost:5000
and this SCSS
config should enable you to use @import
statements in scss/main.scss
for other files.
Step 4: Navigation and first route
To verify routes are working correctly, now create your first page template in form of contact.svelte
:
<!-- src/pages/contact.svelte -->
contact
The _navigation.svelte
is not a page template or route, but only used as import
in _layout.svelte
(templates starting with _
will be ignored by routify
, except _layout.svelte
and other reserved names). The helpers url
and isActive
can be used, to create links to routes and add CSS
classes for active elements:
<!-- src/pages/_navigation.svelte -->
<script>
import {url, isActive} from '@roxi/routify';
</script>
<nav class="main-nav">
<ul>
<li class:active="{$isActive('./index')}"><a href="{$url('')}">index</a></li>
<li class:active="{$isActive('./contact')}"><a href="{$url('./contact')}">contact</a></li>
</ul>
</nav>
Then load the _navigation.svelte
into the _layout.svelte
:
<!-- src/pages/_layout.svelte -->
<script>
import Navigation from "./_navigation.svelte";
</script>
<Navigation/>
<div class="container">
<slot/>
</div>
To actually see, if the helpers for class active
do their job, we add a little SCSS
:
/* scss/main.scss */
@import '_vars';
body {
background: $bodyBackground;
}
.main-nav .active {
font-weight:bold;
}
Now you should be able to navigate in your project, and the active nav item should be highlighted bold.
Conclusion
This is it for now. The page still looks pretty raw, but you should have a starting point with the mentioned technologies and a basic project setup for building nice little blazing fast apps. Take a look at the svelte and routify documentation for the next steps.