使用 Astro 快速搭建自己的博客系统

Astro 是一款现代化的前端框架,由开发团队 Snowpack 创建,旨在提供一种简单而强大的方式来构建快速、可靠且易于维护的 Web 应用程序。
Astro 支持静态站点生成,这意味着在构建时生成 HTML 文件,从而提高网站的加载速度和性能。

今天我们主要讲述如何使用 Astro 快速搭建自己的博客系统。

1. 环境准备

  1. 需要先安装 nodejs v18.17.1 或 v20.3.0 更高版本
  2. 文本编辑器——推荐使用带有官方 Astro 扩展的 VS Code。
  3. 命令行终端- 通过 Astro 的命令行界面 (CLI) 访问。

2. 创建一个 Astro 项目

这里推荐使用 pnpm 作为 node 包管理工具,如果您习惯 npm or yarn 可自行调整命令行指令及参数。

2.1. 使用命令行向导创建项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

$ pnpm create astro@latest
.../191d395dcd8-40343 | +59 ++++++
.../191d395dcd8-40343 | Progress: resolved 59, reused 27, downloaded 32, added 59, done

astro Launch sequence initiated.

dir Where should we create your new project?
./density-dwarf

tmpl How would you like to start your new project?
Use blog template

ts Do you plan to write TypeScript?
Yes

use How strict should TypeScript be?
Strict

deps Install dependencies?
Yes

git Initialize a new git repository?
Yes

✔ Project initialized!
■ Template copied
■ TypeScript customized
■ Dependencies installed
■ Git initialized

next Liftoff confirmed. Explore your project!

Enter your project directory using cd ./density-dwarf
Run pnpm dev to start the dev server. CTRL+C to stop.
Add frameworks like react or tailwind using astro add.

Stuck? Join us at https://astro.build/chat

╭─────╮ Houston:
│ ◠ ◡ ◠ Good luck out there, astronaut! 🚀
╰─────╯

2.2. 使用模板创建项目

官方 templates 可以在这里找到 astro examples

1
2
3
4
5
6
7
8
9

# 使用官方模板创建项目
pnpm create astro@latest --template <example-name>

# 使用第三方模板创建项目
pnpm create astro@latest --template <github-username>/<github-repo>
# 或者
git clone https://github.com/<github-username>/<github-repo> myProjectName

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

$pnpm create astro@latest --template surjithctly/astroship

astro Launch sequence initiated.

dir Where should we create your new project?
./purple-plasma
◼ tmpl Using surjithctly/astroship as project template

ts Do you plan to write TypeScript?
Yes

use How strict should TypeScript be?
Strict

deps Install dependencies?
Yes

git Initialize a new git repository?
Yes

✔ Project initialized!
■ Template copied
■ TypeScript customized
■ Dependencies installed
■ Git initialized

next Liftoff confirmed. Explore your project!

Enter your project directory using cd ./purple-plasma
Run pnpm dev to start the dev server. CTRL+C to stop.
Add frameworks like react or tailwind using astro add.

Stuck? Join us at https://astro.build/chat

╭─────╮ Houston:
│ ◠ ◡ ◠ Good luck out there, astronaut! 🚀
╰─────╯

3. 开发环境启动 Astro

Astro 带有内置开发服务器,其中包含项目开发所需的一切。astro dev命令将启动本地开发服务器,以便您首次看到新网站的运行情况。

每个入门模板都附带一个可astro dev为您运行的预配置脚本。导航到您的项目目录后,使用您最喜欢的包管理器运行此命令并启动 Astro 开发服务器。

1
2
3
4
5
6
7
8
9
10
11
12

$ pnpm dev

> purple-plasma@2.2.0 dev /path-to-astro-project
> astro dev


astro v4.8.7 ready in 395 ms

┃ Local http://localhost:4321/
┃ Network use --host to expose

然后浏览器打开http://localhost:4321/

4. 项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

/
├── public/
│ └── ...
├── src/
│ ├── components/
│ │ └── ...
│ ├── layouts/
│ │ └── ...
│ └── pages/
│ └── ...
│ ├── content
│   │   ├── blog
│   │   │   ├── example-page-a.md
│   │   ├── config.ts
│   │   └── team
│   │   ├── example-page-b.md
│   │   ├── example-page-c.mdx
└── package.json

Astro 会在在 src/pages/ 目录中查找 .astro 或 .md 文件, 在编译期间将其渲染称 html 页面。每个页面都根据其文件名显示为一个路由。

任何静态文件(如图像)都可以放在 public/ 目录中。

5. 创建第一篇博文

