Astro SEO Complete Guide
Astro SEO Complete Guide
Section titled “Astro SEO Complete Guide”SEO (Search Engine Optimization) là yếu tố quyết định website của bạn có được tìm thấy trên Google hay không. Astro là framework tuyệt vờI cho SEO vì generate ra static HTML. Guide này cover tất cả aspects của SEO trên Astro.
1. Meta Tags cơ bản
Section titled “1. Meta Tags cơ bản”Layout với SEO component
Section titled “Layout với SEO component”src/components/SEO.astro:
---export interface Props { title: string; description: string; image?: string; type?: string; publishedTime?: string; modifiedTime?: string; author?: string; tags?: string[];}
const { title, description, image = '/default-og-image.jpg', type = 'website', publishedTime, modifiedTime, author, tags,} = Astro.props;
const canonicalURL = new URL(Astro.url.pathname, Astro.site);---
<!-- Primary Meta Tags --><title>{title}</title><meta name="title" content={title} /><meta name="description" content={description} /><link rel="canonical" href={canonicalURL} />
<!-- Open Graph / Facebook --><meta property="og:type" content={type} /><meta property="og:url" content={canonicalURL} /><meta property="og:title" content={title} /><meta property="og:description" content={description} /><meta property="og:image" content={new URL(image, Astro.site)} />
<!-- Twitter --><meta property="twitter:card" content="summary_large_image" /><meta property="twitter:url" content={canonicalURL} /><meta property="twitter:title" content={title} /><meta property="twitter:description" content={description} /><meta property="twitter:image" content={new URL(image, Astro.site)} />
<!-- Article specific -->{type === 'article' && ( <> {publishedTime && <meta property="article:published_time" content={publishedTime} />} {modifiedTime && <meta property="article:modified_time" content={modifiedTime} />} {author && <meta property="article:author" content={author} />} {tags?.map(tag => <meta property="article:tag" content={tag} />)} </>)}Sử dụng trong Layout
Section titled “Sử dụng trong Layout”src/layouts/Layout.astro:
---import SEO from '../components/SEO.astro';
interface Props { title: string; description: string; image?: string;}
const { title, description, image } = Astro.props;---
<!DOCTYPE html><html lang="vi"><head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width" />
<SEO title={title} description={description} image={image} />
<link rel="sitemap" href="/sitemap-index.xml" /></head><body> <slot /></body></html>2. Sitemap
Section titled “2. Sitemap”Auto-generate sitemap
Section titled “Auto-generate sitemap”npm install @astrojs/sitemapastro.config.mjs:
import sitemap from '@astrojs/sitemap';
export default defineConfig({ site: 'https://yoursite.com', integrations: [ sitemap({ filter: (page) => !page.includes('/admin'), changefreq: 'weekly', priority: 0.7, lastmod: new Date(), i18n: { defaultLocale: 'vi', locales: { vi: 'vi-VN', en: 'en-US', }, }, }), ],});Custom sitemap (nếu cần)
Section titled “Custom sitemap (nếu cần)”src/pages/sitemap.xml.js:
import { getCollection } from 'astro:content';
export async function GET() { const posts = await getCollection('blog'); const pages = [ { url: '/', changefreq: 'daily', priority: 1.0 }, { url: '/about', changefreq: 'monthly', priority: 0.8 }, ];
const sitemap = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> ${pages.map(page => ` <url> <loc>https://yoursite.com${page.url}</loc> <changefreq>${page.changefreq}</changefreq> <priority>${page.priority}</priority> </url> `).join('')} ${posts.map(post => ` <url> <loc>https://yoursite.com/blog/${post.slug}/</loc> <lastmod>${post.data.date.toISOString()}</lastmod> <changefreq>monthly</changefreq> <priority>0.6</priority> </url> `).join('')}</urlset>`;
return new Response(sitemap, { headers: { 'Content-Type': 'application/xml', }, });}3. RSS Feed
Section titled “3. RSS Feed”src/pages/rss.xml.js:
import rss from '@astrojs/rss';import { getCollection } from 'astro:content';
export async function GET(context) { const posts = await getCollection('blog');
return rss({ title: 'My Astro Blog', description: 'A blog about web development', site: context.site, items: posts.map((post) => ({ title: post.data.title, pubDate: post.data.date, description: post.data.excerpt, link: `/blog/${post.slug}/`, categories: post.data.tags, author: post.data.author, })), customData: `<language>vi-vn</language>`, });}4. Structured Data (JSON-LD)
Section titled “4. Structured Data (JSON-LD)”Schema.org markup
Section titled “Schema.org markup”src/components/Schema.astro:
---interface Props { type: 'website' | 'article' | 'person' | 'organization'; data: Record<string, any>;}
const { type, data } = Astro.props;
const schemas = { website: { '@context': 'https://schema.org', '@type': 'WebSite', name: data.title, url: data.url, description: data.description, }, article: { '@context': 'https://schema.org', '@type': 'BlogPosting', headline: data.title, description: data.description, image: data.image, datePublished: data.date, dateModified: data.modified || data.date, author: { '@type': 'Person', name: data.author, }, publisher: { '@type': 'Organization', name: 'Your Brand', logo: { '@type': 'ImageObject', url: 'https://yoursite.com/logo.png', }, }, }, person: { '@context': 'https://schema.org', '@type': 'Person', name: data.name, url: data.url, image: data.image, description: data.description, sameAs: data.socials, },};
const schema = schemas[type] || schemas.website;---
<script type="application/ld+json" set:html={JSON.stringify(schema)} />Sử dụng
Section titled “Sử dụng”---// Trong pageimport Schema from '../components/Schema.astro';---
<Schema type="article" data={{ title: post.data.title, description: post.data.excerpt, image: post.data.image, date: post.data.date, author: post.data.author, }}/>5. Robots.txt
Section titled “5. Robots.txt”public/robots.txt:
User-agent: *Allow: /
# Disallow admin routesDisallow: /adminDisallow: /api
# SitemapSitemap: https://yoursite.com/sitemap-index.xml
# Crawl-delay (optional)Crawl-delay: 10Hoặc generate dynamically:
src/pages/robots.txt.ts:
export function GET() { const robots = `User-agent: *Allow: /
Sitemap: ${import.meta.env.SITE}/sitemap-index.xml `.trim();
return new Response(robots, { headers: { 'Content-Type': 'text/plain' }, });}6. Image SEO
Section titled “6. Image SEO”Alt text bắt buộc
Section titled “Alt text bắt buộc”---import { Image } from 'astro:assets';---
<!-- ✅ Tốt cho SEO --><Image src={image} alt="Mô tả chi tiết về hình ảnh" width={800} height={400}/>
<!-- ❌ Không tốt cho SEO --><img src={image.src} />Structured image data
Section titled “Structured image data”<figure> <Image src={image} alt={caption} width={800} height={400} /> <figcaption>{caption}</figcaption></figure>7. URL Structure
Section titled “7. URL Structure”Semantic URLs
Section titled “Semantic URLs”✅ https://yoursite.com/blog/astro-seo-guide✅ https://yoursite.com/products/laptop-dell-xps❌ https://yoursite.com/p?id=123❌ https://yoursite.com/page.php?cat=tech&id=456Trailing slashes
Section titled “Trailing slashes”export default defineConfig({ trailingSlash: 'always', // hoặc 'never'});8. Internal Linking
Section titled “8. Internal Linking”Breadcrumb navigation
Section titled “Breadcrumb navigation”src/components/Breadcrumb.astro:
---const { items } = Astro.props;---
<nav aria-label="Breadcrumb"> <ol itemscope itemtype="https://schema.org/BreadcrumbList"> {items.map((item, index) => ( <li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem" > <a itemprop="item" href={item.url}> <span itemprop="name">{item.label}</span> </a> <meta itemprop="position" content={index + 1} /> </li> ))} </ol></nav>Related posts
Section titled “Related posts”---const { currentPost, allPosts } = Astro.props;
const relatedPosts = allPosts .filter(post => post.slug !== currentPost.slug && post.data.tags.some(tag => currentPost.data.tags.includes(tag)) ) .slice(0, 3);---
{relatedPosts.length > 0 && ( <aside> <h3>Bài viết liên quan</h3> <ul> {relatedPosts.map(post => ( <li> <a href={`/blog/${post.slug}/`}>{post.data.title}</a> </li> ))} </ul> </aside>)}9. Performance SEO
Section titled “9. Performance SEO”Core Web Vitals
Section titled “Core Web Vitals”| Metric | Target | Cách cải thiện |
|---|---|---|
| LCP | < 2.5s | Optimize images, preload fonts |
| FID | < 100ms | Reduce JS, code splitting |
| CLS | < 0.1 | Set image dimensions |
Preconnect và DNS-prefetch
Section titled “Preconnect và DNS-prefetch”<head> <!-- Preconnect external domains --> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<!-- DNS prefetch --> <link rel="dns-prefetch" href="https://analytics.example.com" /></head>10. International SEO (i18n)
Section titled “10. International SEO (i18n)”Multi-language setup
Section titled “Multi-language setup”astro.config.mjs:
export default defineConfig({ i18n: { defaultLocale: 'vi', locales: ['vi', 'en', 'ja'], routing: { prefixDefaultLocale: false, }, },});Hreflang tags
Section titled “Hreflang tags”<!-- Trong <head> --><link rel="alternate" hreflang="vi" href="https://yoursite.com/vi/page/" /><link rel="alternate" hreflang="en" href="https://yoursite.com/en/page/" /><link rel="alternate" hreflang="x-default" href="https://yoursite.com/page/" />11. Analytics & Monitoring
Section titled “11. Analytics & Monitoring”Google Analytics 4
Section titled “Google Analytics 4”<!-- Trong <head> --><script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX"></script><script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-XXXXXXXX');</script>Google Search Console
Section titled “Google Search Console”- Add property: https://search.google.com/search-console
- Verify ownership (HTML tag hoặc DNS)
- Submit sitemap
- Monitor performance
Tools hữu ích
Section titled “Tools hữu ích”| Tool | Mục đích |
|---|---|
| Google Search Console | Monitor SEO performance |
| Google Analytics | Track traffic |
| Lighthouse | Audit SEO & Performance |
| Screaming Frog | Crawl & analyze site |
| Ahrefs/SEMrush | Keyword research |
| Schema.org | Structured data validator |