← back

Building a markdown based blog with Svelte

Mon Mar 11 2024 blogtechnology

Like I mentioned in the previous blog post, I built this blog / site with Svelte and SvelteKit.

Here’s the second part of my intro series talking more about my setup and how you can build the the same. Bear in mind, I am not a Svelte professional, this was my first venture into this framework. But if you are looking for similar setup this might be helpful.

This will however also not be a step by step guide since there are plenty out there similar to that, but I will mention the main problems I ran into and how I solved them.

Initial setup

Start by creating your project, Svelte recommends using Sveltekit so I did the same.

npm create svelte@latest my-blog

This will run you through a setup and after that it’s off to the races.

Project structure

The project itself is very basic and follows Sveltekits structure when it comes to routes.

There are two main routes relevant to the blog, one being: /src/routes/blog and the other being /src/routes/[slug].

The blog route contains the overview of all my posts and the [slug] refers to the name of the post, which I like to keep as the route for specific posts.

mdsvex

mdsvex is a markdown preprocessor for Svelte. This will allow you to use markdown in svelte, even full markdown files like I am using for my blog posts.

npm i -D mdsvex

At the same time I’m also installing shiki which is a syntax highlighter

npm i shiki

This is what I’m adding to my svelte.config.js

import { mdsvex, escapeSvelte } from 'mdsvex'
import shiki from 'shiki'

const mdsvexConfig = {
	extension: '.md',
	highlight: {
		highlighter: async (code, lang = 'text') => {
			const highlighter = await shiki.getHighlighter({ theme: 'dracula' })
			const html = escapeSvelte(highlighter.codeToHtml(code, { lang }))
			return html
		}
	},
};

const config = {
	extensions: ['.svelte', '.md'],
	preprocess: [vitePreprocess(), mdsvex(mdsvexConfig)],
	kit: {
		adapter: adapter()
	}
};

With this out of the way, now we are ready to create our blog page and the posts.

Blog page

I wanted a simple blog page that just lists all my posts. There is no search built in, so far they are just listed by date.

The posts are created in a folder called src/posts where they are stored as markdown files. This makes it really easy to write them and I can also easily bring over content from my Obsidian vault when I want to

To display the posts we will start by setting up our server file.

// /src/routes/blog/+page.server.js

export async function load() {
  let posts = [];

  const paths = import.meta.glob("/src/posts/**.md", { eager: true });

  for (const path in paths) {
    const file: any = paths[path];
    const slug = path.split("/").pop()?.replace(".md", "");
    const metadata = file.metadata;
    const post = { ...metadata, slug };
    post.published && posts.push(post)
  }

  posts.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());

	return { posts };
}

In the load function we start by getting the paths to all the .md files.

We then create a new post object for each path which contains the slug and all metadata.

We then add them all to the posts array and finally sort the array by date before returning the object in our data when the page is loaded.

This gives us a nice array of post objects we can display on our blog route and even with links based on the slug. Simple and straight forward!

The posts

The posts are even simpler the we add a +page.server.js that looks the following.

// /src/routes/[slug]/+page.server.js

export async function load({ params }) {
	try {
		const post = await import(`../../posts/${params.slug}.md`)

		return {
			content: post.default.render(),
			meta: post.metadata
		}
	} catch (e) {
		throw error(404, `Could not find ${params.slug}`)
	}
}

Here we take advantage of the built in params in svelte. As you can see in the route we defined the [slug] as a param and when clicking the link on the previous page this gets passed to the post page and we get the correct .md file based on it.

We then define a new object with the content and meta data, which we load on the +page.svelte.

To render the markdown content itself the page I use the following.

	<div class="markdownContent">
		{@html data.content.html}
	</div>

I hope that was helpful to get the Markdown part of this setup working. Like I wrote previously, there are many incredible resources already for creating svelte content, this is what worked for me, maybe it will work for you.

rasmusroy.me © 2024last updated: Thu, Apr 25, 2024