通常情况下在 src/content 下有一些预设的目录,如果将 markdown 格式的博客文章,放置在预设的目录下, 并配置好合适的 front-matter,

在开发模式下使用, 例如https://localhost:4321/blog/example-page-a就能访问。

5.1. create a new content Collection

如果你想在 src/content 添加新的目录结构用于分门别类的放置自己的博客文章, 此时需要创建新的content collection,此时就需要修改配置 config.ts,然后在 src/pages 下创建新的页面。

例如我想在 src/content 在创建一个 ansible 的目录用于存放 ansible 相关的文章。

首先我需要在 src/content 下创建 ansible 目录;
然后我需要修改 config.ts,添加 ansible 相关的配置;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const ansibleCollection = defineCollection({
//创建一个新的ansibleCollection
schema: z.object({
draft: z.boolean(),
title: z.string(),
snippet: z.string(),
image: z.object({
src: z.string(),
alt: z.string(),
}),
publishDate: z.string().transform((str) => new Date(str)),
author: z.string().default("Astroship"),
category: z.string(),
tags: z.array(z.string()),
}),
});

// 3. Export a single `collections` object to register your collection(s)
// This key should match your collection directory name in "src/content"
export const collections = {
blog: blogCollection,
team: teamCollection,
ansible: ansibleCollection, // export ansibleCollection
};

然后要创建 ansible 的主页面 src/pages/ansible.astro,这样当用户访问https://localhost:4321/ansible就不会是空白页面或者出现 404 页面找不到的问题

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
---
import { getCollection } from "astro:content";
import { Picture } from "astro:assets";
import Layout from "@layouts/Layout.astro";
import Container from "@components/container.astro";
import Sectionhead from "@components/sectionhead.astro";

// Filter ansible entries with 'draft: false' & date before current date
const publishedAnsibleEntries = await getCollection("ansible", ({ data }) => {
return !data.draft && data.publishDate < new Date();
});

// Sort content entries by publication date
publishedAnsibleEntries.sort(function (a, b) {
return b.data.publishDate.valueOf() - a.data.publishDate.valueOf();
});
---

<Layout title="Ansible">
<Container>
<Sectionhead>
<Fragment slot="title">Ansible</Fragment>
<Fragment slot="desc">
We write about building startups and thoughts going on our mind.
</Fragment>
</Sectionhead>
<main class="mt-16">
<ul class="grid gap-16 max-w-4xl mx-auto">
{
publishedAnsibleEntries.map((ansiblePostEntry, index) => (
<li>
<a href={`/ansible/${ansiblePostEntry.slug}`}>
<div class="grid md:grid-cols-2 gap-5 md:gap-10 items-center">
<Picture
src={ansiblePostEntry.data.image.src}
alt={ansiblePostEntry.data.image.alt}
sizes="(max-width: 800px) 100vw, 800px"
width={800}
height={600}
loading={index <= 2 ? "eager" : "lazy"}
decoding={index <= 2 ? "sync" : "async"}
class="w-full rounded-md object-cover object-center bg-white"
/>
<div>
<span class="text-blue-400 uppercase tracking-wider text-sm font-medium">
{ansiblePostEntry.data.category}
</span>

<h2 class="text-3xl font-semibold leading-snug tracking-tight mt-1 ">
{ansiblePostEntry.data.title}
</h2>

<div class="flex gap-2 mt-3">
<span class="text-gray-400">
{ansiblePostEntry.data.author}
</span>
<span class="text-gray-400"></span>
<time
class="text-gray-400"
datetime={ansiblePostEntry.data.publishDate.toISOString()}>
{ansiblePostEntry.data.publishDate.toDateString()}
</time>
</div>
</div>
</div>
</a>
</li>
))
}
</ul>
</main>
</Container>
</Layout>

最后要创建一个博客文章的渲染页面
例如: src/pages/ansible/[slug].astro

