I created this blog a little over a year ago, and I’ve hardly added any content to it since then, contrary to what I would have liked. However, I have completely reworked the way it is built, migrating from Nuxt 3 to Astro.
Why migrate?
I had a lot of bugs with Nuxt 3 (on static generation, on i18n, on images, etc.). Each time I dug a little deeper, the cause was inextricable or dependent on a poorly or badly maintained package.
While digging out one of these bugs on the nuxt-i18n community module, I came across a comment exchange from @riderx who obviously had had enough and put a $300 bounty to migrate his site to Astro. The creator of Nuxt even stepped in to find out more: https://github.com/LeducIT/captime-website/issues/47.
I have the impression that Nuxt turned away from the static generation usage I needed when it was upgraded to version 3, so I decided to migrate to Astro as well.
PS: I also tested https://islandjs.dev, but it seems to have a smaller community, and the simplicity of a blank Astro project appealed to me, there’s less “magic”.
As for styling, I’m sticking with my previous choice of TailwindCSS.
How it works
There are three types of content on the site:
- pages: these are
*.astro
files in thesrc/pages/
directory. - posts: these are
*.mdx
files in thesrc/content/blog
directory. - i18n: this is a large javascript object containing all the phrases and words in the pages, located in the
src/i18n/index.ts
file.
Pages
Each page uses a layout located in src/layouts/Layout.astro
which defines the elements common to all pages.
I produce an English version and a French version by means of a parameter named [lang]
retrievable from the page with const { lang } = Astro.params
, so that the languages are generated statically, I export a getStaticPaths
function in each page that lists the languages.
Posts
The *.mdx
files are used by the src/pages/[lang]/blog/[slug].astro
file, where slug
is the name of the slugged *.mdx
file. These files are divided into two folders fr
and en
located in src/content/blog/
, each containing the French and English versions of the same articles.
i18n
As Astro doesn’t provide a mechanism for interpolation, and available libraries such as i18next are too cumbersome for my taste, I’ve developed a few functions used for the project, but these will certainly have to be rewritten in the future as the current state is unsatisfactory.
Features
Sitemap
A sitemap is generated automatically via the official integration @astrojs/sitemap
, enabling Google to index the site’s pages.
I also generate the robots.txt
via an endpoint.
RSS
An RSS feed is generated and made available for each language via the endpoint src/pages/[lang]/rss.xml.ts
. For the current language, the link is ../../rss.xml.
Change language
A language selector allows you to change languages dynamically. It’s coded with Alpine.js, which I didn’t know existed, and allows you to write a bit of reactive code in components without using a gas factory like React or Vue.
OpenGraph tags
Inspired by this article on programmatic generation of OpenGraph images with Satori from title, date and description, I developed something similar by:
- creating an Astro component
MetaOGImage.astro
that takes an image, title, description and date. - this component then uses Satori to convert a React component to the dimensions of the OpenGraph image to produce an SVG, then resvg-js to produce a PNG.
- this image in PNG format is then saved in a
public/og
directory (which is in.gitignore
). - an integration copy at the end of build copies the contents of this directory into the build folder (because Astro doesn’t allow a page to render a second file).
To see the implementation
Articles written in MDX
To be able to use components directly in the articles of this blog, the format used is MDX via the plugin @astrojs/mdx.
Conclusion
There are still a number of improvements to be made to the blog, so if you have a problem, feel free to open an issue on Github.