Logo

dev-resources.site

for different kinds of informations.

Astro v5 Blog starter

Published at
12/29/2024
Categories
astro
beginners
webdev
tailwindcss
Author
jldec
Author
5 person written this
jldec
open
Astro v5 Blog starter

Astro v5 blog starter

I recently moved a friend's blog to Astro v5. The motivation behind selecting Astro was its first-class support for markdown content.

With just a minimal amount of boilerplate, Astro will validate markdown frontmatter, generate static pages for each post, and optimize all the images in your posts.

https://astro-v5-blog-starter.jldec.me/blog/first-post

Markdown

---
date: '2024-12-01'
title: 'My First Blog Post'
image:
  src: '../images/birch-trees.webp'
---

## Markdown is

- a lightweight markup language
- for decorating plain text
- with things like headings, lists, links, and blockquotes
- making minimal assumptions about formatting.

#### Here is an inline image:

![sunset](../images/sunset-cambridge.jpg)
Enter fullscreen mode Exit fullscreen mode

HTML

<img
  src="/_astro/birch-trees.DrRha0ED_9bfrU.webp"
  alt=""
  width="2016"
  height="955"
  loading="lazy"
  decoding="async"
  class="w-full h-60 object-cover object-bottom"
/>
<article class="prose mx-auto p-4">
  <h1>My First Blog Post</h1>
  <a href="/">&lt;&lt; Back</a>
  <h2 id="markdown-is">Markdown is</h2>
  <ul>
    <li>a lightweight markup language</li>
    <li>for decorating plain text</li>
    <li>with things like headings, lists, links, and blockquotes</li>
    <li>making minimal assumptions about formatting.</li>
  </ul>
  <h4 id="here-is-an-inline-image">Here is an inline image:</h4>
  <p>
    <img
      alt="sunset"
      width="1343"
      height="683"
      loading="lazy"
      decoding="async"
      src="/_astro/sunset-cambridge.7ZAluiBF_15WAVg.webp"
    />
  </p>
</article>
Enter fullscreen mode Exit fullscreen mode

Starter Repo

Here is the result of extracting these key features into a new blog starter. The repo does not include a lot of design - just the configuration and a minimal amount of code.

https://github.com/jldec/astro-v5-blog-starter

The project includes:

File Structure

β”œβ”€β”€ LICENSE
β”œβ”€β”€ README.md
β”œβ”€β”€ astro.config.mjs
β”œβ”€β”€ package.json
β”œβ”€β”€ public
β”‚Β Β  β”œβ”€β”€ _headers
β”‚Β Β  └── favicon.svg
β”œβ”€β”€ src
β”‚Β Β  β”œβ”€β”€ assets
β”‚Β Β  β”‚Β Β  └── astro.svg
β”‚Β Β  β”œβ”€β”€ components
β”‚Β Β  β”‚Β Β  └── AstroLogo.astro
β”‚Β Β  β”œβ”€β”€ content
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ blog
β”‚Β Β  β”‚Β Β  β”‚Β Β  β”œβ”€β”€ 2nd-post.md
β”‚Β Β  β”‚Β Β  β”‚Β Β  └── first-post.md
β”‚Β Β  β”‚Β Β  └── images
β”‚Β Β  β”‚Β Β      β”œβ”€β”€ birch-trees.webp
β”‚Β Β  β”‚Β Β      └── sunset-cambridge.jpg
β”‚Β Β  β”œβ”€β”€ content.config.ts
β”‚Β Β  β”œβ”€β”€ layouts
β”‚Β Β  β”‚Β Β  └── Layout.astro
β”‚Β Β  β”œβ”€β”€ pages
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ 404.astro
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ blog
β”‚Β Β  β”‚Β Β  β”‚Β Β  └── [id].astro
β”‚Β Β  β”‚Β Β  └── index.astro
β”‚Β Β  └── styles
β”‚Β Β      └── global.css
β”œβ”€β”€ tailwind.config.mjs
β”œβ”€β”€ tsconfig.json
└── wrangler.toml
Enter fullscreen mode Exit fullscreen mode

Markdown driven blog

Markdown blog posts live in src/content/blog.

The schema for the blog collection is defined in content.config.ts. This file also includes utility functions for sorting and filtering posts. E.g. if the draft flag is set, a post will only be included during dev, but not published with the production build.

