Logo

dev-resources.site

for different kinds of informations.

How to Build a Content-Driven Static Site with Markdown, SvelteKit and Fusionable

Published at
11/14/2024
Categories
svelte
sveltekit
markdown
tutorial
Author
robertobutti
Author
12 person written this
robertobutti
open
How to Build a Content-Driven Static Site with Markdown, SvelteKit and Fusionable

Step-by-step tutorial on building a static website with SvelteKit and Fusionable. Explore setting up Markdown content, dynamic filtering, sorting, and displaying articles in a flexible, fast Svelte-based site.

Building a content-driven static website is easy with SvelteKit and Fusionable. With SvelteKit’s powerful framework and Fusionable’s flexible Markdown content querying, you can quickly set up a site that loads content from Markdown files and provides dynamic lists and filtering.

In this guide, we’ll cover the essentials:

  • Setting up SvelteKit and Fusionable
  • Creating Markdown-based content
  • Using Fusionable to query and display content

So in this article we will use:

  • SvelteKit as frontend framework
  • Fusionable the library for querying, parsing, sorting, filtering, limiting the Markdown files
  • Bun as JavaScript runtime, bundler, package manager. Let's dive in!

Set Up Your Project with SvelteKit and Fusionable

First, set up a new SvelteKit project and install Fusionable.

# Create a new SvelteKit project
bunx sv create my-static-site
cd my-static-site

# Add Fusionable
bun add fusionable
Enter fullscreen mode Exit fullscreen mode

With Fusionable, you can efficiently load, filter, and sort Markdown content from your filesystem.

Create Content with Markdown

In your project, create a directory to store Markdown files. For example:

# Inside your project directory
mkdir -p src/content/posts
Enter fullscreen mode Exit fullscreen mode

Inside src/content/posts, add Markdown files for each article. Here’s an example post:

# src/content/posts/my-first-post.md

---
title: "My First Post"
date: "2023-10-01"
slug: "my-first-post"
highlight: true
---

Welcome to my first blog post! This is a *simple* **Markdown** example.

Enter fullscreen mode Exit fullscreen mode

Fusionable allows you to parse, load and filter the frontmatter metadata (title, date, etc.), which will make it easy to query and display your content.

Fusionable is an open source project, here you can find the public repository: https://github.com/Hi-Folks/fusionable

Load Content with Fusionable

Now, create a SvelteKit +page.server.js file to load content using Fusionable. Start by setting up a FusionCollection and loading posts from the src/content/posts directory:

// src/routes/+page.server.js
import FusionCollection from 'fusionable/FusionCollection';

export function load() {
  const collection = new FusionCollection()
    .loadFromDir('src/content/posts')
    .orderBy('date', 'desc');

  const posts = collection.getItemsArray();
  return { posts };
}
Enter fullscreen mode Exit fullscreen mode

Here, we’re ordering posts by date in descending order and retrieving the list as an array. You’ll use this data in the src/routes/+page.svelte file.

// src/routes/+page.svelte
<script lang="ts">
  import type { PageData } from './$types';
  let { data }: { data: PageData } = $props();
</script>

