Migrating my blog to Astro - Planning
So I've decided to move from Jekyll to Astro. What does that actually involve, and how can we move things to the new structure with as little pain (and not breaking things) as possible?
This is part of a series of posts on how I migrated my blog to Astro
The directory structure under Jekyll looked something like this:
+---assets
| +---2005
| | +---06
| | \---12
| +---2006
| +---2025
| | +---01
| | +---02
| | \---04
| \---css
+---images
+---scripts
+---tag
+---_includes
+---_layouts
+---_posts
| +---2005
| +---2006
| \---2025
\---_sass
\---minima
\---skins
The target structure for Astro looks like this. It’s close, but slightly different.
+---public
| +--- favicon.ico
| +--- robots.txt
+---src
| +---assets
| | +---2005
| | | +---06
| | | \---12
| | +---2006
| | +---2025
| | | +---01
| | | +---02
| | | \---04
| | \---css
| +---components
| +---layouts
| +---pages
| | +---archive
| | +---tags
| | \---[year]
| +---posts
| | +---2005
| | +---2006
| | \---2025
| +---scripts
| \---styles
+---_drafts
\---_templates
(You can see it live by looking at the public repo at https://github.com/flcdrg/astro-blog-engine).
There’s a few tasks to achieve here:
- Moving files and directories to match the layout preferred by Astro
- Editing the .md files to remove the
layout:
property - Updating Markdown links to images so they are relative to
../../assets
rather than/asset
- Updating internal links to other posts to remove the Liquid {% %} syntax and replace them with plan Markdown links.
Of note, any files in the public
directory will be copied to the root of the website unmodified. I just have the favicon.ico
file and the robots.txt
. All other images live under the src/assets
folder. This follows the Astro recommendation, so that the images can be optimised and bundled during the build process.
For the moving, git mv
does the trick, but don’t fall for the mistake I made - git mv assets src/assets
will mean you end up with src/assets/assets
. Instead, create the src
directory (otherwise Git will give a weird error) and then use this:
git mv assets src
git mv _posts src
cd src
git mv _posts posts
Note we do a second move, so that we end up with src/posts
.
For all the blog post .md updates, I wrote a PowerShell script to do the edits:
param(
[string]$directory = ".\src\posts\"
)
# Define the regex pattern to match the markdown link
# [new laptop]({% post_url 2023/2023-04-26-new-laptop %})
$pattern = "\[([^\]]+)\]\(\{% post_url (\d{4})/\d{4}-(\d{2})-(\d{2})-([^\s%]+) %\}\)"
# Loop through all .md files in the directory and its subdirectories
Get-ChildItem -Path $directory -Recurse -Filter "*.md" | ForEach-Object {
$filePath = $_.FullName
$content = Get-Content -Path $filePath -Raw
# Replace the markdown link with the desired HTML link format
$updatedContent = $content -replace $pattern, '[$1](/$2/$3/$5.html)'
# Remove the 'layout: post' line
$updatedContent = $updatedContent -replace "layout: post`r?`n", ""
# Assets path in the frontmatter
$updatedContent = $updatedContent -replace "image: /assets", "image: ../../assets"
# Assets paths in remaining content
$updatedContent = $updatedContent -replace "(?<!\.\.)/assets/", "../../assets/"
# Remove .html extension from internal links
$updatedContent = $updatedContent -replace "\[([^\]]+)\]\((\/\d{4}\/\d{2}\/[\w\d\-]+)\.html\)", '[$1]($2)'
# Ensure just a single blank line at the end of the file
$updatedContent = $updatedContent.TrimEnd()
# Save the updated content back to the file if changes were made
if ($content -ne $updatedContent) {
Set-Content -Path $filePath -Value $updatedContent
Write-Host "Updated: $filePath"
}
}
This wasn’t perfect, but it got me most of the way there.
Trailing slashes and .html suffixes
Initially I was thinking it would be nice if ‘directory’ (aka ‘index’) URLs just ended with a trailing slash, but actual posts ended with .html
.
But that’s not something supported by Astro. The build.format
configuration property determines how Astro generates index.html
files and refers to them. I chose the file
option.
The other part of this was whether URLs were expected to end with ‘.html’ or just the filename with no suffix. Previously the URLs did include a suffix (and if you requested without a suffix you’d get redirected to the one with one). I’ve changed this now so that URLs don’t have suffixes. The redirection now works the other way and if you request a URL ending in .html then it will switch to the non-suffix one.
The design
While I like to think have one or two artistic bones in my body, I’m the first to confess I’m no expert at web design. For the theme/design/style of the new blog I tried to keep things as simple as possible. I borrowed some styles off the old Jekyll site (courtesy of the F12 browser tools) and then did some minor adjustments to those with the help of GitHub Copilot.
It’s good enough for now, but I can always improve it over time.