Contents
- About my blog
- Configure Sveltekit
- Terraform and Infrastructure as Code
- Obsidian
- Deploying and Updating the app
About my blog
I decided to build a blog using tools and frameworks I’m most comfortable with. While not all of these are essential, they represent a stack that suits my workflow:
- SvelteKit: A UI framework that uses a compiler to help build concise, fast-loading components.
- Obsidian: A private and flexible writing app that I use as my markdown editor.
- Buttondown: An email platform that makes it easy to start and grow a newsletter.
- Terraform: A tool for automating infrastructure, which I use to deploy and distribute my blog.
As a foreword, this post is not a deep dive into the technical details of my blog’s setup. Instead, I’m outlining the project as a reference for myself and anyone interested in building a similar system. I’d like to thank the following for their valuable resources:
The maintainers of:
And the blogs of:
Configure Sveltekit
To set up a static blog capable of rendering markdown files, I configured SvelteKit to use a static site generator (SSG).
Start by installing the SvelteKit static adapter:
npm i -D @sveltejs/adapter-static
Then, add the adapter to your svelte.config.js file:
import adapter from '@sveltejs/adapter-static';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// ....
// your config
// ....
kit: {
adapter: adapter({
pages: 'dist',
fallback: 'index.html'
}),
prerender: {
crawl: true
}
}
}
};
export default config;
Ensuring that all your files can be prerendered is crucial. Having dynamic content transformed into cachable static assets is a huge performance boost for the site.
Page Routing and Rendering
The root of the project is in the routes/
directory. Within that, I created a
folder called [...path]/
to handle routing logic for the blog. This folder
contains two main files:
+page.ts
: Loads and processes the posts.+page.svelte
: Displays the post.
I write my posts in markdown for faster content creation while focusing on the writing itself. SvelteKit, with the help of mdsvex, handles the transformation of markdown into renderable Svelte components.
Mdsvex
mdsvex is a popular Svelte package that allows you to write markdown in your Svelte components or Svelte syntax in your markdown files.
To configure mdsvex in your project, first install it:
npm i --save-dev mdsvex
Then, update your svelte.config.ts file:
// svelte.config.ts
import adapter from "@sveltejs/adapter-static";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
import { mdsvex } from "mdsvex";
/** @type {import('mdsvex').MdsvexOptions} */
const mdsvexOptions = {
// define you're config inside here
};
/** @type {import('@sveltejs/kit').Config} */
const config = {
extensions: [".svelte", ".md"],
preprocess: [mdsvex(mdsvexOptions), vitePreprocess()],
// other config stuff...
};
export default config;
I’ve kept the mdsvex configuration simple, but if you want more details, feel free to check out my full setup here.
Svelte and Markdown
SvelteKit doesn’t natively render markdown without configuring a markdown
processor like mdsvex. This setup allows .md
files to be parsed into usable
HTML strings and rendered inside Svelte components.
Here’s a simple example of how you can dynamically load and display markdown content in your SvelteKit app:
// [...posts]/+page.svelte
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
</script>
<svelte:component this={data.component} />
Skeleton UI
Skeleton integrates with Tailwind to provide opinionated solutions for themes, colors, typography and more. Including easy to use components for your favorite web frameworks.
I use skeleton’s unreleased v3 updates which are almost complete! Go support them, and checkout their nearly complete v3 documentation (link is likely to expire when the updates are finished) to get started.
Terraform and Infrastructure as Code
For deployment, I rely on Terraform to automate the infrastructure setup for my blog. Here’s a breakdown of the components I use:
S3 Buckets: I deploy two S3 buckets—one for storing the Terraform remote backend and another for hosting my blog’s static content. The S3 bucket efficiently serves my static assets (HTML, CSS, JavaScript).
CloudFront Distribution: I use Amazon CloudFront as a CDN for my blog, ensuring fast, secure delivery of content to users worldwide. It’s placed in front of my S3 bucket to speed up access times.
Route 53 Domain Name: Amazon Route 53 manages my DNS and domain name, allowing me to point my custom domain to the CloudFront distribution and handle HTTPS traffic seamlessly.
Additional Infrastructure: Terraform helps automate the provisioning of SSL certificates (via AWS Certificate Manager), configure IAM roles, and scale resources as needed.
Obsidian
I use Obsidian as my primary writing tool. It’s a powerful, flexible markdown editor that lets me focus solely on writing, without distractions from formatting or code. Obsidian allows me to easily organize my drafts, manage notes, and sync my posts with my SvelteKit blog setup.
Once my posts are finalized in markdown, I export the files, and mdsvex takes care of converting them into HTML for the blog. It’s a straightforward and efficient workflow that helps me focus on creating content.
Deploying and Updating the app
Here’s how you can implement the deployment and updating process using a combination of the services I’ve mentioned
1. Update Git Repository
Push your latest changes to your Git repository using standard Git commands:
# Add any new or updated files
git add .
# Commit the changes with a message
git commit -m "Update blog content and infrastructure"
# Push the changes to your remote repository
git push origin main
2. Sync S3 Bucket with Static Files
To sync your static blog content to your S3 bucket, you can use the AWS CLI
command. Replace my-s3-bucket
with your actual S3 bucket name:
# create a new production build with you're latest changes
npm run build
# Sync the local build directory (e.g., dist/) with your S3 bucket
aws s3 sync ./dist s3://my-s3-bucket --delete
This command ensures that the latest static files are uploaded to your S3 bucket, and any deleted or changed files are updated accordingly.
3. Invalidate CloudFront Cache
To ensure that CloudFront serves the updated content, you need to invalidate its
cache. This forces CloudFront to fetch the new files from the S3 bucket. Replace your-distribution-id
with your CloudFront distribution ID:
# Invalidate CloudFront cache to serve the latest content
aws cloudfront create-invalidation --distribution-id YOUR_DISTRIBUTION_ID --paths "/*"
This command will invalidate all the cached files so that the updated files are served immediately.
4. Infrastructure Changes with Terraform
If any infrastructure changes are necessary, you can apply them with Terraform. Here’s how to initialize Terraform and apply changes to your infrastructure:
# Navigate to your Terraform configuration directory
cd terraform
# Initialize Terraform (only required the first time or after changes to modules/providers)
terraform init
# Review the planned changes
terraform plan
# Apply the changes to your infrastructure
terraform apply
With these steps, you can easily deploy and update your blog, ensuring that new content and infrastructure changes are live without manual intervention. By automating the workflow, you’re able to focus on writing and growing your blog, while the deployment pipeline handles the rest.