Setting Up a Blog with Astro
Tags: javascript, webdev, astro
Published: 2022-02-07 01:07:33

In [previous article](https://dev.to/destiner/why-use-astro-for-static-site-generation-l0e), 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](https://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:

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

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

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

Now, let's create an index page:

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

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

```html
<!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:

```bash
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:

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

Open `post.astro` file to create the post layout:

```astro
---
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:

```md
title: My Astro Post
date: 2022-06-01T13:00:00
```

```js
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:

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

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

```md
---
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:

```ts
const posts = Astro.fetchContent('./post/*.md');
```

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

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

Here, we're using [JSX templating](https://reactjs.org/docs/introducing-jsx.html) to create a list of links each pointing to the corresponding blog post.

Now your `index.astro` should look something like this:

```astro
---
const posts = Astro.fetchContent('./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.url}>{post.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](https://app.netlify.com/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.