SvelteKit Blog: Generate post links at build time
Jan 13, 2022Notice. This was written pre SvelteKit 1.0.0. With the release of SvelteKit 1.0.0 some things changed. Especially the folder and routing structure. The solution in this blog post isn’t compatible with version 1.0.0.
My blog posts are markdown files that get transformed to html files by using mdsvex.
After I set up this processing I thought: But how can I create the links to the posts on my index page?
The first attempt was to import some file-system packages and try to scan the folder with the markdown files. But that wasn’t possible.
Using vite import
But then I found the solution in this blog post.
By using the vite glob import it was possible to get the markdown files during build time
function getMarkdownFiles() {
return import.meta.globEager(`../routes/blog/**/*.md`);
}
The result had the following structure:
{
"../routes/blog/add-frontmatter-to-blog-post.md": {
default: {},
metadata: {
date: "2022-01-08T00:00:00.000Z",
title: "Add frontmatter data to posts in SvelteKit"
}
},
"../routes/blog/some-other-post.md": {}
}
You can see the object contains all the necessary information. Awesome. I just had to extract the relevant information. If you want to know more about this you can check this file.
The result:
[
{
route: "/blog/add-frontmatter-to-blog-post",
metadata: {
title: "Add frontmatter data to posts in SvelteKit",
date: "2022-01-08T00:00:00.000Z"
}
},
]
But where do I invoke this?
Components in SvelteKit can have a load
function (placed in a <script context="module">
block). This function executes before the component is created.
The function returns an object that contains a props
property. The value of this property is passed to the component.
Now we can access the log posts information in the component and create links to posts.
// execute before the component is initialized
<script context="module">
import { getLatestFivePostsDescByDate } from '../blog/markdownFilesToPosts';
export async function load() {
const postsByDescDate = getLatestFivePostsDescByDate();
// pass the post data as props to the component
return { props: { posts: postsByDescDate } };
}
</script>
<script>
// posts are injected by the load function
export let posts;
</script>
<h1>recent posts</h1>
<div>
{#each posts as post}
<li>
<a href={post.route}>
{post.metadata.title}
</a>
</li>
{/each}
</div>