从零开始搭建个人博客

Oct 18, 2026

3448 words

17 min read

Uncategorized

Note: This page does not support English, using the default language version

一直想抽空搭一个完全属于自己的个人博客。
前阵子在逛 Astro 官网的主题市场时,一眼就相中了 Momo 这款主题。
它最吸引我的地方就是那股纯白、利落的极简风
没有任何花里胡哨的组件,能让人把心思完全放在文字本身。
此外,Astro 标志性的“孤岛架构”让生成的静态页面几乎没有冗余代码,加载速度快得惊人。

我把这次建站的完整流程记录下来,既作为日后重新配置的参考,也希望能帮到想搭建同款博客的朋友。

第一步:环境准备

安装 Node.js

Node.js® 是一个免费、开源、跨平台的 JavaScript 运行时环境。
Astro 基于 Node.js 开发,因此你需要先安装 Node.js 运行环境。

如果你尚未安装 Node.js:

请访问 https://nodejs.org/ 下载并安装 Node.js 运行环境。
网上有许多详细的 Node.js 安装教程,你可以搜索“Node.js 安装教程”找到适合的指南。

验证安装

安装完成后,打开你的终端,输入以下命令验证安装是否正确:

第一个命令:

Terminal window
node -v

第二个命令:

Terminal window
npm -v

如果看到类似这样的版本号输出,说明安装成功:

v25.6.0 # Node.js 版本
11.9.0 # npm 版本

如果这些命令提示“未找到命令”或显示错误信息,
请重新检查 Node.js 的安装步骤,确保已将 Node.js 添加到系统环境变量中。

关于包管理器(推荐pnpm)

相比npm,为何推荐使用pnpm?它在以下两个方面优势显著:

  1. 极致的安装速度 pnpm采用独特的硬链接机制管理依赖,避免了npm复制文件的操作,
    通常能将依赖安装时间缩短数倍。

  2. 高效的磁盘利用 在pnpm的全局存储模式下,同一个版本的依赖包在磁盘上只会保存一次。
    你创建的所有项目都可以共享这些依赖,从而节省大量磁盘空间。

安装 pnpm 非常简单,只需在终端中执行以下命令即可:

Terminal window
npm install -g pnpm@latest-10

安装完毕后,可通过以下命令来验证是否安装成功:

Terminal window
pnpm -v

如果终端显示出 pnpm 的版本号(例如 10.29.3),就说明 pnpm 已准备就绪。

安装 Git

获取 Momo 主题最推荐的方式是通过 Git,这样方便后续直接拉取源码并同步主题的日常更新。
当然,你也可以直接在 GitHub 仓库页面点击 “Download ZIP” 下载压缩包。

如果选择使用 Git,前往 Git 官网下载安装完成后,可在终端执行以下命令进行验证:

Terminal window
git --version

如果终端正确输出了类似 git version 2.xx.x 的字样,说明 Git 已成功安装。

安装 VS Code

推荐使用 Visual Studio Code 作为编辑器,用来修改配置和撰写文章会更加顺手。

安装完成后,进入博客项目文件夹,右键 →「通过 Code 打开」 即可开始编辑。

第二步:初始化博客

Momo 是一个「开箱即用」的 Astro 博客主题,
不需要复杂的配置和主题合并,克隆下来就能跑。

1. 获取源码

你可以创建一个 Blog 的项目文件夹然后执行:

Terminal window
git clone https://github.com/Motues/Momo.git

2. 安装依赖

克隆完成后双击进入 Momo 文件夹执行:

Terminal window
pnpm install

这一步会自动安装 Astro、Tailwind、Pagefind 等所有依赖。

3. 本地启动

在终端中执行以下命令,启动 Astro 的本地开发服务器:

Terminal window
pnpm dev

启动成功后,终端会输出一个本地访问地址。
打开浏览器访问:

http://localhost:4321/

如果一切顺利,这时候一个博客在本地就算是初始化完成了。

WARNING

重要的事情说三遍!!!
后续所有步骤均需在 Blog\Momo 项目根目录下执行。
重要的事情说三遍!!!
后续所有步骤均需在 Blog\Momo 项目根目录下执行。
重要的事情说三遍!!!
后续所有步骤均需在 Blog\Momo 项目根目录下执行。

第三步:个性化修改

在这个主题原版的基础上,我做了一些个性化修改。
如果你也喜欢同样的风格,可以跟着下面的步骤一起调整,将博客打造得和我完全一致。

