Skip to content

chore(seo): redirects 单跳 + root metadata hreflang,i18n 段化收尾 #766

chore(seo): redirects 单跳 + root metadata hreflang,i18n 段化收尾

chore(seo): redirects 单跳 + root metadata hreflang,i18n 段化收尾 #766

Workflow file for this run

name: Build Check
permissions:
contents: read
actions: write
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
env:
NEXT_TELEMETRY_DISABLED: "1"
CI: "true"
steps:
- uses: actions/checkout@v4
# Enable corepack to ensure the exact pnpm version from package.json is used
- name: Enable Corepack
run: corepack enable
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
# Verify pnpm version matches package.json packageManager field
- name: Check pnpm version
run: node scripts/check-pnpm-version.mjs
- run: pnpm install --frozen-lockfile
# Verify lockfile wasn't modified by install
- name: Check lockfile consistency
run: |
if ! git diff --exit-code pnpm-lock.yaml; then
echo "❌ Error: pnpm-lock.yaml was modified after install"
echo "This indicates a pnpm version mismatch or corrupted lockfile"
echo ""
echo "Expected pnpm version from package.json:"
# Use multiple fallback methods to extract version
grep '"packageManager"' package.json | grep -o 'pnpm@[^"]*' || \
node -e "try { console.log(require('./package.json').packageManager || 'not specified') } catch(e) { console.log('Could not read') }" || \
echo "Could not extract version"
echo ""
echo "Actual pnpm version:"
pnpm --version || echo "pnpm not found"
exit 1
fi
echo "✅ Lockfile is consistent"
- run: pnpm run lint
- run: pnpm run lint:images
- run: pnpm run typecheck
# === IndexNow 提交(仅在 main 分支执行) ===
- name: Install jq (for JSON build)
if: github.ref == 'refs/heads/main'
run: sudo apt-get update && sudo apt-get install -y jq
- name: Submit IndexNow (changed URLs)
if: github.ref == 'refs/heads/main'
env:
SITE_ORIGIN: https://involutionhell.com
INDEXNOW_API: https://involutionhell.com/api/indexnow
INDEXNOW_API_TOKEN: ${{ secrets.INDEXNOW_API_TOKEN }}
run: |
set -euo pipefail
git fetch --depth=2 origin ${{ github.ref }} || true
CHANGED="$(git diff --name-only HEAD~1 HEAD || true)"
CHANGED_DOCS="$(echo "$CHANGED" | grep -E '^content/docs/.*\.(md|mdx)$' || true)"
# i18n URL 段化(2026-05)后所有 docs URL 都带 /<locale>/ 前缀。
# 每篇文档对外有 /zh/docs/<slug> 和 /en/docs/<slug> 两个独立 URL,
# 任意文件变更都推送两条让 IndexNow 同时刷新两种语言版本。
# 文件命名约定(fumadocs dot parser):
# xxx.mdx → 默认 (zh) 原文,slug = xxx
# xxx.en.mdx → en 翻译,slug = xxx(去 .en 后缀提 base slug)
#
# 例外:career/interview-prep/leetcode/ 下含中文的文件名会被
# lib/source.ts 的 transformer 拼音化(convertSlugToPinyin),
# 实际路由的最后一段是拼音 slug 而不是中文 stem。这里复用
# generated/leetcode-slug-map.json (prebuild 时由
# scripts/generate-leetcode-slug-map.mts 与 source.ts 同算法生成)
# 把中文 stem 映射到拼音 slug,否则推送的 URL 会 404。
LEETCODE_PREFIX="career/interview-prep/leetcode/"
SLUG_MAP_FILE="generated/leetcode-slug-map.json"
URLS=()
while IFS= read -r f; do
[ -z "$f" ] && continue
if [[ "$f" =~ ^content/docs/(.*)\.(md|mdx)$ ]]; then
slug="${BASH_REMATCH[1]}"
# 剥离 locale 后缀(.en / .zh),拿到 canonical base slug
slug="${slug%.en}"
slug="${slug%.zh}"
# index.mdx 对应目录本身的 URL(fumadocs 约定)
slug="${slug%/index}"
# leetcode 中文 stem → 拼音 slug 映射(与 source.ts transformer 一致)
if [[ "$slug" == "$LEETCODE_PREFIX"* && -f "$SLUG_MAP_FILE" ]]; then
stem="${slug##*/}"
dir="${slug%/*}"
mapped="$(jq -r --arg k "$stem" '.[$k] // empty' "$SLUG_MAP_FILE")"
if [ -n "$mapped" ]; then
slug="$dir/$mapped"
fi
fi
URLS+=("$SITE_ORIGIN/zh/docs/$slug")
URLS+=("$SITE_ORIGIN/en/docs/$slug")
fi
done <<< "$CHANGED_DOCS"
mapfile -t URLS < <(printf "%s\n" "${URLS[@]}" | awk 'NF' | sort -u)
if [ "${#URLS[@]}" -eq 0 ]; then
# 没有 docs 改动时(例如改 README / 配置等)仍提交首页让 Bing/Yandex
# 知道站点活跃。i18n 段化后首页有两个 URL,分别推送。
URLS=("$SITE_ORIGIN/zh" "$SITE_ORIGIN/en")
fi
echo "✅ Submitting URLs to IndexNow:"
printf ' - %s\n' "${URLS[@]}"
JSON="$(jq -n --argjson arr "$(printf '%s\n' "${URLS[@]}" | jq -R . | jq -s .)" '{urlList: $arr}')"
AUTH_HEADER=()
if [ -n "${INDEXNOW_API_TOKEN:-}" ]; then
AUTH_HEADER=(-H "Authorization: Bearer ${INDEXNOW_API_TOKEN}")
fi
echo "📡 Sending request to $INDEXNOW_API ..."
RESPONSE=$(curl -sS -w "\nHTTP_STATUS=%{http_code}" -X POST "$INDEXNOW_API" \
-H "Content-Type: application/json" \
"${AUTH_HEADER[@]}" \
-d "$JSON")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTP_STATUS=.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTP_STATUS=//')
echo "📥 API Response Status: $STATUS"
echo "📦 Response Body:"
echo "$BODY"
if [ "$STATUS" -ge 400 ]; then
echo "❌ IndexNow submission failed!"
exit 1
fi
echo "✅ IndexNow submission completed."