I finally switched from Sapper to SvelteKit 
Tags: svelte, sveltekit, sapper, markdown
Published: 2022-03-08 20:39:24

---
title: I finally switched from Sapper to SvelteKit 
published: true
description: Notes on my journey into the lands of SvelteKit goodness…
tags: svelte, sveltekit, sapper, markdown
---

_Original post (ironically the blog I'm talking about itself) is [here](https://developtodesign.com/sveltekit-refactor-notes)…_

This post is a sort of &ldquo;stream-of-conciousness set of notes&rdquo; that jot down lessons I learned as I refactor this previously Sapper-based blog to use SvelteKit instead.

My main motivation for updating the blog is that I'd like to incorporate [agnostic-svelte](https://github.com/AgnosticUI/agnosticui/tree/master/agnostic-svelte) examples and dog-food that package. The main [AgnosticUI site](https://www.agnosticui.com/) leverages [Vitepress](https://vitepress.vuejs.org/) which allows you to use Vue components within your content. So, any rendered examples you see are using Vue 3 under the hood. As I'm big on verification through tried-and-true real usage, I wanted to start creating Svelte templates here on my blog as well.

## Svelte

Along the way there were a couple of basic Svelte lessons I had to learn or relearn as well. Probably it's stuff I should have grok'd when I built the Sapper-based site but didn't.

### Auto-subscriptions

I noticed I had a memory leak bug in my old blog code — I wasn't using `onDestroy(unsubscribe)`. I went to the docs to ensure I understood how I should do that and discovered [auto-subscriptions](https://svelte.dev/tutorial/auto-subscriptions):

> Svelte has a trick up its sleeve — you can reference a store value by prefixing the store name with $...You're not limited to using $count inside the markup, either — you can use it anywhere in the `<script>` as well

As such, I refactored code like:

```js
  import { isDarkModeEnabled } from '$lib/common/store.js';
  let isDarkMode;
  onMount(() => {
    const unsubscribe = isDarkModeEnabled.subscribe((value) => {
      isDarkMode = value;
    });
  });
  onDestroy(unsubscribe);
```

To simply use `$isDarkModeEnabled` removing for the lifecycle code cruft:

```js
  {#if $isDarkModeEnabled}...conditional code here...{/if}
```

## SvelteKit

These are some SvelteKit specific notes…

### Static Site

For my use case, I needed to be able to completely build out a static site and was please to learn that [@sveltejs/adapter-static](https://github.com/sveltejs/kit/tree/master/packages/adapter-static) can give you that for free. No fuss, just followed the `README` instructions and was off and running.

#### Page Slugs with no .html

The way I originally set up the Sapper version of this site had a couple of features in the produced URLs that I still like:
- The blog post comes right off the top-domain so `foo.com/my-slug`
- Omits `.html` file type

In fact, if you look in the URL address bar you should see:

`https://developtodesign.com/sveltekit-refactor-notes`

Well, once I refactored to use SvelteKit and built the static site with:

```shell
npm run build # npm run preview to verify
```

I noticed that my site would work ok if I came in from the home page and clicked around. However, if I hard reloaded an article's URL e.g. this very page: `https://developtodesign.com/sveltekit-refactor-notes` I would get a 404 not found. On closer examination, I saw that the static pages being produced actually had `.html` file extensions. I did not find instructions for this in the static adapter readme (perhaps it's considered common knowledge), but I added the following to my `.htaccess` file which got things working as expected:

```shell
RewriteEngine On
RewriteBase /

# Check if request is for an actual file, serve the file
RewriteRule ^([^\.]+)$ $1.html [NC,L]

# Catch request to HTML file, remove extension
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^\ ]+)\.html
RewriteRule ^/?(.*)\.html$ /$1 [L,R=301]
```

### SvelteKit & mdsvex

I switched to [mdsvex](https://mdsvex.pngwn.io/) to pull in my markdown-based static posts. This seems to be the popular choice for SvelteKit static blogs.

Honestly, fussing around with getting `mdsvex` and svelte-kit [Endpoints](https://kit.svelte.dev/docs/routing#endpoints) to work together took some experimentation. My blog articles are NOT at `/posts/my-article-slug` as is typical, but right off the top-level e.g. `/my-article-slug`. Achieving this was a challenge but I got it going.

I found I could only get the `mdsvex` to work correctly if I &ldquo;artifically&rdquo; created a `src/routes/posts` directory and placed my `index.json.js` in there, but place my content top-level in `src/routes` and use `[slug].json.js` to load the articles individually. It's nuanced and if you're looking for details I'd point you to my [blog's GitHub repo](https://github.com/roblevintennis/developtodesign) and you can reverse engineer ;-)

#### Code Highlighting

`mdsvex` provides [Prism.js](https://github.com/PrismJS) support out-of-the-box and so all I had to do was to drop in a [css theme](https://github.com/PrismJS/prism-themes/blob/master/themes/prism-material-dark.css) and I had code highlighting. Super easy!

#### Svelte Components in Markdown

One of the more interesting features of `mdsvex` is full support for Svelte syntax—perfect for my motives to start showing some example templates using `agnostic-svelte`! I'm quite happy that the [AgnosticUI Svelte setup docs](http://www.agnosticui.com/docs/setup.html#svelte) worked just fine.

## Feeds

From when the site was in Sapper, I had dynamic sitemap, rss, and atom feeds. I basically hand-refactored any subtle path changes, etc., and got those working. But, they all leveraged a helper to actually pull in the markdown. It used to be super long and I was quite please that it's been reduced to just:

```js
export const getMarkdownContent = async () => {
  const posts = await Object.entries(
    import.meta.globEager('/src/routes/*.md')
  ).map(([, post]) => post.metadata);
  posts.sort((a, b) => (a.date < b.date ? 1 : -1))

  return posts
}
```

The huge lines-of-code saver was this `import.meta.globEager` thing that Vite calls [Glob Import](https://vitejs.dev/guide/features.html#glob-import). It's very nice to have your builder remove the need for extra dependencies.

The dynamic feed scripts are a bit involved for this article, but feel free to reverse them off the [blog's GitHub repo](https://github.com/roblevintennis/developtodesign).

# Conclusion

So far I've mainly enjoyed working with SvelteKit. I didn't find a lot of examples of having the posts show up top-level as I've done here, but did find the following resources helpful in one way or another:

- [SvelteKit Docs](https://kit.svelte.dev/)

- [Merilynn Bandy mdsvex and SvelteKit](https://www.furudean.com/blog/svelte-kit-mdsvex)

- [Let's learn SvelteKit by building a static Markdown blog from scratch](https://joshcollinsworth.com/blog/build-static-sveltekit-markdown-blog#adding-markdown-to-sveltekit-with-mdsvex)