1. 安装插件

为了让博客具备完善的 SEO(搜索引擎优化)和极致的加载速度,需要先补充两个底层插件:

  • @astrojs/sitemap:自动生成网站地图,方便搜索引擎抓取你博客的全部文章。
  • @zokki/astro-minify:自动压缩 HTML、CSS 和 JS 代码,进一步压榨页面体积,让加载速度更快。

在终端里先执行 Ctrl + C 停掉刚才的本地服务,然后运行以下命令安装它们:

Terminal window
pnpm add @astrojs/sitemap
Terminal window
pnpm add @zokki/astro-minify

2. 修改配置文件:astro.config.mjs

找到并打开 astro.config.mjs 文件。

为了让刚安装的两个插件生效,需要把它们配置到文件里。

在开头添加 import 导入插件

import sitemap from "@astrojs/sitemap";
import { minify } from '@zokki/astro-minify';

修改 site 为你的域名,
并在 integrations 里找到 svelte() 在后面添加 sitemap(), minify() 调用函数

export default defineConfig({
site: siteConfig.rootSiteUrl || 'https://example.com', // Root URL of site
i18n: {
locales: i18nConfig.supportedLanguages,
defaultLocale: i18nConfig.defaultLanguage,
routing: {
prefixDefaultLocale: false,
redirectToDefaultLocale: false
}
},
integrations: [icon({
include: {
"fa6-brands": ["*"],
"fa6-solid": ["*"],
"simple-icons": ["*"],
"vscode-icons": ["*"],
"material-symbols": ["*"],
"fluent": ["*"],
}
}), svelte(),sitemap(), minify(),

3. 修改配置文件:src/config.ts

修改 title rootSiteUrl 然后把 comments 的 enable 改为 false

export const siteConfig: SiteConfig = {
title: "example", // Title of the site, used in the tab in the browser and in SEO
subTitle: "Blog", // Subtitle of the site
rootSiteUrl: "https://example.com", // Root URL of the site, used for generating absolute URLs for SEO and social sharing
favicon: "/favicon/favicon.ico", // Path of the favicon, relative to the /public directory
pageSize: 6, // Number of posts per page
toc: {
enable: true,
depth: 3 // Max depth of the table of contents, between 1 and 4
},
blogNavi: {
enable: true // Whether to enable blog navigation in the blog footer
},
comments: {
enable: false, // Whether to enable comments
platform: "default", // Comment platform, set "default" to use Momo-backend, also supports "twikoo"
backendUrl: "https://api-momo.motues.top" // Backend URL for comments
},
theme: {
AOS: true, // Whether to enable AOS (Animate On Scroll) for animations
LQIP: true, // Whether to enable LQIP (Low-Quality Image Placeholder) for image placeholders
PhotoSwipe: true, // Whether to enable PhotoSwipe for image viewer
imageCollage: {
enable: true, // Whether to automatically arrange consecutive images into a grid (collage)
maxColumns: 4 // Max images per row in a collage (2 - 6); the actual number is chosen automatically
},
postCard: {
imageMode: "top" // Cover image mode for article cards: "top" shows the image above the content; "background" uses the image as the card background, fading to transparent from right to left
},
photoCover: {
enable: false, // Whether to use a full-screen photo as the background of the home page; the title and subtitle are centered, and everything smoothly returns to the normal style as you scroll down
image: "/cover.jpg", // Photo path: relative to the /public directory if it starts with '/', otherwise relative to the /src directory (e.g. assets/cover.jpg). The blurred placeholder is generated at build time, so there is no small image to prepare by hand
mask: 0.5 // Opacity (0 - 1) of the black mask over the photo, fading away as you scroll down
},
overlayScrollbars: {
enable: true, // Whether to replace the browser's default scrollbar with OverlayScrollbars (overlay style, can auto-hide)
autoHide: "leave", // When to hide the scrollbar: "never" always visible; "scroll" hidden unless scrolling; "move" hidden unless the pointer moves over the page or the user scrolls; "leave" hidden when the pointer leaves the page or the user isn't scrolling
size: 8 // Scrollbar thickness in pixels
}
},
expressiveCode: {
enable: true, // Whether to enable Expressive Code for code blocks; when false, code blocks fall back to plain text without highlighting (same in the CMS preview)
theme: "one-dark-pro" // Shiki theme of code blocks, e.g. "one-dark-pro", "github-dark", "vitesse-dark"; one theme is used for both light and dark mode
}
}

这里只改 indexPage 和 startYear 就行

export const profileConfig: ProfileConfig = {
avatar: "assets/avatar.png", // Relative to the /src directory. Relative to the /public directory if it starts with '/'
name: "example", // Used in the footer of the blog
description: "example", // Used in SEO
indexPage: "https://github.com/example", // The homepage, used in footer and SEO
startYear: 2025, // The year the site was created, used in the footer
}

找到 I18nConfig 修改 title subTitle

export const i18nConfig: I18nConfig = {
defaultLanguage: "zh-cn", // Default language of the site
supportedLanguages: ["zh-cn", "en"], // List of supported languages
translations: { // Translation content for each supported language
"zh-cn": {
Cover: {
title: {
home: "欢迎来到我的博客!",
archive: "文章归档",
about: "关于",
friends: "友链",
},
subTitle: {
home: "example",
archive: "共 {count} 篇文章", // {count} will be replaced with the total number of articles
about: "",
friends: "",
}
}
},
"en": {
Cover: {
title: {
home: "Welcome to My Blog!",
archive: "Archive",
about: "About",
friends: "Friends",
},
subTitle: {
home: "example",
archive: "Total of {count} articles",
about: "",
friends: "",
}
}
}
}
};

4. 修改配置文件:src\components\Header.astro

隐藏 Dark Mode

<!-- Dark Mode
<ThemeIcon class="flex items-center justify-center w-10 h-10 hover:bg-[var(--button-hover-color)] rounded-lg hover:text-current active:scale-90 border border-[var(--button-border-color)] transition duration-300"/>
-->

找到 updateNavBar 里的 const scrolled = y > 0; 修改为 const scrolled = false; 隐藏顶部导航栏跟随

function updateNavBar() {
ticking = false;
const y = window.scrollY;
if (y === lastScrollY) return;
lastScrollY = y;
if (!navBar || !navBarList) return;
const scrolled = false;
navBar.classList.toggle('fixed', scrolled);
// 外壳(描边 / 底色 / 阴影 / 模糊)全部由 --nav-chrome 派生,这里只负责翻状态:
// 0 = 顶部,只有文字与当前页色块(没有边框、没有底色)
// 1 = 吸顶,完整毛玻璃胶囊
// photo-cover.css 会把照片封面页的这个变量换成滚动进度 --photo-p,
// 于是首页是逐帧插值,而不是滚一像素就硬切 —— 所以状态类仍然要照常维护。
// 打在两层上是同一个状态的两个落点:#nav-bar 供 photo-cover.css 覆盖,
// #nav-bar-list 是外壳本身,两行都由这只 updateNavBar() 幂等对账。
navBar.classList.toggle('nav-scrolled', scrolled);
navBarList.classList.toggle('nav-scrolled', scrolled);
}

5. 修改配置文件:src\i18n\language\en.ts

找到 page404 修改 title subTitle errorCode

page404: {
title: "404",
subTitle: "page not found or removed",
backToHome: "Home",
backToPreview: "Previous Page",
errorCode: "Error Code: 404",
notice: "Perhaps you can try:"
},

6. 修改配置文件:src\i18n\language\zh-cn.ts

找到 page404 修改 title subTitle errorCode

page404: {
title: "404",
subTitle: "页面不存在或已被移除",
backToHome: "返回首页",
backToPreview: "返回上一页",
errorCode: "错误代码:404",
notice: "或许你可以尝试:"
},

7. 修改配置文件:src\pages\404.astro

MainPageLayout 替换下面这一段代码

<MainPageLayout title={pageTitle} lang="zh-CN">
<div class="mx-auto w-full max-w-[var(--page-width)] px-4 text-center">
<div class="my-8">
<h1 class="text-7xl md:text-8xl font-bold text-black dark:text-white mb-2">{t("page404.title")}</h1>
<p class="text-xl md:text-2xl text-[var(--text-color-80)]">{t("page404.subTitle")}</p>
</div>
<div class="mt-8 flex flex-col items-center">
<p class="text-[var(--text-color-70)]">{t("page404.notice")}</p>
<div class="mt-4 flex gap-4">
<a href={indexPage}
class="px-6 py-2 border border-[var(--button-border-color)] rounded-lg text-[var(--text-color)] hover:bg-[var(--button-hover-color)] transition-all">
{t("page404.backToHome")}
</a>
<a href="javascript:history.back()"
class="px-6 py-2 border border-[var(--button-border-color)] rounded-lg text-[var(--text-color)] hover:bg-[var(--button-hover-color)] transition-all">
{t("page404.backToPreview")}
</a>
</div>
</div>
</div>
</MainPageLayout>

在完成上述的所有个性化修改后,你就搭建好了属于你自己的博客。
接下来,就是学会如何预览最终打包效果,以及如何开始撰写你的第一篇文章。

第四步:写文章、构建与预览

1. 撰写新文章

Momo 主题内置了快捷命令,可以快速创建新文章。

创建命令:

Terminal window
pnpm momo new <文章路径>
  • <文章路径>:文章的文件夹名,同时也是 slugId

使用示例:

Terminal window
# 创建文章
pnpm momo new hello-world

执行后会自动生成对应的 Markdown 文件:

src/content/blog/hello-world/
└── zh-cn.md

生成的模板内容如下:

---
title: hello-world
pubDate: 2026-10-18
description: ""
image: ""
draft: false
slugId: hello-world
category: ""
pinTop: 0
---
## hello-world
在这里开始写作…

根据实际需求修改 title、description、category 等字段,然后在 ## Title 下方撰写正文即可。

2. 本地打包

文章写完后,在项目根目录下执行:

Terminal window
pnpm build

执行后,Astro 会在根目录生成 dist 文件夹,里面全是优化压缩后的纯静态文件。

3. 生产环境预览

Terminal window
pnpm preview

该命令会启动一个本地静态服务器,完美模拟线上真实环境。
打开浏览器访问:

http://localhost:4321/

在这里可以确认新文章是否正常显示,以及整体效果。
确认无误后,就可以进入下一步
发布到互联网。

第五步:线上部署与域名绑定

这里推荐使用 Cloudflare Static Workers,完全免费且自带全球 CDN 加速。
为了省去配置 Git 的麻烦,我们直接选择上传文件夹功能。

1. 部署步骤

  1. 准备文件:确保本地已执行 pnpm build,此时根目录下会生成一个 dist 文件夹。
  2. 创建项目:登录 Cloudflare 控制台
    点击 「Workers 和 Pages」 -> 「创建应用程序」 -> 「Upload your static files」。
  3. 选择文件夹:点击上传区域的 「文件夹」(folder)按钮,
    在弹出窗口中选中本地的 dist 文件夹,点击上传。

注意:上传之前需要先选择 高级设置 -> 未找到处理 -> 404-page 配置好404页面

  1. 部署站点:等待网页加载完毕后,点击底部的 「部署站点」。

等待上传完成,Cloudflare 就会生成一个免费的 *.workers.dev 网址,博客正式上线!

注意:以后每次写了新文章或修改了配置,都需要在本地重新执行 pnpm build,
并将新生成的 dist 文件夹再次选择上传覆盖。

2. 绑定自定义域名

如果你有自己的域名托管在 Cloudflare,可以让博客看起来更专业:

  1. 进入刚刚创建的 Workers 项目后台,切换到 「自定义域」(Custom domains)标签页。
  2. 点击 「添加域名」,选择你的个人域名然后输入子域名(如 blog.example.com)。
  3. 直接点击确认,系统会自动帮你添加 DNS 解析记录。

绑定成功后,稍等几分钟,你就可以用自己的专属域名访问博客了。

总结

回看整个搭建过程,
从最初的环境配置到最终的线上部署,
核心其实只有三步:配好基础环境、按需微调配置、打包上传托管。

借助 Astro 的极致性能与 Momo 主题的极简设计,我们不仅在本地搭建起了一个纯粹的文字空间,
更通过 Cloudflare Static Workers 让它获得了免费、稳定且全球加速的线上家园。
这种“无数据库、无繁琐后台”的静态方案,完美契合了独立博客的初衷

让技术退居幕后,让文字重回焦点。

至此,博客搭建已正式完工。
在接下来的日子里,剩下的事情就是安安静静地把心思放在内容上。
不妨现在就静下心来,敲下键盘,去记录、去表达、去留住属于你的每一个瞬间。

祝你写作愉快!

从零开始搭建个人博客
https://05740682.de5.net/en/blog/setup-blog/
Author
05740682
Published on
Oct 18, 2026

Enter keywords to start searching