site-architecture
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSite Architecture Skill
网站架构技能
Load with: base.md + web-content.md
For technical website structure that enables discovery by search engines AND AI crawlers (GPTBot, ClaudeBot, PerplexityBot).
加载依赖:base.md + web-content.md
适用于可被搜索引擎和AI爬虫(GPTBot、ClaudeBot、PerplexityBot)发现的技术型网站架构。
Philosophy
理念
Content is king. Architecture is the kingdom.
Great content buried in poor architecture won't be discovered. This skill covers the technical foundation that makes your content findable by:
- Google, Bing (traditional search)
- GPTBot (ChatGPT), ClaudeBot, PerplexityBot (AI assistants)
- Social platforms (Open Graph, Twitter Cards)
内容为王,架构为疆。
优质内容如果被糟糕的架构埋没,就无法被发现。本技能涵盖让你的内容被以下渠道发现的技术基础:
- Google、Bing(传统搜索引擎)
- GPTBot(ChatGPT)、ClaudeBot、PerplexityBot(AI助手)
- 社交平台(Open Graph、Twitter Cards)
robots.txt
robots.txt
Basic Template
基础模板
txt
undefinedtxt
undefinedrobots.txt
robots.txt
Allow all crawlers by default
默认允许所有爬虫
User-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Disallow: /private/
Disallow: /_next/
Disallow: /cdn-cgi/
User-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Disallow: /private/
Disallow: /_next/
Disallow: /cdn-cgi/
Sitemap location
站点地图位置
Sitemap: https://yoursite.com/sitemap.xml
Sitemap: https://yoursite.com/sitemap.xml
Crawl delay (optional - be careful, not all bots respect this)
爬取延迟(可选 - 注意,并非所有爬虫都遵循此规则)
Crawl-delay: 1
Crawl-delay: 1
undefinedundefinedAI Bot Configuration
AI爬虫配置
txt
undefinedtxt
undefinedrobots.txt with AI bot rules
包含AI爬虫规则的robots.txt
=== SEARCH ENGINES ===
=== 搜索引擎 ===
User-agent: Googlebot
Allow: /
User-agent: Bingbot
Allow: /
User-agent: Googlebot
Allow: /
User-agent: Bingbot
Allow: /
=== AI ASSISTANTS (Allow for discovery) ===
=== AI助手(允许爬取以实现内容发现) ===
User-agent: GPTBot
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: Claude-Web
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Amazonbot
Allow: /
User-agent: anthropic-ai
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: GPTBot
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: Claude-Web
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Amazonbot
Allow: /
User-agent: anthropic-ai
Allow: /
User-agent: Google-Extended
Allow: /
=== BLOCK AI TRAINING (Optional - block training, allow chat) ===
=== 阻止AI训练(可选 - 允许引用但禁止用于训练) ===
Uncomment these if you want to be cited but not used for training
如果你希望内容被引用但不用于训练,取消以下注释
User-agent: CCBot
User-agent: CCBot
Disallow: /
Disallow: /
User-agent: GPTBot
User-agent: GPTBot
Disallow: / # Blocks both chat and training
Disallow: / # 同时阻止聊天和训练用途
=== BLOCK SCRAPERS ===
=== 阻止数据抓取工具 ===
User-agent: AhrefsBot
Disallow: /
User-agent: SemrushBot
Disallow: /
User-agent: MJ12bot
Disallow: /
User-agent: AhrefsBot
Disallow: /
User-agent: SemrushBot
Disallow: /
User-agent: MJ12bot
Disallow: /
=== DEFAULT ===
=== 默认规则 ===
User-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Disallow: /auth/
Disallow: /private/
Disallow: /.json$
Disallow: /?*
Sitemap: https://yoursite.com/sitemap.xml
undefinedUser-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Disallow: /auth/
Disallow: /private/
Disallow: /.json$
Disallow: /?*
Sitemap: https://yoursite.com/sitemap.xml
undefinedNext.js robots.txt
Next.js 版本 robots.txt
typescript
// app/robots.ts
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/', '/private/', '/_next/'],
},
{
userAgent: 'GPTBot',
allow: '/',
},
{
userAgent: 'ClaudeBot',
allow: '/',
},
{
userAgent: 'PerplexityBot',
allow: '/',
},
],
sitemap: `${baseUrl}/sitemap.xml`,
};
}typescript
// app/robots.ts
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/', '/private/', '/_next/'],
},
{
userAgent: 'GPTBot',
allow: '/',
},
{
userAgent: 'ClaudeBot',
allow: '/',
},
{
userAgent: 'PerplexityBot',
allow: '/',
},
],
sitemap: `${baseUrl}/sitemap.xml`,
};
}Sitemap
站点地图(Sitemap)
XML Sitemap Template
XML站点地图模板
xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
<url>
<loc>https://yoursite.com/</loc>
<lastmod>2025-01-15</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://yoursite.com/pricing</loc>
<lastmod>2025-01-10</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://yoursite.com/blog/article-slug</loc>
<lastmod>2025-01-12</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
<image:image>
<image:loc>https://yoursite.com/images/article-image.jpg</image:loc>
</image:image>
</url>
</urlset>xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
<url>
<loc>https://yoursite.com/</loc>
<lastmod>2025-01-15</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://yoursite.com/pricing</loc>
<lastmod>2025-01-10</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://yoursite.com/blog/article-slug</loc>
<lastmod>2025-01-12</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
<image:image>
<image:loc>https://yoursite.com/images/article-image.jpg</image:loc>
</image:image>
</url>
</urlset>Next.js Dynamic Sitemap
Next.js 动态站点地图
typescript
// app/sitemap.ts
import { MetadataRoute } from 'next';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';
// Static pages
const staticPages = [
{ url: '/', priority: 1.0, changeFrequency: 'weekly' as const },
{ url: '/pricing', priority: 0.9, changeFrequency: 'monthly' as const },
{ url: '/about', priority: 0.8, changeFrequency: 'monthly' as const },
{ url: '/contact', priority: 0.7, changeFrequency: 'yearly' as const },
];
// Dynamic pages (e.g., blog posts)
const posts = await getBlogPosts(); // Your data fetching function
const blogPages = posts.map((post) => ({
url: `/blog/${post.slug}`,
lastModified: new Date(post.updatedAt),
changeFrequency: 'monthly' as const,
priority: 0.8,
}));
return [
...staticPages.map((page) => ({
url: `${baseUrl}${page.url}`,
lastModified: new Date(),
changeFrequency: page.changeFrequency,
priority: page.priority,
})),
...blogPages.map((page) => ({
url: `${baseUrl}${page.url}`,
lastModified: page.lastModified,
changeFrequency: page.changeFrequency,
priority: page.priority,
})),
];
}typescript
// app/sitemap.ts
import { MetadataRoute } from 'next';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';
// 静态页面
const staticPages = [
{ url: '/', priority: 1.0, changeFrequency: 'weekly' as const },
{ url: '/pricing', priority: 0.9, changeFrequency: 'monthly' as const },
{ url: '/about', priority: 0.8, changeFrequency: 'monthly' as const },
{ url: '/contact', priority: 0.7, changeFrequency: 'yearly' as const },
];
// 动态页面(如博客文章)
const posts = await getBlogPosts(); // 你的数据获取函数
const blogPages = posts.map((post) => ({
url: `/blog/${post.slug}`,
lastModified: new Date(post.updatedAt),
changeFrequency: 'monthly' as const,
priority: 0.8,
}));
return [
...staticPages.map((page) => ({
url: `${baseUrl}${page.url}`,
lastModified: new Date(),
changeFrequency: page.changeFrequency,
priority: page.priority,
})),
...blogPages.map((page) => ({
url: `${baseUrl}${page.url}`,
lastModified: page.lastModified,
changeFrequency: page.changeFrequency,
priority: page.priority,
})),
];
}Sitemap Index (Large Sites)
站点地图索引(大型站点适用)
xml
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://yoursite.com/sitemap-pages.xml</loc>
<lastmod>2025-01-15</lastmod>
</sitemap>
<sitemap>
<loc>https://yoursite.com/sitemap-blog.xml</loc>
<lastmod>2025-01-14</lastmod>
</sitemap>
<sitemap>
<loc>https://yoursite.com/sitemap-products.xml</loc>
<lastmod>2025-01-13</lastmod>
</sitemap>
</sitemapindex>xml
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://yoursite.com/sitemap-pages.xml</loc>
<lastmod>2025-01-15</lastmod>
</sitemap>
<sitemap>
<loc>https://yoursite.com/sitemap-blog.xml</loc>
<lastmod>2025-01-14</lastmod>
</sitemap>
<sitemap>
<loc>https://yoursite.com/sitemap-products.xml</loc>
<lastmod>2025-01-13</lastmod>
</sitemap>
</sitemapindex>Meta Tags
元标签(Meta Tags)
Essential Meta Tags
必备元标签
html
<head>
<!-- Basic -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Title | Brand Name</title>
<meta name="description" content="Compelling 150-160 character description with keywords and CTA.">
<!-- Canonical (prevent duplicate content) -->
<link rel="canonical" href="https://yoursite.com/current-page">
<!-- Language -->
<html lang="en">
<meta name="language" content="English">
<!-- Robots -->
<meta name="robots" content="index, follow">
<meta name="googlebot" content="index, follow">
<!-- Author -->
<meta name="author" content="Author Name">
<!-- Favicon -->
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/manifest.webmanifest">
</head>html
<head>
<!-- 基础设置 -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>页面标题 | 品牌名称</title>
<meta name="description" content="150-160字符的有吸引力描述,包含关键词和行动号召。">
<!-- 规范链接(避免重复内容) -->
<link rel="canonical" href="https://yoursite.com/current-page">
<!-- 语言设置 -->
<html lang="en">
<meta name="language" content="English">
<!-- 爬虫规则 -->
<meta name="robots" content="index, follow">
<meta name="googlebot" content="index, follow">
<!-- 作者信息 -->
<meta name="author" content="作者姓名">
<!-- 网站图标 -->
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/manifest.webmanifest">
</head>Open Graph (Social Sharing)
Open Graph(社交分享)
html
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://yoursite.com/page">
<meta property="og:title" content="Page Title - Brand">
<meta property="og:description" content="Description for social sharing (can be longer).">
<meta property="og:image" content="https://yoursite.com/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:site_name" content="Brand Name">
<meta property="og:locale" content="en_US">
<!-- Article-specific (for blog posts) -->
<meta property="og:type" content="article">
<meta property="article:published_time" content="2025-01-15T08:00:00Z">
<meta property="article:modified_time" content="2025-01-20T10:00:00Z">
<meta property="article:author" content="https://yoursite.com/team/author">
<meta property="article:section" content="Technology">
<meta property="article:tag" content="AI, SEO, Content">html
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://yoursite.com/page">
<meta property="og:title" content="页面标题 - 品牌">
<meta property="og:description" content="用于社交分享的描述(可更长)。">
<meta property="og:image" content="https://yoursite.com/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:site_name" content="品牌名称">
<meta property="og:locale" content="en_US">
<!-- 文章专属设置(适用于博客文章) -->
<meta property="og:type" content="article">
<meta property="article:published_time" content="2025-01-15T08:00:00Z">
<meta property="article:modified_time" content="2025-01-20T10:00:00Z">
<meta property="article:author" content="https://yoursite.com/team/author">
<meta property="article:section" content="Technology">
<meta property="article:tag" content="AI, SEO, Content">Twitter Cards
Twitter 卡片
html
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@yourbrand">
<meta name="twitter:creator" content="@authorhandle">
<meta name="twitter:title" content="Page Title">
<meta name="twitter:description" content="Description for Twitter (max 200 chars).">
<meta name="twitter:image" content="https://yoursite.com/twitter-image.jpg">html
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@yourbrand">
<meta name="twitter:creator" content="@authorhandle">
<meta name="twitter:title" content="页面标题">
<meta name="twitter:description" content="Twitter分享描述(最多200字符)。">
<meta name="twitter:image" content="https://yoursite.com/twitter-image.jpg">Next.js Metadata
Next.js 元数据配置
typescript
// app/layout.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
metadataBase: new URL('https://yoursite.com'),
title: {
default: 'Brand Name',
template: '%s | Brand Name',
},
description: 'Your default site description.',
keywords: ['keyword1', 'keyword2', 'keyword3'],
authors: [{ name: 'Brand Name', url: 'https://yoursite.com' }],
creator: 'Brand Name',
publisher: 'Brand Name',
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
openGraph: {
type: 'website',
locale: 'en_US',
url: 'https://yoursite.com',
siteName: 'Brand Name',
title: 'Brand Name',
description: 'Your site description.',
images: [
{
url: '/og-image.jpg',
width: 1200,
height: 630,
alt: 'Brand Name',
},
],
},
twitter: {
card: 'summary_large_image',
site: '@yourbrand',
creator: '@yourbrand',
},
verification: {
google: 'google-verification-code',
yandex: 'yandex-verification-code',
},
};
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
type: 'article',
publishedTime: post.publishedAt,
modifiedTime: post.updatedAt,
authors: [post.author.name],
images: [post.coverImage],
},
};
}typescript
// app/layout.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
metadataBase: new URL('https://yoursite.com'),
title: {
default: '品牌名称',
template: '%s | 品牌名称',
},
description: '你的默认网站描述。',
keywords: ['keyword1', 'keyword2', 'keyword3'],
authors: [{ name: '品牌名称', url: 'https://yoursite.com' }],
creator: '品牌名称',
publisher: '品牌名称',
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
openGraph: {
type: 'website',
locale: 'en_US',
url: 'https://yoursite.com',
siteName: '品牌名称',
title: '品牌名称',
description: '你的网站描述。',
images: [
{
url: '/og-image.jpg',
width: 1200,
height: 630,
alt: '品牌名称',
},
],
},
twitter: {
card: 'summary_large_image',
site: '@yourbrand',
creator: '@yourbrand',
},
verification: {
google: 'google-verification-code',
yandex: 'yandex-verification-code',
},
};
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
type: 'article',
publishedTime: post.publishedAt,
modifiedTime: post.updatedAt,
authors: [post.author.name],
images: [post.coverImage],
},
};
}URL Structure
URL 结构
Best Practices
最佳实践
markdown
✅ GOOD URLs:
/blog/ai-seo-best-practices
/products/pro-plan
/pricing
/about/team
❌ BAD URLs:
/blog?id=123
/p/12345
/index.php?page=about
/Products/Pro_Plan (inconsistent casing)markdown
✅ 优质URL示例:
/blog/ai-seo-best-practices
/products/pro-plan
/pricing
/about/team
❌ 不良URL示例:
/blog?id=123
/p/12345
/index.php?page=about
/Products/Pro_Plan(大小写不一致)URL Guidelines
URL 规范
| Rule | Example |
|---|---|
| Lowercase only | |
| Hyphens not underscores | |
| No trailing slashes | |
| Descriptive slugs | |
| No query params for content | |
| Max 3-4 levels deep | |
| 规则 | 示例 |
|---|---|
| 仅使用小写字母 | |
| 使用连字符而非下划线 | |
| 末尾无斜杠 | |
| 描述性路径段 | |
| 内容页面不使用查询参数 | |
| 深度不超过3-4层 | |
Redirect Configuration
重定向配置
typescript
// next.config.js
module.exports = {
async redirects() {
return [
// Redirect old URLs to new
{
source: '/old-page',
destination: '/new-page',
permanent: true, // 301 redirect
},
// Redirect with wildcard
{
source: '/blog/old/:slug',
destination: '/articles/:slug',
permanent: true,
},
// Trailing slash redirect
{
source: '/:path+/',
destination: '/:path+',
permanent: true,
},
];
},
};typescript
// next.config.js
module.exports = {
async redirects() {
return [
// 将旧URL重定向到新URL
{
source: '/old-page',
destination: '/new-page',
permanent: true, // 301永久重定向
},
// 通配符重定向
{
source: '/blog/old/:slug',
destination: '/articles/:slug',
permanent: true,
},
// 末尾斜杠重定向
{
source: '/:path+/',
destination: '/:path+',
permanent: true,
},
];
},
};Canonical URLs
规范链接(Canonical URLs)
Implementation
实现方式
html
<!-- Always include canonical, even for primary URL -->
<link rel="canonical" href="https://yoursite.com/current-page">html
<!-- 始终包含规范链接,即使页面只有一个版本 -->
<link rel="canonical" href="https://yoursite.com/current-page">When to Use
使用场景
markdown
✅ USE CANONICAL:
- Every page (even if only version exists)
- Paginated content (point to page 1 or use rel=prev/next)
- URL parameters that don't change content (?utm_source=...)
- HTTP vs HTTPS (canonical to HTTPS)
- www vs non-www (pick one, canonical to it)
Example: /products?sort=price should canonical to /productsmarkdown
✅ 应使用规范链接的场景:
- 每个页面(即使只有一个版本)
- 分页内容(指向第1页或使用rel=prev/next)
- 不改变内容的URL参数(如?utm_source=...)
- HTTP与HTTPS(规范到HTTPS)
- www与非www域名(选择其一,规范到该域名)
示例:/products?sort=price 应规范到 /productsNext.js Canonical
Next.js 规范链接配置
typescript
// Automatic in metadata
export const metadata: Metadata = {
alternates: {
canonical: '/current-page',
},
};typescript
// 在元数据中自动配置
export const metadata: Metadata = {
alternates: {
canonical: '/current-page',
},
};Security Headers
安全头
Essential Headers
必备头信息
typescript
// next.config.js
const securityHeaders = [
{
key: 'X-DNS-Prefetch-Control',
value: 'on',
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin',
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()',
},
];
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: securityHeaders,
},
];
},
};typescript
// next.config.js
const securityHeaders = [
{
key: 'X-DNS-Prefetch-Control',
value: 'on',
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin',
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()',
},
];
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: securityHeaders,
},
];
},
};Core Web Vitals
核心网页指标(Core Web Vitals)
Target Metrics
目标指标
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP (Largest Contentful Paint) | ≤2.5s | ≤4.0s | >4.0s |
| INP (Interaction to Next Paint) | ≤200ms | ≤500ms | >500ms |
| CLS (Cumulative Layout Shift) | ≤0.1 | ≤0.25 | >0.25 |
| 指标 | 优秀 | 需要改进 | 较差 |
|---|---|---|---|
| LCP(最大内容绘制) | ≤2.5秒 | ≤4.0秒 | >4.0秒 |
| INP(交互到下一次绘制) | ≤200毫秒 | ≤500毫秒 | >500毫秒 |
| CLS(累积布局偏移) | ≤0.1 | ≤0.25 | >0.25 |
Optimization Checklist
优化检查清单
markdown
undefinedmarkdown
undefinedLCP (Loading)
LCP(加载性能)
- Optimize largest image (WebP, proper sizing)
- Preload critical assets
- Use CDN for static assets
- Enable compression (gzip/brotli)
- Minimize render-blocking resources
- 优化最大图片(WebP格式、合适尺寸)
- 预加载关键资源
- 为静态资源使用CDN
- 启用压缩(gzip/brotli)
- 最小化阻塞渲染的资源
INP (Interactivity)
INP(交互性能)
- Minimize JavaScript execution time
- Break up long tasks
- Use web workers for heavy computation
- Optimize event handlers
- Lazy load non-critical JS
- 最小化JavaScript执行时间
- 拆分长任务
- 使用Web Workers处理重型计算
- 优化事件处理器
- 懒加载非关键JS
CLS (Visual Stability)
CLS(视觉稳定性)
- Set dimensions on images/videos
- Reserve space for dynamic content
- Avoid inserting content above existing
- Use transform for animations
- Preload fonts
undefined- 为图片/视频设置尺寸
- 为动态内容预留空间
- 避免在现有内容上方插入新内容
- 使用transform实现动画
- 预加载字体
undefinedNext.js Performance
Next.js 性能优化
typescript
// Image optimization
import Image from 'next/image';
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={630}
priority // Preload for LCP
placeholder="blur"
blurDataURL={blurDataUrl}
/>
// Font optimization
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap', // Prevent FOIT
});
// Dynamic imports
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <Skeleton />,
ssr: false, // Client-only if needed
});typescript
// 图片优化
import Image from 'next/image';
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={630}
priority // 为LCP预加载
placeholder="blur"
blurDataURL={blurDataUrl}
/>
// 字体优化
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap', // 避免FOIT(字体加载前不可见文本)
});
// 动态导入
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <Skeleton />,
ssr: false, // 如需仅在客户端渲染
});Internal Linking
内部链接
Structure
结构
markdown
undefinedmarkdown
undefinedLink Architecture
链接架构
Homepage
├── /pricing (1 click)
├── /features (1 click)
├── /blog (1 click)
│ ├── /blog/category-1 (2 clicks)
│ │ └── /blog/category-1/post (3 clicks)
│ └── /blog/category-2 (2 clicks)
└── /about (1 click)
Rule: Every page within 3 clicks of homepage
undefined首页
├── /pricing(1次点击)
├── /features(1次点击)
├── /blog(1次点击)
│ ├── /blog/category-1(2次点击)
│ │ └── /blog/category-1/post(3次点击)
│ └── /blog/category-2(2次点击)
└── /about(1次点击)
规则:所有页面需在3次点击内从首页到达
undefinedBest Practices
最佳实践
markdown
✅ DO:
- Use descriptive anchor text
- Link contextually within content
- Create hub pages for topics
- Link to related content at end of posts
- Use breadcrumbs for navigation
❌ AVOID:
- "Click here" as anchor text
- Orphan pages (no internal links)
- Too many links per page (>100)
- Broken internal links
- Redirect chainsmarkdown
✅ 推荐做法:
- 使用描述性锚文本
- 在内容中上下文关联链接
- 创建主题中心页面
- 在文章末尾链接到相关内容
- 使用面包屑导航
❌ 避免做法:
- 使用“点击这里”作为锚文本
- 孤立页面(无内部链接)
- 单页面链接过多(>100个)
- 无效内部链接
- 重定向链Breadcrumbs
面包屑导航
typescript
// components/Breadcrumbs.tsx
import Link from 'next/link';
interface BreadcrumbItem {
name: string;
href: string;
}
export function Breadcrumbs({ items }: { items: BreadcrumbItem[] }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: `https://yoursite.com${item.href}`,
})),
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<nav aria-label="Breadcrumb">
<ol className="flex gap-2">
{items.map((item, index) => (
<li key={item.href}>
{index > 0 && <span>/</span>}
<Link href={item.href}>{item.name}</Link>
</li>
))}
</ol>
</nav>
</>
);
}typescript
// components/Breadcrumbs.tsx
import Link from 'next/link';
interface BreadcrumbItem {
name: string;
href: string;
}
export function Breadcrumbs({ items }: { items: BreadcrumbItem[] }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: `https://yoursite.com${item.href}`,
})),
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<nav aria-label="Breadcrumb">
<ol className="flex gap-2">
{items.map((item, index) => (
<li key={item.href}>
{index > 0 && <span>/</span>}
<Link href={item.href}>{item.name}</Link>
</li>
))}
</ol>
</nav>
</>
);
}AI Crawler Handling
AI爬虫处理
Known AI Crawlers
已知AI爬虫
| Bot | User Agent | Purpose |
|---|---|---|
| GPTBot | | ChatGPT web browsing |
| ChatGPT-User | | ChatGPT user browsing |
| ClaudeBot | | Claude web access |
| Claude-Web | | Claude web features |
| PerplexityBot | | Perplexity search |
| Google-Extended | | Gemini/Bard training |
| Amazonbot | | Alexa/Amazon AI |
| CCBot | | Common Crawl (AI training) |
| 爬虫 | 用户代理 | 用途 |
|---|---|---|
| GPTBot | | ChatGPT网页浏览 |
| ChatGPT-User | | ChatGPT用户浏览 |
| ClaudeBot | | Claude网页访问 |
| Claude-Web | | Claude网页功能 |
| PerplexityBot | | Perplexity搜索 |
| Google-Extended | | Gemini/Bard训练 |
| Amazonbot | | Alexa/亚马逊AI |
| CCBot | | Common Crawl(AI训练数据集) |
Allow AI Discovery, Block Training (Optional)
允许AI发现,阻止训练(可选)
txt
undefinedtxt
undefinedrobots.txt
robots.txt
Allow GPTBot for ChatGPT browsing
允许GPTBot用于ChatGPT浏览
User-agent: GPTBot
Allow: /
User-agent: GPTBot
Allow: /
Block CCBot (used for training datasets)
阻止CCBot(用于训练数据集)
User-agent: CCBot
Disallow: /
User-agent: CCBot
Disallow: /
Block Google AI training, allow search
阻止谷歌AI训练,允许搜索
User-agent: Google-Extended
Disallow: /
undefinedUser-agent: Google-Extended
Disallow: /
undefinedAI-Specific Meta Tags
AI专属元标签
html
<!-- Block AI training but allow indexing -->
<meta name="robots" content="index, follow, max-image-preview:large">
<!-- Opt out of AI training (proposed standard) -->
<meta name="ai-training" content="disallow">html
<!-- 阻止AI训练但允许索引 -->
<meta name="robots" content="index, follow, max-image-preview:large">
<!-- 选择退出AI训练(提议中的标准) -->
<meta name="ai-training" content="disallow">Structured Data Placement
结构化数据放置
Where to Add Schema
Schema添加位置
html
<!-- Option 1: In <head> with JSON-LD (recommended) -->
<head>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Your Company"
}
</script>
</head>
<!-- Option 2: Before closing </body> -->
<body>
<!-- Page content -->
<script type="application/ld+json">
{ "@context": "https://schema.org", ... }
</script>
</body>html
<!-- 选项1:在<head>中使用JSON-LD(推荐) -->
<head>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Your Company"
}
</script>
</head>
<!-- 选项2:在</body>结束前添加 -->
<body>
<!-- 页面内容 -->
<script type="application/ld+json">
{ "@context": "https://schema.org", ... }
</script>
</body>Multiple Schema Per Page
单页面多Schema
html
<head>
<!-- Organization (site-wide) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "Organization", ... }
</script>
<!-- BreadcrumbList (navigation) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "BreadcrumbList", ... }
</script>
<!-- Article (page-specific) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "Article", ... }
</script>
<!-- FAQPage (if FAQ section exists) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "FAQPage", ... }
</script>
</head>html
<head>
<!-- 组织信息(全站通用) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "Organization", ... }
</script>
<!-- 面包屑列表(导航) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "BreadcrumbList", ... }
</script>
<!-- 文章信息(页面专属) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "Article", ... }
</script>
<!-- FAQ页面(如果有FAQ区域) -->
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "FAQPage", ... }
</script>
</head>Project Structure
项目结构
project/
├── public/
│ ├── robots.txt # Or generate dynamically
│ ├── sitemap.xml # Or generate dynamically
│ ├── favicon.ico
│ ├── icon.svg
│ ├── apple-touch-icon.png
│ ├── og-image.jpg # Default OG image (1200x630)
│ └── manifest.webmanifest
├── app/
│ ├── layout.tsx # Global metadata
│ ├── robots.ts # Dynamic robots.txt
│ ├── sitemap.ts # Dynamic sitemap
│ └── [page]/
│ └── page.tsx # Page-specific metadata
├── components/
│ ├── SchemaMarkup.tsx
│ ├── Breadcrumbs.tsx
│ └── MetaTags.tsx
└── lib/
├── schema.ts # Schema generators
└── seo.ts # SEO utilitiesproject/
├── public/
│ ├── robots.txt # 或动态生成
│ ├── sitemap.xml # 或动态生成
│ ├── favicon.ico
│ ├── icon.svg
│ ├── apple-touch-icon.png
│ ├── og-image.jpg # 默认OG图片(1200x630)
│ └── manifest.webmanifest
├── app/
│ ├── layout.tsx # 全局元数据
│ ├── robots.ts # 动态生成robots.txt
│ ├── sitemap.ts # 动态生成站点地图
│ └── [page]/
│ └── page.tsx # 页面专属元数据
├── components/
│ ├── SchemaMarkup.tsx
│ ├── Breadcrumbs.tsx
│ └── MetaTags.tsx
└── lib/
├── schema.ts # Schema生成器
└── seo.ts # SEO工具函数Verification & Submission
验证与提交
Search Console Setup
搜索控制台设置
bash
undefinedbash
undefinedVerify ownership methods
所有权验证方式
- HTML file upload (google*.html to public/)
- Meta tag (add to <head>)
- DNS TXT record
- Google Analytics (if already installed)
undefined- HTML文件上传(将google*.html放入public/)
- 元标签(添加到<head>)
- DNS TXT记录
- Google Analytics(如果已安装)
undefinedSubmit Sitemap
提交站点地图
markdown
1. Google Search Console
- Sitemaps → Add new sitemap → yoursite.com/sitemap.xml
2. Bing Webmaster Tools
- Sitemaps → Submit sitemap
3. Yandex Webmaster (if relevant)
- Indexing → Sitemap filesmarkdown
1. Google Search Console
- 站点地图 → 添加新站点地图 → yoursite.com/sitemap.xml
2. Bing Webmaster Tools
- 站点地图 → 提交站点地图
3. Yandex Webmaster(如适用)
- 索引 → 站点地图文件Checklist
检查清单
markdown
undefinedmarkdown
undefinedTechnical SEO Checklist
技术SEO检查清单
robots.txt
robots.txt
- Allow search engines
- Allow AI bots (GPTBot, ClaudeBot, PerplexityBot)
- Block admin/private areas
- Include sitemap reference
- Test with Google's robots.txt tester
- 允许搜索引擎访问
- 允许AI爬虫(GPTBot、ClaudeBot、PerplexityBot)
- 阻止管理/私有区域
- 包含站点地图引用
- 使用Google的robots.txt测试工具验证
Sitemap
站点地图
- Include all indexable pages
- Exclude noindex pages
- Include lastmod dates
- Submit to Search Console
- Auto-update on content changes
- 包含所有可索引页面
- 排除noindex页面
- 包含lastmod日期
- 提交到搜索控制台
- 内容更新时自动更新
Meta Tags
元标签
- Unique title per page (50-60 chars)
- Unique description per page (150-160 chars)
- Canonical URL on every page
- Open Graph tags
- Twitter Card tags
- 每个页面有唯一标题(50-60字符)
- 每个页面有唯一描述(150-160字符)
- 每个页面包含规范链接
- 配置Open Graph标签
- 配置Twitter Card标签
URL Structure
URL结构
- Lowercase, hyphenated
- Descriptive slugs
- No query params for content
- 301 redirects for moved content
- No broken links
- 小写、连字符分隔
- 描述性路径段
- 内容页面不使用查询参数
- 为迁移内容设置301重定向
- 无无效链接
Performance
性能
- LCP < 2.5s
- INP < 200ms
- CLS < 0.1
- HTTPS enabled
- Security headers configured
- LCP < 2.5秒
- INP < 200毫秒
- CLS < 0.1
- 启用HTTPS
- 配置安全头
Structured Data
结构化数据
- Organization schema (homepage)
- BreadcrumbList (all pages)
- Article schema (blog posts)
- FAQ schema (FAQ sections)
- Validate with Rich Results Test
---- 首页配置组织Schema
- 所有页面配置面包屑列表Schema
- 博客文章配置文章Schema
- FAQ区域配置FAQ Schema
- 使用富结果测试工具验证
---Quick Reference
快速参考
File Checklist
文件检查清单
public/
├── robots.txt ✓ Required
├── sitemap.xml ✓ Required
├── favicon.ico ✓ Required
├── og-image.jpg ✓ Required (1200x630)
└── manifest.json ○ Recommendedpublic/
├── robots.txt ✓ 必填
├── sitemap.xml ✓ 必填
├── favicon.ico ✓ 必填
├── og-image.jpg ✓ 必填(1200x630)
└── manifest.json ○ 推荐Meta Tag Lengths
元标签长度
| Tag | Length |
|---|---|
| Title | 50-60 characters |
| Description | 150-160 characters |
| OG Title | 60-90 characters |
| OG Description | 200 characters |
| Twitter Description | 200 characters |
| 标签 | 长度 |
|---|---|
| 标题 | 50-60字符 |
| 描述 | 150-160字符 |
| OG标题 | 60-90字符 |
| OG描述 | 200字符 |
| Twitter描述 | 200字符 |
Image Sizes
图片尺寸
| Image | Dimensions |
|---|---|
| OG Image | 1200 x 630 |
| Twitter Image | 1200 x 628 |
| Favicon | 32 x 32 |
| Apple Touch Icon | 180 x 180 |
| 图片 | 尺寸 |
|---|---|
| OG图片 | 1200 x 630 |
| Twitter图片 | 1200 x 628 |
| 网站图标 | 32 x 32 |
| Apple Touch Icon | 180 x 180 |