Hello World

Hello World

•约 3.6 千字

Hello World 是 Hexo 创建时就会生成的一篇文章,标题沿用到现在,在很久之前就标记为草稿不再构建。到现如今更新了,将其作为渲染管线的自检页:Markdown 写进来之后不会直接输出,@content-collections 先解析 Frontmatter,mdx-bundler 把正文编译成 MDX,中间依次挂上 remark-gfm、rehype-slug 和 rehype-mermaid,最后由 Next.js 静态渲染,代码块交给 Shiki。

下面按语法类别,把这条管线能遇到的写法过一遍,顺便记下每一条当前的实际表现。每次换插件或者调配置,都会回到这里看看哪一段的输出变了。

另外,有些写法虽然合法,但会被仓库的 prettier 改写成别的形式,本文不测这些写法,原因列在文末。

一、标题

标题由 Frontmatter 的 title 渲染,正文本来不该再写一级标题。这里把 H1 到 H6 全列出来,只是为了确认组件映射没有漏掉哪一级。

一级标题 H1

锚点不会支持 H1

二级标题 H2

三级标题 H3

四级标题 H4

五级标题 H5
六级标题 H6

每个标题的 id 由 rehype-slug 生成,页面上的锚点靠它。

Setext 标题

Setext 一级标题

即使是 Setext 标题,一级也不支持锚点

md
Setext 一级标题
==============

Setext 二级标题

标题边界

####### 七个井号不是标准标题

#标题后没有空格时通常不是标题

二、段落与换行

段落之间空一行,这一点没有例外。只按一次回车算软换行,渲染后会和上一行接在同一段里:

这句话末尾只按了一次回车。 它和上一句属于同一个段落。

硬换行有行尾两个空格和行尾反斜杠两种写法。前者看不见那两个空格,很容易被编辑器或格式化工具清掉;本文统一用反斜杠:

这一行末尾是反斜杠
同样断开了。

三、强调

星号和下划线等价,叠三个就是粗斜体,GFM 另外补了删除线。

  • 双星号加粗
  • 双下划线加粗
  • 单星号斜体
  • 单下划线斜体
  • 三星号粗斜体
  • 三下划线粗斜体
  • 删除线
  • 行内代码

混排时只要不越界,各写各的:

  • 加粗里放 代码 和 斜体
  • 斜体里放 加粗 和 删除线
  • 中文紧贴着加粗,英文写成 wordinsideword,用来确认单词内部的星号不会乱咬
  • 行内代码里的标记一律不生效:**not bold** _not italic_ [not link](#)
  • 想在里面再放反引号,外壳用两个:Use `code` inside inline code

四、引用

这是第一层引用,可以连着写很多行。 中间不空行,它们就属于同一个引用块。

引用里也能用加粗、斜体 和 代码。

嵌套就是再套一层尖括号:

第一层

第二层

第三层

引用里放列表和代码块也没问题:

  • 引用中的无序列表
  • 第二项
ts
const quoted = true

高亮块

本站给引用加了一个标记:块首写一行 [!HIGHLIGHT color=...],构建时 formatHighlights 会认出它,把这行删掉,并给 blockquote 挂上 data-highlight 属性。颜色可选 yellow、blue、green、red、purple,不写就是蓝色。

这是一个蓝色高亮块,里面照常能用 Markdown。

  • 可以放列表
  • 也可以放链接

不写颜色,默认蓝色。

颜色也接受六位十六进制值。这时属性会写成 data-highlight-color="custom",具体颜色通过 CSS 变量传进去:

这是一个自定义颜色的高亮块。

标记行和正文之间要留一行空的 >,让它们成为两个独立段落。忘了留,[!HIGHLIGHT] 会和正文挤成一段,直接显示在页面上。不认得这个约定的渲染器会把它退化成普通引用块,颜色没了,文字还在。

五、列表

无序列表嵌套

  • 一级项目 A
  • 一级项目 B
    • 二级项目 B-1
    • 二级项目 B-2
      • 三级项目 B-2-a
      • 三级项目 B-2-b
  • 一级项目 C

有序列表

  1. 第一步
  2. 第二步
  3. 第三步
    1. 第三步的子项一
    2. 第三步的子项二
  4. 第四步

起始编号

  1. 从 7 开始
  2. 自动往下排
  3. 这里写的 9,因为会被格式化,但即使不格式化写 10 也应该显示 9

有序与无序混排

  1. 准备工作
    • 检查环境
    • 安装依赖
  2. 执行
    • 运行脚本
      1. 子步骤一
      2. 子步骤二

列表项里的段落和代码

  • 第一段。

    同一个列表项里的第二段,缩进要和文字对齐。

  • 带代码块的列表项:

    bash
    npm run build

任务列表

  • 待办事项
  • 已完成的事项
  • 带子任务的事项
    • 子任务已完成
    • 子任务未完成

复选框由 GFM 生成,本站渲染时会带上 disabled,所以只能看,不能点。GFM 也认大写 X,但 prettier 会统一成小写,本文只用小写。

六、代码

行内代码用反引号包住,里面的 **、[] 都不会被解析。

围栏代码块的语言标识决定 Shiki 用哪套高亮。目前装了 asm、bash、c、go、http、ini、javascript、json、protobuf、ruby、sql、ssh-config、toml、tsx、typescript、vue 和 yaml,另外认 ts、js、sh、yml、proto 这类别名。写别的语言不会报错,只是按纯文本处理。

typescript
function greet(name: string) {
  const message = `Hello, ${name}!`
  console.log(message)
  return message
}

greet('World')
go
package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

在语言标识后面跟一个文件名,代码块顶部就会显示它。这一步由 formatCode 完成,它把围栏的 meta 直接塞进 code 元素的 filename 属性:

src/content/collections.ts
ts
export const post = z.object({
  title: z.string(),
  category: z.string(),
  keywords: z.array(z.string()).optional(),
})

顶部那一栏里,文件名居中,语言在右上角,旁边是复制按钮。

缩进四个空格也能生成代码块,只是没法指定语言:

四个空格缩进也可以形成代码块 const indented = true;

围栏也能用波浪线代替反引号,效果一样,但 prettier 会统一成反引号,本文只用反引号:

json
{
  "name": "vacuum",
  "markdown": true
}

七、链接与图片

链接

图片

正文图片由 Image 组件渲染,默认懒加载,并关掉拖拽:

封面

标准语法可以加上标题 ![图片](https://o2x.net/0xf2/s4b5K1B8QsyJIRyV4MD0qQ.jpg '封面') 但是没有实现,或许后面考虑实现它。

引用式写法可以省掉重复的长 URL:

引用式图片

标准 Markdown 没有尺寸语法,要指定显示大小只能写成 <img>,width 和 height 按像素算,不过我的实现中已经指定了 width: auto,所以并不能通过这种方式指定。

八、表格

基础表格

语言用途特点
Python数据分析与脚本语法简洁,生态丰富
Rust系统与高性能服务内存安全,没有垃圾回收
TypeScript前端与全栈开发给 JavaScript 补上静态类型
Go云原生与后端服务并发模型简单,编译快

列对齐

左对齐居中对齐右对齐
leftcenterright
文本文本文本
abbccc

单元格里的格式

类型示例备注
加粗bold行内语法
代码const x = 1行内代码
链接example单元格链接
转义竖线a | b显示一条竖线

九、分割线

分割线写作三个及以上连字符:


星号和下划线也能当分割线,但 prettier 会统一成 ---,本文只演示这一种。

十、转义字符

反斜杠能把特殊字符还原成普通字符:

  • *不会变成斜体*
  • _不会变成斜体_
  • # 不会变成标题
  • `不会变成代码`
  • [不会变成链接](https://example.com)
  • !不会变成图片
  • > 不会变成引用
  • - 不会变成列表
  • + 不会变成列表
  • \1. 不会变成有序列表
  • 反斜杠本身写作 \\

十一、解析边界

列表还是年份

数字加句点会被当成有序列表,年份得转义:

1986. 这是一年,不是列表项。

  1. 这才是列表项

列表项后面的懒续行仍然属于同一个列表项,空行才会把它断开:

  • 第一行 这是同一个列表项的续行。

    这是同一个列表项里的第二个段落。

  • 下一个列表项

围栏嵌套

外层用四个反引号,里面的三个就不会提前收尾:

markdown
```ts
const nestedFence = true
```

链接目标的边界

空单元格

左空中空右空
BC
AC
AB

十二、GFM 扩展

删除线

这段文字被划掉了。

自动链接

链接和邮箱不用写成 Markdown 链接也能识别:访问 https://github.com,或者发邮件到 hi@example.com。

尖括号那种写法在 MDX 里要当心,<https://example.com> 可能被当成 JSX 标签,直接用上面的字面量形式更省事。

脚注

GFM 的脚注在这里可用,正文里的角标会跳到文末的定义。1

定义列表

定义列表不属于 CommonMark,也不在 GFM 里,本站没有对应插件,下面两行会原样显示成普通段落:

术语 : 定义内容

十三、HTML、实体与 MDX

HTML 块与行内标签

MDX 允许直接写 HTML,它会当作 JSX 处理:

展开

段落里有 HTML 加粗 和 行内代码。

行内标签也能和 Markdown 混排:按 Command + K,以及 高亮文本。

实体与尖括号

  • 命名实体:&amp; → &,&lt; → <,&copy; → ©
  • 数字实体:&#35; → #,&#x1F600; → 😀
  • GFM 自动链接字面量:https://example.com/path?q=markdown&lang=zh
  • 转义之后只是普通文本:<not-a-tag>content</not-a-tag>

花括号

Markdown 里花括号就是普通字符,MDX 会把它当成表达式,想显示原文得转义:{ key: "value" }。代码里的花括号不受影响:const value = { nested: true }。

十四、图表

Mermaid 交给 rehype-mermaid 处理,构建时用 Playwright 渲染成内联 SVG,页面里不需要额外的脚本。CI 专门装 Chromium 就是为这一步。

流程图

是否开始条件判断执行操作跳过结束

时序图

浏览器构建流程作者浏览器构建流程作者提交 Markdown渲染 Mermaid SVG输出静态页面显示图表

甘特图

2026-01-012026-01-032026-01-052026-01-072026-01-092026-01-112026-01-132026-01-152026-01-172026-01-192026-01-212026-01-232026-01-252026-01-272026-01-292026-01-312026-02-012026-02-03需求分析 原型设计 编码实现 测试 设计开发项目计划

饼图

55%30%15%语言占比TypeScriptRustCSS

思维导图

思维导图没有单独语法,还是写在 mermaid 代码块里,用缩进表示层级,root(( )) 是中心主题:

vacuum内容MarkdownMDX图片构建Content CollectionsMermaid 预渲染Shiki部署GitHub ActionsCloudflare Pages

括号形状对应节点形状:(( )) 圆形、( ) 圆角、[ ] 方形、{{ }} 六边形。

学习计划语言英语日语运动游泳爬山技术前端ReactTypeScript后端RustTauri

十五、没有测试的写法

下面这些写法本身合法,解析器大概率也认得,但仓库用 prettier 统一 Markdown 格式,pnpm lint 里的 format/prettier 会把它们改写成另一种形式。为了不和格式化结果打架,本文直接不写这些形式:

  • 行尾两个空格的硬换行:prettier 会删掉行尾空白,硬换行统一写成反斜杠。
  • 无序列表的 * 和 + 标记:prettier 可能把它们改成 -,本文统一用减号。
  • 任务列表里的大写 [X]:会被改成小写。
  • 波浪线围栏 ~~~:会被换成反引号。
  • *** 和 ___ 分割线:会被换成 ---。
  • 链接目标里不加尖括号的括号,以及空目标 ():prettier 会补上或改写成尖括号。
  • 省略首尾竖线的表格:prettier 会补全竖线。

这一页只收录格式化之后仍然稳定的写法,所以它同时是一份渲染测试和一份格式基线。想确认上面这些形式在渲染器里是什么表现,不要改这篇文章,另开一个临时文件,用 <!-- prettier-ignore --> 或者单独跑一遍构建再验。

十六、综合混排

提示: 引用里的列表混了 代码、链接 和 删除线。

  1. 第一项有 加粗
  2. 第二项有一段行内代码:const x = 1;
  3. 第三项引出下面的表格
功能状态说明
标题是H1-H6,rehype-slug 生成锚点
段落与换行是软换行合并,行尾两空格或反斜杠断开
强调是加粗、斜体、粗斜体、删除线
引用是支持嵌套、列表和代码块
高亮块本站扩展[!HIGHLIGHT] 标记,别的渲染器退化成普通引用
列表是有序、无序、任务列表,嵌套任意层
任务列表只读复选框由 GFM 生成,渲染时禁用
表格是GFM,支持对齐、转义竖线、省略首尾竖线
代码块是Shiki 高亮,语言和文件名写在围栏上
链接与图片是行内、引用式,<img> 可指定尺寸
脚注是GFM 脚注,定义排到文末
定义列表否非 CommonMark/GFM,原样显示
Mermaid是流程图、时序图、甘特图、饼图、思维导图,构建时转 SVG
原始 HTML是按 JSX 处理,<details>、<kbd> 都能用

这一页的写法大多是为了压测渲染器,日常写文章用不到这么多花样,真正常用的还是标题、段落、列表、代码块和表格。哪天换了插件,我会回到这里重新跑一遍,看哪一段又变了。

Footnotes

  1. 这是脚注定义,渲染时会排到文章末尾。 ↩

作者Aoang
发布于2016-06-01
更新于2026-09-17
许可协议CC BY-NC-SA 4.0
转载或引用本文时请遵守许可协议,并注明出处。