跳转到内容

Astro + Starlight 个人主页开发速查

这是一份面向当前 jeremy-homepage 项目的开发速查表。项目使用 Astro 7Starlight 0.41:Astro 负责构建、组件和路由,Starlight 负责内容页面、导航、 搜索和文档风格的界面。

在项目根目录执行:

Terminal window
# 安装依赖
npm install
# 按本项目约定,在后台启动开发服务器
npm run astro -- dev --background
# 查看地址和运行状态
npm run astro -- dev status
# 查看开发日志
npm run astro -- dev logs
# 停止后台开发服务器
npm run astro -- dev stop
# 生成生产文件到 dist/
npm run build
# 本地预览生产构建
npm run preview
# 执行 Astro 的类型和内容检查
npm run astro -- check

开发服务器通常使用 http://localhost:4321/。修改 src/ 中的文件后,页面会自动 刷新,一般不需要重启服务。

提交或部署前,至少运行:

Terminal window
npm run build

如果项目安装了 @astrojs/check,再运行:

Terminal window
npm run astro -- check
.
├── public/ # 原样复制的静态资源,例如 favicon、robots.txt
├── src/
│ ├── assets/ # 交给 Astro 处理和优化的图片
│ ├── components/ # 可复用的 .astro 组件(需要时创建)
│ ├── content/
│ │ └── docs/ # Starlight 的 Markdown/MDX 内容页面
│ ├── pages/ # 自定义 Astro 路由(需要时创建)
│ ├── styles/ # 全站或主题样式(需要时创建)
│ └── content.config.ts # Starlight 内容集合及类型规则
├── astro.config.mjs # Astro、Starlight、导航和站点配置
└── package.json # 依赖与 npm 命令

资源放置原则:

  • 页面正文使用的本地图片优先放在 src/assets/,Astro 可以优化和打包它们。
  • 必须保持原文件、固定 URL 的资源放在 public/,例如 public/favicon.svg 对应 /favicon.svg
  • 自己编写的 CSS 和 JavaScript 放在 src/,不要放进 public/,这样构建工具才能 处理和优化它们。

Starlight 会把 src/content/docs/ 中的 .md.mdx 文件生成页面,子目录会 成为 URL 路径的一部分:

src/content/docs/about.md → /about/
src/content/docs/projects/index.md → /projects/
src/content/docs/projects/my-app.md → /projects/my-app/
src/content/docs/notes/astro.md → /notes/astro/

一个常规 Markdown 页面可以这样写:

---
title: 关于我
description: Jeremy 的个人介绍、技术方向和联系方式。
sidebar:
order: 1
---
这里先写页面简介。Starlight 已经使用 `title` 生成了一级标题,
所以正文通常从二级标题开始。
## 经历
正文内容……
## 联系方式
[GitHub](https://github.com/xmlearning)
---
# 必填,同时用于页面标题、浏览器标题和元数据
title: 项目名称
# 推荐填写,用于搜索引擎和社交分享摘要
description: 一句话介绍这个项目。
# 覆盖由文件路径生成的 URL
slug: projects/custom-url
# 草稿只在开发环境出现,不进入生产构建
draft: true
# 是否显示右侧目录,也可以设置标题级别范围
tableOfContents:
minHeadingLevel: 2
maxHeadingLevel: 3
# 控制自动生成侧边栏时的显示
sidebar:
label: 项目名称
order: 2
badge: 新增
hidden: false
---

title 是必填项。个人主页内容建议始终填写 description,它会进入页面元数据。 暂未完成的文章可设为 draft: true

template: splash 会使用无侧边栏的宽布局,适合入口页:

---
title: Jeremy
description: Jeremy 的个人主页
template: splash
hero:
title: 你好,我是 Jeremy
tagline: 我在这里记录项目、思考与学习过程。
image:
file: ../../assets/houston.webp
alt: Jeremy 的主页插图
actions:
- text: 查看项目
link: /projects/
icon: right-arrow
- text: GitHub
link: https://github.com/xmlearning
icon: external
variant: minimal
---

普通文章保留默认的 doc 模板即可。

Starlight 会根据二级和三级标题生成右侧目录,并自动为标题添加锚点。不要在正文重复 写 # 一级标题,因为 Frontmatter 的 title 已经承担这个作用。

## 项目介绍
这是**重点**、这是*强调*、这是 `inline code`
[站内页面](/projects/) · [外部网站](https://example.com)
![图片说明](../../assets/project-cover.png)
:::note
补充背景信息。
:::
:::tip[开发提示]
这里放更高效的做法。
:::
:::caution
这里提醒可能产生问题的操作。
:::
```ts title="src/example.ts"
const message = '代码块支持语法高亮和文件标题';
```
<details>
<summary>展开查看详情</summary>
可以折叠的补充内容。
</details>

旁白可使用 notetipcautiondanger 类型,适合简短提示,不要把大段正文 都放进旁白。

纯文本内容优先使用 .md。需要卡片、步骤、标签页或自定义组件时改用 .mdx

---
title: 我的项目
description: 个人项目列表。
---
import { Card, CardGrid, Steps } from '@astrojs/starlight/components';
## 代表项目
<CardGrid>
<Card title="项目 A" icon="rocket">
项目 A 的简短介绍。
</Card>
<Card title="项目 B" icon="star">
项目 B 的简短介绍。
</Card>
</CardGrid>
## 开发过程
<Steps>
1. 明确问题与目标。
2. 完成实现与测试。
3. 部署并记录复盘。
</Steps>

也可以导入自己的 Astro 组件:

import ProjectCard from '../../../components/ProjectCard.astro';
<ProjectCard title="个人主页" href="https://example.com">
使用 Astro 构建的个人网站。
</ProjectCard>

如果 Starlight 默认的正文样式影响了自定义组件,在组件最外层添加 class="not-content"

可复用的展示块放在 src/components/.astro 文件通常由两部分组成:

  1. 两条 --- 之间是仅在构建或服务端运行的组件脚本。
  2. 下方是输出 HTML 的组件模板。
---
interface Props {
title: string;
href: string;
description?: string;
}
const {
title,
href,
description = '查看项目详情',
} = Astro.props;
---
<article class="project-card">
<h3><a href={href}>{title}</a></h3>
<p>{description}</p>
<slot />
</article>
<style>
.project-card {
padding: 1.25rem;
border: 1px solid var(--sl-color-gray-5);
border-radius: 0.75rem;
}
.project-card h3 {
margin-top: 0;
}
</style>

使用组件:

---
import ProjectCard from '../components/ProjectCard.astro';
---
<ProjectCard
title="Jeremy Homepage"
href="https://github.com/xmlearning"
description="个人主页源码"
>
<p>这里会渲染到组件的 <code>&lt;slot /&gt;</code> 位置。</p>
</ProjectCard>

Astro 组件默认输出静态 HTML,不会把组件运行时代码发送到浏览器。只有确实需要交互时, 再引入 React、Vue、Svelte 等 UI 框架及 client:* 指令;当前项目没有安装这些框架, 不要为了简单的展示组件额外引入它们。

如果页面不适合文档布局,例如作品集首页、时间轴或照片墙,在 src/pages/ 中添加 .astro 文件。Astro 按文件路径自动生成路由:

src/pages/index.astro → /
src/pages/about.astro → /about/
src/pages/projects/index.astro → /projects/
src/pages/projects/[slug].astro → /projects/:slug

Starlight 项目可以同时拥有内容页和自定义页。自定义页若仍想沿用 Starlight 的外观, 可使用 StarlightPage

---
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
---
<StarlightPage
frontmatter={{
title: '作品集',
description: 'Jeremy 的代表项目',
}}
>
<section>
<h2>项目列表</h2>
<p>这里可以使用任意 Astro 模板和组件。</p>
</section>
</StarlightPage>

src/pages/ 中的自定义页不属于 Starlight 的 docs 内容集合,因此不会自动进入 基于内容目录生成的侧边栏;需要在 astro.config.mjs 中用 link 手动添加。

把需要优化的图片放在 src/assets/,然后使用相对于当前文档的路径:

![项目后台界面](../../../assets/project-dashboard.png)

始终填写有意义的替代文本。纯装饰图片可以使用空替代文本 ![](...)

---
import { Image } from 'astro:assets';
import portrait from '../assets/portrait.jpg';
---
<Image
src={portrait}
alt="Jeremy 的头像"
width={480}
loading="eager"
/>

Image 会推断本地图片尺寸并在构建时优化图片。首屏核心图片可以使用 loading="eager";非首屏图片保留默认的懒加载更合适。

public/ 中的图片使用从站点根目录开始的 URL,并由普通 <img> 显示:

<img src="/avatar-static.png" alt="Jeremy 的头像" width="480" height="480" />

Astro 组件中的 <style> 默认只作用于当前组件,适合绝大多数组件样式:

<section class="intro">你好!</section>
<style>
.intro {
font-size: 1.25rem;
}
</style>

需要统一修改 Starlight 主题时,创建 src/styles/custom.css

:root {
--sl-content-width: 52rem;
--sl-color-accent-low: #172554;
--sl-color-accent: #3b82f6;
--sl-color-accent-high: #dbeafe;
}

然后在 astro.config.mjs 的 Starlight 配置中注册:

starlight({
title: "Jeremy's",
customCss: ['./src/styles/custom.css'],
})

优先修改 Starlight 的 CSS 自定义属性;只有属性无法满足设计时,再覆盖具体选择器。 全局 CSS 影响范围大,修改后同时检查浅色、深色和移动端显示。

侧边栏在 astro.config.mjsstarlight({ sidebar: [] }) 中配置。

明确且数量少的核心页面可以手动列出:

sidebar: [
{
label: '主页',
items: [
{ label: '关于我', slug: 'about' },
{ label: '现在', slug: 'now' },
],
},
]

经常增加内容的目录适合自动生成:

sidebar: [
{
label: '项目',
items: [{ autogenerate: { directory: 'projects' } }],
},
{
label: '笔记',
items: [{ autogenerate: { directory: 'notes', collapsed: true } }],
},
{
label: '作品集',
items: [{ label: '自定义作品页', link: '/portfolio/' }],
},
]
  • slug 指向 src/content/docs/ 中的内容页面,不要以 / 开头。
  • link 是 URL,可用于自定义页面和外部链接。
  • autogenerate.directory 对应 src/content/docs/ 下的目录。
  • 自动生成时,可在页面 Frontmatter 的 sidebar.order 中调整顺序。
src/
├── assets/
│ ├── avatar.jpg
│ └── projects/
├── components/
│ └── ProjectCard.astro
├── content/docs/
│ ├── index.mdx
│ ├── about.md
│ ├── now.md
│ ├── projects/
│ │ ├── index.mdx
│ │ └── project-name.md
│ └── notes/
│ └── astro.md
├── pages/
│ └── portfolio.astro
└── styles/
└── custom.css

建议从简单内容开始:能用 Markdown 表达就不写组件,能用 Astro 静态组件完成就不添加 客户端框架。这样页面的 JavaScript 更少,维护和部署也更简单。

  1. 确认文件在 src/content/docs/,扩展名是 .md.mdx
  2. 确认 Frontmatter 包含 title
  3. 检查是否设置了 draft: truesidebar.hidden: true
  4. 如果侧边栏是手动配置的,在 astro.config.mjs 中添加对应 slug
  5. 查看 npm run astro -- dev logs 中的内容校验错误。
  1. src/assets/ 图片应使用相对于文档或组件文件的导入路径。
  2. public/ 图片应使用 /文件名,路径中不要包含 public
  3. 注意 Linux 文件名大小写敏感。
  1. Astro 组件内的 <style> 默认有作用域,不会自动影响子组件内部。
  2. 全站样式需通过 Starlight 的 customCss 注册。
  3. 自定义 MDX 组件被正文样式干扰时,给根元素添加 not-content
  4. 同时检查选择器优先级和浏览器开发者工具中的最终样式。

开发页面能打开不代表生产构建一定通过。运行:

Terminal window
npm run build

根据第一条错误定位文件;常见原因包括无效 Frontmatter、错误的内部链接、缺失图片、 MDX 标签未闭合或导入路径错误。