<main>
  <h1>Blog Posts</h1>
  <ul>
    {#each data.posts as post}
      <li>
        <a href={`/posts/${post.fields.slug}`}>{post.fields.title}</a>
        <p>{post.fields.date}</p>
      </li>
    {/each}
  </ul>
</main>
Enter fullscreen mode Exit fullscreen mode

This code iterates over posts and displays each post’s title and date with a link. The links will point to individual post pages.

Create Individual Post Pages

To display individual posts, set up a src/routes/posts/[slug]/+page.svelte page that renders each post based on its unique slug. Create a new file in src/routes/posts/[slug]/+page.server.js:

// src/routes/posts/[slug]/+page.server.js
import FusionCollection from 'fusionable/FusionCollection';

export function load({ params }) {
  const collection = new FusionCollection().loadFromDir('src/content/posts');
  const post = collection.getOneBySlug(params.slug);

  if (!post) {
    throw new Error('Post not found');
  }

  return { post: post.getItem() };
}
Enter fullscreen mode Exit fullscreen mode

And then, create +page.svelte in src/routes/posts/[slug]:

// src/routes/posts/[slug]/+page.svelte
<script lang="ts">
  import type { PageData } from './$types';
  let { data }: { data: PageData } = $props();
</script>

<article>
  <h1>{data.post.fields.title}</h1>
  <p>{data.post.fields.date}</p>
  {@html data.post.content}
</article>

Enter fullscreen mode Exit fullscreen mode

Now, each post’s page renders its title, date, and Markdown content.

Final Touch: Converting Markdown to HTML with Showdown

To make our content even more dynamic, let's convert the Markdown content in post.content into HTML using the Showdown library. This will allow us to display fully formatted Markdown as HTML on each post page.

Installing Showdown

If you're using Bun, you can install Showdown quickly with:

bun add showdown
Enter fullscreen mode Exit fullscreen mode

Converting Markdown to HTML in +page.svelte

In src/routes/posts/[slug]/+page.svelte, import and use Showdown to process data.post.content before rendering it.

  • First, import Showdown in your Svelte component.
  • Then, convert the Markdown to HTML and use Svelte's {@html ...} directive to render it safely.

Here’s how it looks:

<script lang="ts">
  import type { PageData } from './$types';
  import Showdown from 'showdown';
  let { data }: { data: PageData } = $props();
  const converter = new Showdown.Converter();
  const postContentHTML = converter.makeHtml(data.post.content);
</script>

<article>
  <h1>{data.post.fields.title}</h1>
  <p>{data.post.fields.date}</p>
  {@html postContentHTML}
</article>
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

That’s it!
For running your local project you can execute:

bun dev --open
Enter fullscreen mode Exit fullscreen mode

If you are interested into builing statically the website for deploying HTML static assets in production environment, you can take a look at this article: Building your static website with Svelte, SvelteKit and TailwindCSS. The section "Build statics pages (Static Site Generator)" explaing and demostrate how to use the static adapter for building quickly static pages.

You’ve now set up a basic website using SvelteKit and Fusionable, complete with Markdown-based content, custom filtering, and sorting. Fusionable provides powerful querying tools, making it easy to expand this setup with more filters (e.g., featured posts) or custom sort orders.

You’re now ready to customize and expand your site. Happy coding!

Remember to give a star ⭐ to the Open Source repository: https://github.com/Hi-Folks/fusionable, thank you!

sveltekit Article's
30 articles in total
Favicon
Optimize SvelteKit performance with brotli compression
Favicon
SvelteKit VS Astro. laidback side by side
Favicon
Integrating SvelteKit with Storyblok (Using Svelte 5)
Favicon
Make EditorJS work in Svelte(kit) SSR
Favicon
Why Svelte?
Favicon
Nosecone: a library for setting security headers in Next.js, SvelteKit, Node.js, Bun, and Deno
Favicon
Building AI-Powered Apps with SvelteKit: Managing HTTP Streams from Ollama Server
Favicon
NgSysV2-3.4: A Serious Svelte InfoSys: Rules-friendly version
Favicon
NgSysV2-3.3: A Serious Svelte InfoSys: Firebase D/b rules and Login
Favicon
NgSysV2-3.6: A Serious Svelte InfoSys: Deploying to the Google Cloud
Favicon
NgSysV2-3.5: A Serious Svelte InfoSys: Client-Server Version
Favicon
NgSysV2-4.2: SEO (Search Engine Optimisation)
Favicon
NgSysV2-4.3: Automated Svelte Pre-render Builds
Favicon
NgSysV2-4.4: Responsive/Adaptive Design
Favicon
Deploy a Static Sveltekit site to Railway
Favicon
Why You Should Avoid Using `try...catch` in SvelteKit Actions
Favicon
How to integrate shadcn-svelte into the editable.website template
Favicon
PostgreSQL Full Text Search Rank by Position
Favicon
How to Build a Content-Driven Static Site with Markdown, SvelteKit and Fusionable
Favicon
Interview with Prabhu Kiran Konda, Creator of Snail AI!
Favicon
"Helper" Varaibles in Svelte 5
Favicon
Experiences and Caveats of Svelte 5 Migration
Favicon
Running a Function When an #await Block resolves in Svelte(Kit)
Favicon
SanS-UI v0.0.1 Quick Start!
Favicon
Introduction to Svelte: Features and Benefits of the Modern JavaScript Framework
Favicon
Sveltekit + TypeScript + TypeORM + ESM
Favicon
Svelte 5 is out!!!
Favicon
SanS-UI Released v0.0.1
Favicon
How to Integrate Passkeys into SvelteKit
Favicon
AWS Amplify (Gen2) with SvelteKit: authentication on SSR

Featured ones: