javascript seo
本地来源:seo-llm/skill/google-seo-skill/references/javascript-seo.md
JavaScript SEO 与渲染优化
1. 服务端渲染策略 (SSR/SSG/ISR)
Next.js 渲染模式选择
rendering_strategy:
SSG:
use_when: "内容不频繁变更(博客、文档、着陆页)"
seo_benefit: "最佳 — 完整 HTML 在构建时生成"
performance: "最快 — 直接提供静态文件"
ISR:
use_when: "内容定期更新(产品页、新闻)"
seo_benefit: "优秀 — 与 SSG 相同,支持增量更新"
performance: "快速 — 缓存 + 按需再生成"
SSR:
use_when: "个性化内容、实时数据"
seo_benefit: "良好 — 每次请求生成完整 HTML"
performance: "取决于服务器响应时间"
CSR:
use_when: "仅用于交互式功能(仪表板、编辑器)"
seo_benefit: "差 — Google 需执行 JS 才能索引"
performance: "首次加载慢"
Next.js 实现示例
// SSG - 静态生成
export default async function BlogPost({ params }: PageProps) {
const post = await getPost(params.slug)
return <Article post={post} />
}
export async function generateStaticParams() {
const posts = await getAllPosts()
return posts.map((post) => ({ slug: post.slug }))
}
// ISR - 增量静态再生成
export const revalidate = 3600 // 每小时重新验证
// SSR - 服务端渲染
export const dynamic = 'force-dynamic'
2. 关键内容必须在原始 HTML 中
// ✅ 服务端渲染关键 SEO 内容
// app/blog/[slug]/page.tsx (Server Component)
export default async function BlogPost({ params }: PageProps) {
const post = await getPost(params.slug)
return (
<article>
{/* 这些内容在原始 HTML 中可见,无需 JS */}
<h1>{post.title}</h1>
<p>{post.excerpt}</p>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
{/* 结构化数据也在服务端渲染 */}
<ArticleSchema post={post} />
</article>
)
}
// ❌ 不要用客户端组件渲染关键 SEO 内容
'use client'
export default function BlogPost() {
const [post, setPost] = useState(null)
useEffect(() => {
fetch('/api/post').then(r => r.json()).then(setPost)
}, [])
// Google 必须执行 JS 才能看到内容!
return post ? <h1>{post.title}</h1> : <Loading />
}
3. 结构化数据必须服务端渲染
// ✅ 结构化数据在 Server Component 中
export default async function ProductPage({ params }: PageProps) {
const product = await getProduct(params.id)
return (
<>
{/* JSON-LD 在服务端渲染,Google 可直接读取 */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Product',
name: product.name,
// ...
}),
}}
/>
<ProductDetail product={product} />
</>
)
}
// ❌ 不要在客户端 useEffect 中注入结构化数据
4. Meta 标签在原始 HTML Response 中
// ✅ Next.js App Router - metadata 自动在服务端渲染
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.excerpt,
openGraph: { title: post.title, description: post.excerpt },
}
}
// Next.js 自动将这些 meta 标签放入原始 HTML <head> 中
// ❌ 不要在客户端动态修改 <title> 或 meta 标签
// document.title = 'New Title' // Google 可能不会读取
5. 导航链接规范
<!-- ✅ 标准的 <a href> 链接 — Google 可爬取 -->
<a href="/about">关于我们</a>
<!-- ✅ Next.js Link 组件 — 渲染为标准 <a> 标签 -->
<Link href="/blog">博客</Link>
<!-- ❌ JavaScript 导航 — Google 无法爬取 -->
<div onClick={() => router.push('/about')}>关于我们</div>
<button onClick={() => navigate('/blog')}>博客</button>
<span className="link" data-href="/contact">联系</span>
6. 懒加载图片规范
<!-- ✅ 使用原生 loading="lazy" + src 属性 -->
<img src="/image.jpg" loading="lazy" alt="描述" width="800" height="450" />
<!-- ✅ Next.js Image 自动处理 -->
<Image src="/image.jpg" alt="描述" width={800} height={450} />
<!-- ❌ 仅使用 data-src,Google 可能无法索引图片 -->
<img data-src="/image.jpg" class="lazyload" alt="描述" />
7. Hydration 错误检查
hydration_errors:
common_causes:
- "服务端和客户端渲染输出不一致"
- "使用 Date.now() 或 Math.random() 在渲染中"
- "访问 window/document 在服务端组件中"
- "HTML 嵌套不正确(如 <p> 内嵌 <div>)"
detection:
- "浏览器控制台检查 hydration 错误"
- "React DevTools Profiler"
prevention:
- "使用 useEffect 处理客户端专属逻辑"
- "使用 suppressHydrationWarning 仅在必要时"
- "确保 HTML 结构在服务端和客户端一致"
8. JavaScript Bundle 优化
// 代码分割策略
import dynamic from 'next/dynamic'
// 1. 路由级分割 - Next.js 自动处理
// app/page.tsx, app/blog/page.tsx 自动分割
// 2. 组件级分割 - 重型组件
const HeavyEditor = dynamic(() => import('@/components/Editor'), {
loading: () => <Skeleton />,
ssr: false, // 仅客户端渲染的交互组件
})
// 3. 第三方库按需导入
// ❌ import _ from 'lodash' // 导入整个库
// ✅ import debounce from 'lodash/debounce' // 只导入需要的
// 4. Tree-shaking 优化
// package.json 中设置 "sideEffects": false
9. Google JS 渲染机制与限制
Google 对 JavaScript 渲染采用三阶段处理:
google_js_rendering:
stage_1_crawl: "下载 HTML,提取链接和资源引用"
stage_2_queue: "将页面放入渲染队列(可能延迟数小时到数天)"
stage_3_render: "使用 headless Chromium 执行 JS 并索引渲染后的内容"
limitations:
- "单页 JS 文件总大小限制 15MB(超出部分不执行)"
- "渲染超时约 5 秒,复杂 JS 可能未完成"
- "不支持 hash URL(#/path)— 爬虫不会区分 # 后的内容"
- "Web Components / Shadow DOM 内容可能无法被索引"
- "IntersectionObserver 懒加载在 Googlebot 中可能不触发"
best_practices:
- "关键内容必须在原始 HTML 或首次渲染中可见"
- "URL 使用 History API(pushState),绝对不用 hash routing"
- "静态资源使用长期缓存(Cache-Control: max-age=31536000)+ 文件名 hash"
- "动态内容返回正确的 HTTP 状态码(404 页面不要返回 200 = soft 404)"
- "确保 JS/CSS 资源不被 robots.txt 阻止"
10. URL Inspection 验证
使用 Google Search Console 的 URL Inspection 工具验证: - 渲染后的 HTML 是否包含关键内容 - 结构化数据是否正确显示 - meta 标签是否完整 - 截图是否与实际页面一致 - 是否有 JavaScript 错误阻止渲染
相关文档
- 语义化 HTML 与图片优化 — 语义化标签与可访问性
- 性能优化与 Core Web Vitals — JS 对 CWV 的影响
- 技术 SEO — 爬虫控制与索引优化
- SEO 问题排查 — JS 渲染问题诊断
- 结构化数据指南 — 动态渲染中的 Schema
本文档为站内渲染。原始文件本地路径:saas/source/seo-llm/skill-google-seo-skill-references-javascript-seo-48d022.md(仅本地保留,不入库不部署)