How I built and organized my blog with Astro JS
Introduction ๐
To provide some context, in 2022, I used Hugo as the static site generator for my blog.
In 2023, I conducted a technological review of various static site generators. This led me to adopt Astro, and I wrote an article about it.
In this blog post, Iโll show you how I organized my code and share my workflows.
From Hugo to Astro ๐ซ
I chose to migrate from Hugo to Astro to gain more control over my blog.
While Hugo is excellent for websites with extensive content like documentation, my needs were different: I wanted to build a comfortable site that reflected my personality.
I preferred Astro for several reasons:
- Hugoโs syntax can be cumbersome: I found the syntax of shortcodes to be quite awkward, especially for generating diagrams. I prefer not to use custom syntax for my needs, as it would make migrating from Hugo more difficult in the future, requiring me to rewrite my content.
- Astro is built with JavaScript and Vite: I am very familiar with these mature, highly customizable technologies that have a large community. Astro also supports TypeScript, a tool I love! This gives me 100% control over how my blog is built, aligning perfectly with the Astro philosophy.
Folder structure ๐ ๏ธ
Letโs dive into my code organization ๐ฎ ! The structure I use looks like this:
Public directory (./public/
)
This directory contains all the files I want to push to the server without any processing.
Assets (./src/assets/
) ๐ผ๏ธ
This directory contains all the compiled assets, such as images and icons.
Components (./src/components/
) ๐งฉ
This directory contains all the components of the website.
I use atomic design to organize my components.
This is why I donโt have a ./src/layouts/
directory, even though it is recommended in the documentation. Instead, all my layouts are in the ./src/components/templates/
directory.
Youโll also notice an index.ts
file, which I use to re-export all the components. And I avoid using export default
to keep the variable names clean.
I style my components with TailwindCSS.
I donโt have CSS files to build my blog. Everything is managed with TailwindCSS, and I am very happy with it! The documentation recommends having a ./src/styles/
directory, but I donโt need it.
Note: to use components with dark mode, I have configured Tailwind like this:
Next, I add the dark
class to the <html>
element. This enables dark mode without needing any contexts or global variables (we reduce dependencies this way)!
Translations (I donโt have any specific directory ๐) ๐๏ธ
To set up internationalization (i18n), I followed this recipe and used the Astro APIs directly.
I forced the URLs to include the language, like โ/en/about-meโ.
If users navigate to โ/โ, they will be redirected to โ/en/โ.
To achieve this, I use this code:
Note: Since I use Apache with a .htaccess
file, I added a 301 redirect header like this:
I donโt have a specific /i18n/
directory for translations. Instead, I use a function to print the correct translation like this:
This approach avoids managing files with numerous key/value translations, as described here.
Content (./src/content/
) ๐
This directory contains all the siteโs content, stored as md
or mdx
files.
Astro natively manages content.
I use these conventions/tools:
- Content files are named with a format like โ2024-08-22-my-slug.md(x)โ. Example:
I use this file naming convention because it automatically sorts posts by date when I look in the file explorer, ensuring the newest content is always at the bottom. However, it has a drawback: releasing two articles on the same day can disrupt the order.
- I use Expressive Code to render code blocks
- I use Mermaid to render diagrams
- Content is typed with TypeScript. You can generate types with Astro with the command:
astro sync
. You can find more information in the documentation
Everything is versioned with Git as part of the source code!
Functions (./src/functions/
) โ๏ธ
All the functions are implemented in TypeScript, which provides strong typing to minimize errors and prevent bugs. Astroโs type-checking (astro check
) generates reports for type errors, enhancing code reliability. Additionally, TypeScript can identify breaking changes introduced by package updates, ensuring smoother maintenance and updates.
This directory contains all functions shared across components. It is organized by type.
All the functions are paired with a corresponding test to ensure thorough testing and to prevent any missing tests. I use Vitest to run these tests.
Youโll also notice an index.ts
file, which I use to re-export all the functions. And I avoid using export default
to keep the variable names clean.
Pages (./src/pages/
) ๐
This directory contains all the routes of my application. These files serve two main roles:
- Prepare the routing using the
getStaticPaths
function. - Execute queries to fetch content, images, and translations (if needed).
You can also notice a _routes.ts
file. This file is not present in the dist
folder. It simply re-exports the routes and connects similar pages together. This is particularly useful in the navbar for language switching. For example, if you are on the /en/about-me/
page and want to switch to French, this dictionary helps query the corresponding French page (in this case, /fr/a-propos/
).
Plugins ๐
This directory contains the plugins and integrations I want to add. For example, I have a mermaid
integration. You can find more information here.
Code Tools ๐ง
I donโt use many code tools. I primarily use git
to version the code and the blog content.
Node Packages ๐ฆ
Here is the list of the Node packages I use:
- Astro Integration:
astro
,astro-expressive-code
,@astrojs/alpinejs
,@astrojs/check
,@astrojs/markdown-remark
,@astrojs/mdx
,@astrojs/rss
,@astrojs/sitemap
,@astrojs/tailwind
- TypeScript:
typescript
,@types/alpinejs
,@types/node
- TailwindCSS:
tailwindcss
,@tailwindcss/aspect-ratio
,@tailwindcss/forms
,@tailwindcss/typography
,clsx
- Alpine:
alpinejs
- Knip (detect unused code):
knip
- Mermaid (draw diagrams):
mermaid
,unist-util-visit
- Prettier (format the code):
prettier
,prettier-plugin-astro
,prettier-plugin-astro-organize-imports
,prettier-plugin-tailwindcss
- Vitest (run tests):
vitest
TypeScript configuration ๐น๐ธ
Here is my TypeScript configuration:
I use the strictest configuration to adhere to good coding practices and avoid bugs.
I have to exclude the dist
folder; otherwise, it crashes for some reason with Mermaid JS.
Prettier configuration โจ
Workflows ๐
In the package.json
file, I have several scripts to handle the building of the site:
In the Makefile
, I have higher level helpers:
Choices ๐ญ
I want to depend to the less node packages as possible.
I am using Alpine integration to manage user interactions. Before, I used Svelte, but I got difficulties to manage translations, display resized images, and implementing Markdown syntax highlighting. With Alpine, I can use even in .astro
file, so I can have the full Astro API.
To make my website look like an SPA, I can use the transition API: (https://astro.build/blog/future-of-astro-zero-js-view-transitions/)
No big framework is needed !
In the future: whatโs next? โณ
Looking ahead, I have several plans to evolve my website:
- Design Improvements: I aim to enhance the design of my website.
- Component UI Page: I have a UI page to check my components. Iโm considering integrating it with StoryBook once an integration becomes available. The progress can be followed here.
- Astro 5: with Astro 5 on the horizon, Iโm excited to see how it evolves. Some file scripts might become obsolete, simplifying the code further?
- Tailwind 4: the release of Tailwind 4 is also on the horizon.
- Code Hike Compatibility: Iโm hopeful that libraries like Code Hike will become compatible with Astro. You can read more about it here.
Letโs see what the future holds! ๐ฎ
Atomic distribution - Fedora Silverblue - Technological watch
Learn what is an Atomic distribution in less than 5 minutesย !
My feedbacks about Static Site Generator
Here, I will present you my feedbacks about Static Site Generator
Atomic design - Technological watch
Learn what is the atomic design in less than 5 minutesย !
Redis - Technological watch
Learn what is Redis in less than 5 minutesย !