The home page is defined in src/pages/index.astro which lists posts in date order.

Posts are rendered by the dynamic route src/pages/blog/[id].astro. In order for Astro to pre-render static pages, dynamic routes export a getStaticPaths function which returns a list of params and props for each rendered route.

src/pages/blog/[id].astro

---
import { Image } from 'astro:assets';
import { getCollection, render } from 'astro:content';
import { filterAllPosts } from '~/content.config';
import Layout from '~/layouts/Layout.astro';

export async function getStaticPaths() {
  const posts = await getCollection('blog', filterAllPosts);
  return posts.map((post) => ({
    params: { id: post.id },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await render(post);
---

<Layout title={post.data.title}>
  <Image
    src={post.data.image.src}
    alt={post.data.image.alt || ''}
    class="w-full h-60 object-cover object-bottom"
  />
  <article class="prose mx-auto p-4">
    <h1>{post.data.title}</h1>
    <a href="/">&lt;&lt; Back</a>
    <Content />
  </article>
</Layout>
Enter fullscreen mode Exit fullscreen mode

Image optimization

A src path and alt text can be declared for images in markdown frontmatter, or inline in markdown.

These are passed into the <Image> component which inspects each image, and generates <img> tags with width and height attributes, thereby reducing layout shifts in the browser.

Images are converted to webp format, and stored in dist/_astro with unique (cacheable) names during the build process.

Publishing on Cloudflare Pages

The @astrojs/cloudflare adapter is not needed for static sites.

Cloudflare Pages matches routes with .html files. To avoid trailing slashes, configure the build to generate <route>.html files instead of <route>/index.html.

The _headers file adds cache control headers for immutable content.

Conclusion

Astro v5 is a great choice for a markdown driven blog, as long as you're fine with doing occasional maintenance to update dependencies.

Here are some ideas for future improvements to this starter:

  • Sitemap
  • Menu component for desktop and mobile
  • Nicer fonts
  • Icons for social links

I hope you find this starter useful. Please reach out on X if you have any feedback or suggestions.

astro Article's
30 articles in total
Favicon
Transforming Starlight into PDF: experience and insights
Favicon
Dynamic Routes in Astro (+load parameters from JSON)
Favicon
Import JSON Data in Astro (with Typescript)
Favicon
Use LateX in Astro.js for Markdown Rendering
Favicon
From Legacy to Lightning: Modernizing an Astro App with Daytona
Favicon
Having a Good Ol' RSS Feed in Astro
Favicon
A Date with Daytona: Exploring AstroJS and Sanity CMS
Favicon
Roast my portfolio
Favicon
SvelteKit VS Astro. laidback side by side
Favicon
✍️ Cross-Posting Astro Blog Posts to BlueSky Using GPT-4 🧠
Favicon
The best CMS for Astro: How to choose CMS for Astro projects
Favicon
Integrando MΓΊltiples APIs de Blog en un Sitio Astro: Dev.to y Hashnode
Favicon
Construyendo un Portfolio Moderno con Astro y Tailwind CSS
Favicon
Hybrid Rendering Architecture using Astro and Go Fiber
Favicon
The Single Quote Curse: When AI Mistook an MDX Front Matter Issue for a YAML Bug
Favicon
First impressions of Astro: what I liked and disliked
Favicon
Mysterious Display in Astro: Unraveling the Secrets of the Development Environment
Favicon
Astro v5 Blog starter
Favicon
Letting the product shape the infrastructure
Favicon
Using Angular Inside of Astro
Favicon
AstroJS 5.1: Integra contenido de Dev.to de manera sencilla
Favicon
Less is More: The Case Against Feature-Bloated CMS
Favicon
Add content to your site: Markdown πŸ“
Favicon
Learn how to create an interactive pricing table with Astro JS, Tailwind CSS and Alpine.js
Favicon
So I created Linktree alternative...
Favicon
Debugging failed builds with Netlify
Favicon
API Keys y Variables de Entorno en Astro: GuΓ­a Completa de Seguridad
Favicon
Fighting with Redirects: A Journey of Astro Site Migration
Favicon
Why I Used Astro, Tailwind, and Qwik to Build My Personal Website
Favicon
Creating a Custom Astro Integration: Auto-Publishing to Hashnode

Featured ones: