跳到导航

预览变更

以 Markdown 格式查看

Fern 提供两种预览文档变更的方式:

  • 本地开发:快速迭代,支持热重载,最适合活跃开发阶段
  • 预览链接:可分享的 URL,用于审查和协作
前置条件

安装以下软件:

  • Node.js 版本 22 或更高
  • Fern CLI
  • pnpm,需要在你的 PATH 中可用。fern docs dev 内部使用 pnpm 来安装渲染预览所需的依赖(例如 esbuild),因此即使你的项目使用 npm 或 yarn,也必须全局安装 pnpm。

本地开发

运行本地预览服务器,通过热重载即时查看文档变更。首次在线运行后可离线访问。

# 启动预览服务器(从包含 fern 文件夹的目录运行)
fern docs dev
# 或使用自定义端口
fern docs dev --port 3002

在 Windows 上,fern docs dev 需要启用长路径支持

要启用长路径支持,在管理员权限的 PowerShell 提示符中运行以下命令,然后重启你的终端:

New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1 -PropertyType DWORD -Force

如果无法启用长路径支持,请使用 Windows Subsystem for Linux (WSL) 在 Linux 环境中运行 fern docs dev

你的文档将在 http://localhost:3000(默认)或你指定的端口上可用。如果你尝试在已占用的端口上运行 Fern,它将使用下一个可用端口。

本地开发中某些功能被禁用:

  • 搜索
  • SEO(网站图标、自动生成的 meta 标签等)
  • 身份验证

预览链接

生成可分享的预览 URL,在发布前审查和协作文档变更。预览链接不会被搜索引擎索引,也不会过期。

默认情况下,每次运行都会生成带有唯一 UUID 的新 URL。--id 标志创建稳定的命名预览链接 — 使用相同的 --id 重新运行会就地更新现有预览。

# 生成带有唯一 URL 的预览链接
fern generate --docs --preview
# 或使用 --id 创建稳定的命名预览链接
fern generate --docs --preview --id my-feature
示例输出
# 不使用 --id(每次都是唯一 UUID)
[docs]: Published docs to https://fern-preview-c973a36e-337b-44f5-ab83-aab.docs.buildwithfern.com/learn
# 使用 --id my-feature(稳定 URL)
[docs]: Published docs to https://fern-preview-my-feature.docs.buildwithfern.com/learn

当已存在相同 --id 的预览时,Fern 会提示你确认覆盖。在 GitHub Actions 中会自动跳过此确认,但对于其他 CI 环境(例如 Azure Pipelines),请使用 --force 跳过确认。

fern generate --docs --preview --id my-feature --force

当不再需要时,你可以删除预览部署

fern docs preview delete <url>

使用 GitHub Actions 自动化

你可以使用 GitHub Actions 工作流在打开拉取请求时自动生成预览 URL。通过传递分支名称的 --id,同一 PR 的每次推送都会更新相同的预览 URL,而不是创建新的。工作流会在 PR 上发布评论,包含预览链接和 PR 中每个更改页面的直接链接,以便审查者可以直接跳转到受影响的页面。

GitHub Actions 机器人在拉取请求上的评论,显示命名预览 URL 和已更改文档页面的直接链接

如果你使用引导式 UICLI 快速开始设置站点,此工作流会自动包含在你的仓库中。否则,请使用下面的示例手动添加。

这些工作流需要 FERN_TOKEN 仓库密钥。如果你使用了引导式工作流,此密钥会自动添加。否则,在终端中运行 fern token 生成令牌,然后在仓库的设置 > 密钥和变量 > Actions中添加,名称为 FERN_TOKEN

你可能需要重新运行在配置 FERN_TOKEN 之前打开的任何 PR 的预览构建。

.github/workflows/preview-docs.yml
name: Preview Docs
on:
pull_request:
types: [opened, synchronize, ready_for_review]
branches:
- main
jobs:
run:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Fern CLI
uses: fern-api/setup-fern-cli@v1
- name: Generate preview URL
id: generate-docs
env:
FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
HEAD_REF: ${{ github.head_ref }}
run: |
OUTPUT=$(fern generate --docs --preview --id "$HEAD_REF" 2>&1) || true
echo "$OUTPUT"
URL=$(echo "$OUTPUT" | grep -oP 'Published docs to \K.*(?= \()')
echo "preview_url=$URL" >> $GITHUB_OUTPUT
echo "Preview URL: $URL"
- name: Get page links for changed MDX files
id: page-links
env:
FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
run: |
PREVIEW_URL="${{ steps.generate-docs.outputs.preview_url }}"
CHANGED_FILES=$(git diff --name-only origin/main...HEAD -- '*.mdx' 2>/dev/null || echo "")
if [ -z "$CHANGED_FILES" ] || [ -z "$PREVIEW_URL" ]; then
echo "page_links=" >> $GITHUB_OUTPUT; exit 0
fi
BASE_URL=$(echo "$PREVIEW_URL" | grep -oP 'https?://[^/]+')
FILES_PARAM=$(echo "$CHANGED_FILES" | tr '\n' ',' | sed 's/,$//')
RESPONSE=$(curl -sf -H "FERN_TOKEN: $FERN_TOKEN" "${PREVIEW_URL}/api/fern-docs/get-slug-for-file?files=${FILES_PARAM}" 2>/dev/null) || {
echo "page_links=" >> $GITHUB_OUTPUT; exit 0
}
PAGE_LINKS=$(echo "$RESPONSE" | jq -r --arg url "$BASE_URL" \
'.mappings[] | select(.slug != null) | "- [\(.slug)](\($url)/\(.slug))"')
if [ -n "$PAGE_LINKS" ]; then
{ echo "page_links<<EOF"; echo "$PAGE_LINKS"; echo "EOF"; } >> $GITHUB_OUTPUT
else
echo "page_links=" >> $GITHUB_OUTPUT
fi
- name: Create comment content
run: |
echo ":herb: **预览你的文档:** <${{ steps.generate-docs.outputs.preview_url }}>" > comment.md
if [ -n "${{ steps.page-links.outputs.page_links }}" ]; then
echo "" >> comment.md
echo "以下是你更新的 markdown 页面:" >> comment.md
echo "${{ steps.page-links.outputs.page_links }}" >> comment.md
fi
- name: Post PR comment
uses: thollander/actions-comment-pull-request@v2.4.3
with:
filePath: comment.md
comment_tag: preview-docs
mode: upsert

如果你的仓库接受来自 fork 的贡献,请使用 pull_request_target 而不是 pull_request 以允许工作流访问你的 FERN_TOKEN 密钥:

.github/workflows/preview-docs.yml
name: Preview Docs
on:
pull_request_target:
types: [opened, synchronize, ready_for_review]
branches:
- main
jobs:
run:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkout PR
run: |
git fetch origin pull/${{ github.event.pull_request.number }}/head:pr-${{ github.event.pull_request.number }}
git checkout pr-${{ github.event.pull_request.number }}
- name: Setup Fern CLI
uses: fern-api/setup-fern-cli@v1
- name: Generate preview URL
id: generate-docs
env:
FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
HEAD_REF: ${{ github.head_ref }}
run: |
OUTPUT=$(fern generate --docs --preview --id "$HEAD_REF" 2>&1) || true
echo "$OUTPUT"
URL=$(echo "$OUTPUT" | grep -oP 'Published docs to \K.*(?= \()')
echo "preview_url=$URL" >> $GITHUB_OUTPUT
echo "Preview URL: $URL"
- name: Get page links for changed MDX files
id: page-links
env:
FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
run: |
PREVIEW_URL="${{ steps.generate-docs.outputs.preview_url }}"
CHANGED_FILES=$(git diff --name-only origin/main...HEAD -- '*.mdx' 2>/dev/null || echo "")
if [ -z "$CHANGED_FILES" ] || [ -z "$PREVIEW_URL" ]; then
echo "page_links=" >> $GITHUB_OUTPUT; exit 0
fi
BASE_URL=$(echo "$PREVIEW_URL" | grep -oP 'https?://[^/]+')
FILES_PARAM=$(echo "$CHANGED_FILES" | tr '\n' ',' | sed 's/,$//')
RESPONSE=$(curl -sf -H "FERN_TOKEN: $FERN_TOKEN" "${PREVIEW_URL}/api/fern-docs/get-slug-for-file?files=${FILES_PARAM}" 2>/dev/null) || {
echo "page_links=" >> $GITHUB_OUTPUT; exit 0
}
PAGE_LINKS=$(echo "$RESPONSE" | jq -r --arg url "$BASE_URL" \
'.mappings[] | select(.slug != null) | "- [\(.slug)](\($url)/\(.slug))"')
if [ -n "$PAGE_LINKS" ]; then
{ echo "page_links<<EOF"; echo "$PAGE_LINKS"; echo "EOF"; } >> $GITHUB_OUTPUT
else
echo "page_links=" >> $GITHUB_OUTPUT
fi
- name: Create comment content
run: |
echo ":herb: **预览你的文档:** <${{ steps.generate-docs.outputs.preview_url }}>" > comment.md
if [ -n "${{ steps.page-links.outputs.page_links }}" ]; then
echo "" >> comment.md
echo "以下是你更新的 markdown 页面:" >> comment.md
echo "${{ steps.page-links.outputs.page_links }}" >> comment.md
fi
- name: Post PR comment
uses: thollander/actions-comment-pull-request@v2.4.3
with:
filePath: comment.md
comment_tag: preview-docs
mode: upsert

PR 合并时清理预览链接

要在 PR 合并后自动清理预览链接,在上面的工作流旁边添加此工作流。它调用 fern docs preview delete,使用 PR 的分支名称作为 --id,与生成预览时使用的标识符匹配。

.github/workflows/cleanup-preview.yml
name: Clean up preview links
on:
pull_request:
types: [closed]
jobs:
cleanup:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Fern CLI
uses: fern-api/setup-fern-cli@v1
- name: Delete preview deployment
env:
FERN_TOKEN: ${{ secrets.FERN_TOKEN }}
run: |
echo "正在删除分支预览:${{ github.head_ref }}"
fern docs preview delete --id "${{ github.head_ref }}" || echo "预览删除返回非零值 — 可能已经删除"