内容可以参考下面的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
---
import { getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Container from "@components/container.astro";

// Generate a new path for every collection entry
export async function getStaticPaths() {
const ansibleEntries = await getCollection("ansible");
return ansibleEntries.map((entry) => ({
params: { slug: entry.slug },
props: { entry },
}));
}

// Get the entry directly from the prop on render
const { entry } = Astro.props;
const { Content } = await entry.render();
---

<Layout title={entry.data.title}>
<Container>
<div class="mx-auto max-w-3xl mt-14">
<span class="text-blue-400 uppercase tracking-wider text-sm font-medium">
{entry.data.category}
</span>
<h1
class="text-4xl lg:text-5xl font-bold lg:tracking-tight mt-1 lg:leading-tight">
{entry.data.title}
</h1>
<div class="flex gap-2 mt-3 items-center flex-wrap md:flex-nowrap">
<span class="text-gray-400">
{entry.data.author}
</span>
<span class="text-gray-400"></span>
<time
class="text-gray-400"
datetime={entry.data.publishDate.toISOString()}>
{entry.data.publishDate.toDateString()}
</time>
<span class="text-gray-400 hidden md:block"></span>
<div class="w-full md:w-auto flex flex-wrap gap-3">
{
entry.data.tags.map((tag) => (
<span class="text-sm text-gray-500">#{tag}</span>
))
}
</div>
</div>
</div>

<div class="mx-auto prose prose-lg mt-6 max-w-3xl">
<Content />
</div>
<div class="text-center mt-8">
<a
href="/ansible"
class="bg-gray-100 px-5 py-3 rounded-md hover:bg-gray-200 transition"
>← Back to ansible</a
>
</div>
</Container>
</Layout>

最终,我们放置一篇文章在 src/content/ansible 下面,内容如下,当我们打开https://localhost:4321/ansible/first-page 就可以正常访问了。

vi src/content/ansible/first-page.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
---
title: 运维自动化之Ansible
snippet: "Ornare cum cursus laoreet sagittis nunc fusce posuere per euismod dis vehicula a, semper fames lacus maecenas dictumst pulvinar neque enim non potenti. Torquent hac sociosqu eleifend potenti."
draft: false
toc: true
name: "Robert Palmer"
avatar:
{
src: "https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?&fit=crop&w=280",
alt: "Robert Palmer",
}
image:
{
src: "https://images.unsplash.com/photo-1593720213428-28a5b9e94613?&fit=crop&w=430&h=240",
alt: "full stack web development",
}
publishDate: "2022-11-08 11:39"
category: "Tutorials"
tags:
- linux
- Ansible
categories:
- devops
- ansible
reward: true
---

我的第一篇博客

6. 如何发布博客

astro 支持的发布平台有很多,例如:Netlify, Vercel, Github pages, gitlab pages, Cloudflare pages, Heroku, AWS, Google cloud 等等。

今天我们以 github pages 为例,讲解如何将自己的博客发布到 github pages。

6.1. 配置站点

修改配置

astro.config.mjs

1
2
3
4
5
6
// https://astro.build/config
export default defineConfig({
site: "https://your_website_domain",
base: 'your-repo',
});

site:

站点的值必须为以下值之一:

以下 URL 基于您的用户名:https://.github.io
为 GitHub 组织的私人页面自动生成的随机 URL:https://.pages.GitHub.io/

base:
可能需要一个 base 值,以便 Astro 将您的存储库名称(例如/your-repo)视为您网站的 base。

设置自定义域

您可以通过添加以下内容来设置自定义域/将 public/CNAME 文件添加到您的项目:

public/CNAME
sub.mydomain.com

这将在您的自定义域而不是 user.github.io 部署您的网站。别忘了为您的域提供商配置 DNS。

6.2. 发布站点

发布之前,先编译

1
2
3

pnpm build

编译后将在 dist 目录生成网站所有静态资源文件。然后将其发布到 github 上。

1
2
3
4
5
6
7
8
9
10

git init
git add .

git commit -m "initial commit"
# 添加 repo
git remote add origin <https://github.com/><username>/<repository>.git
# 这里借助angular的ghpage cli将生成的内容发布到github
npx angular-cli-ghpages --dir=dist/

7. 配置 Astro 编辑器

对于 vscode 编辑器, 可以安装插件 astro-build.astro-vscode

1
2
3

code --install-extension astro-build.astro-vscode

其他编辑器,可以参考:

Astro Editor Setup

7.1. 自动格式化 astro 文档

首先安装 prettier 和 prettier astro 插件

1
2
pnpm i --save-dev prettier prettier-plugin-astro

修改 vscode settings.json

1
2
3
"[astro]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},

修改配置 .prettierrc 覆盖 prettier 默认的 parser 为 astro

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"plugins": ["prettier-plugin-astro"],
"overrides": [
{
"files": "*.astro",
"options": {
"parser": "astro"
}
}
],
....
}

参考How to automatically format Astro files in VS Code using Prettier

8. 参考文档

Start a new Astro project

Astro deploy

Astro Editor Setup

Astro Introduction

使用 Astro 快速搭建自己的博客系统

https://pengtech.net/astro/astro_install_and_configure.html

作者

鹏叔

发布于

2024-09-09

更新于

2024-09-13

许可协议

评论