Destiner's notes

Setting Up a Blog with Astro

29 January 2022

In previous article, I went on my motivation to use Astro instead of other static site generators. Here, I will provide a guide on setting up a blog in Astro with minimal steps. I will cover the essential basics, and guide the next steps.

The fastest way

The fastest way to get started is to go to Astro New page and select a “Blog” template there. You can run the template inside a web sandbox or by cloning the git template.

To better understand how Astro works under the hood, we will now create a project from scratch.

Creating an empty Astro project

Note: before we start, I will introduce a few Astro concepts that will be used across this guide. First, there are Markdown pages, pages that have an .md extension and usually contain the blog post text. Second, there are Astro pages, pages that have an .astro extension and usually serve for unique pages (like index page). Finally, there are Astro layouts, pages that also have an .astro extension which defines how pages with similar structure (e.g. blog posts) should look like.

First, create an empty directory, initialize an NPM project, and install Astro as a dev dependency:

mkdir astro-blog
cd astro-blog
npm init -y
npm i -D astro

In your package.json, add build and dev scripts:

"scripts": {
  "dev": "astro dev",
  "build": "astro build"
},

Now, let’s create an index page:

mkdir src
mkdir src/pages
touch src/pages/index.astro

Open index.astro with a text editor to make a bare bones page:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Blog</title>
  </head>
  <body>
    <main>
      <h1>Hello, Astro!</h1>
    </main>
  </body>
</html>

Finally, let’s start a dev server to view the page:

npm run dev

Go to http://localhost:3000 to see the rendered page!

Creating post layout

Before we jump into making our first post, we need to create a layout for it. The way SSGs work is that for pages with similar structure (e.g. blog posts) you provide a template that will be applied to each page in that list. In Astro, layouts serve that goal. Let’s create a layout:

mkdir src/layouts
touch src/layouts/post.astro

Open post.astro file to create the post layout:

---
const { content } = Astro.props;
const { title } = content;
---

<html lang="en">
  <head>
    <title>{title}</title>
  </head>
  <body>
    <slot />
  </body>
</html>

You can notice that this doesn’t look like normal HTML. Let’s untangle Astro layout syntax one by one.

Note: the syntax described below is similar for Astro components, layouts, and regular Astro pages (all files ending with .astro). The frontmatter part (---) is optional, and what’s below that is a normal HTML with the addition of templating ({ JS_CODE_HERE }) and component slots (<slot />).

First, at the top of the layout, there is something called frontmatter script. It supports both JS and TS and also gives access to Astro.props object which provides component props. In the case of layouts, it will provide you with values that are defined in the Markdown page frontmatter. Here’s an example:

title: My Astro Post
date: 2022-06-01T13:00:00
const { content } = Astro.props;
const { title, date } = content;
console.log(title); // "My Astro Post"
console.log(date); // "2022-06-01T13:00:00"

Variables defined inside the frontmatter script can be used in the layout template, as we will see further.

Second, there is a <title> tag that contains an expression instead of a constant value. Inside layouts, we can execute arbitrary JS by wrapping it into curly braces. In this example, we “print” the value of a variable defined in the frontmatter (title), so that Astro will effectively render page title.

Finally, there is a <slot /> tag. In the context of layouts, a slot provides access to the content of the underlying Markdown page. To put it simply, inserting a slot tag into any part of the layout will render the Markdown page as HTML in that place.

Making a first post

Now that we have a layout for our posts, we can start creating them. Let’s make the first one:

mkdir src/pages/post
touch src/pages/post/first-post.md

Inside first-post.md will be the post content:

---
title: My first post
layout: ../../layouts/post.astro
---

# My first post

This is my first Astro post.

First, we define the post metadata in frontmatter. We also specify the page layout here.

Then, we describe the post content itself using Markdown.

If you open ‌http://localhost:3000/post/first-post, you can see your page live! Note that your page has a title (as shown in the browser tab), which means that your layout was successfully applied.

You can practice a bit and create your second and third pages by copying the first one and adding some changes. Once you save them, they will be available in your browser.

Note: Astro has file-based routing. What that means is that the way that your pages are organized inside the pages directory will translate into relative URL paths of the generated site. For example, a page that is located at src/pages/post/first-post.md will have a /post/first-post URL.

Adding a list of all posts

Currently, the only way to open a page on our site is to paste its exact URL. Thankfully, we can fix that. We will add a list of all posts to our index page.

Inside index.astro, create a frontmatter script with the following content:

const posts = await Astro.glob('./post/*.md');

Then, inside the template, add the following under the <h1> tag:

<ul>
  {posts.map((post) => (
    <li>
      <a href={post.frontmatter.url}>{post.frontmatter.title}</a>
    </li>
  ))}
</ul>

Here, we’re using JSX templating to create a list of links each pointing to the corresponding blog post.

Now your index.astro should look something like this:

---
const posts = await Astro.glob('./post/*.md');
---

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Blog</title>
  </head>
  <body>
    <main>
      <h1>Hello, Astro!</h1>
      <ul>
        {posts.map((post) => (
          <li>
            <a href={post.frontmatter.url}>{post.frontmatter.title}</a>
          </li>
        ))}
      </ul>
    </main>
  </body>
</html>

If you open http://localhost:3000 now, you will see a link pointing to your first post. As you create more posts, they will be automatically added to the list.

Building the site

So far, we were using Astro in dev mode, where the content is served dynamically. This is great for development, but to use our site in production, we will need to build it. Inside your repository, run npm run build to generate your site and npx http-server dist to serve it. This helps preview your site just before deploying it, but generally, you will use dev mode while you are working on your site.

Deploying

Deployment is the process of publishing your site on the Internet for everyone to see it. You can self-host your site, although it’s more convenient to use a hosting provider.

I will use Netlify as an example since the process of deploying is similar across many popular static site hosting services.

The simplest way to deploy your site on Netlify is to use Drop. Simply build your site and update the output folder by drag and drop. Netlify will give you a public link. Congrats, you’ve just deployed your site!

While Drop is useful, it’s very limiting. For example, updating your site will require you to upload build artifacts each time you want to make a change. It’s also doesn’t support custom domains, HTTPS, prerendering, and many other features. To use all of that you will need to create a Netlify site.

First, you will need to create a repository using the git provider of your choice (e.g. GitHub) and upload your source code there. If you don’t want to publish the source code of your site, that’s fine, you can create a private repository.

Second, you will need to create a Netlify site and connect your git repository. During setup, set npm run build as build command and dist as publish directory.

Once Netlify will finish the build, you should be able to access your site. Anyone with the link can see it now! From there, you can add a custom domain, enable SSL, create redirect rules, and much more.


And that’s it. We just went from nothing to a blog built by Astro and deployed by Netlify (or any other hosting). We erred on the side of simplicity here to focus on vital Astro concepts. In future posts, we will look at more advanced stuff.