SEO khi triển khai SvelteKit — bảng tra nhanh
SvelteKit đã kết xuất các trang của bạn trên máy chủ — phần đó đã được xử lý. Trang này nói về quyết định *tiếp theo*: trang web của bạn được xây dựng và triển khai như thế nào. Một **adapter** đóng gói ứng dụng SvelteKit cho một máy chủ lưu trữ (máy chủ tệp tĩnh, máy chủ Node hoặc một dịch vụ như Vercel hay Cloudflare), còn thiết lập **prerender** theo từng trang quyết định trang đó được chuyển thành tệp HTML thuần từ trước hay được kết xuất mới ở mỗi lượt truy cập. Hai lựa chọn này quyết định trình thu thập dữ liệu nhận HTML nhanh đến đâu — và SvelteKit sẽ không tạo sitemap hay robots.txt cho bạn, nên bạn phải tự bổ sung chúng.
SvelteKit đã kết xuất các trang của bạn trên máy chủ — phần đó đã được xử lý. Trang này nói về quyết định *tiếp theo*: trang web của bạn được xây dựng và triển khai như thế nào. Một **adapter** đóng gói ứng dụng SvelteKit cho một máy chủ lưu trữ (máy chủ tệp tĩnh, máy chủ Node hoặc một dịch vụ như Vercel hay Cloudflare), còn thiết lập **prerender** theo từng trang quyết định trang đó được chuyển thành tệp HTML thuần từ trước hay được kết xuất mới ở mỗi lượt truy cập. Hai lựa chọn này quyết định trình thu thập dữ liệu nhận HTML nhanh đến đâu — và SvelteKit sẽ không tạo sitemap hay robots.txt cho bạn, nên bạn phải tự bổ sung chúng.
TL;DR — SvelteKit đã kết xuất các trang của bạn trên máy chủ — phần đó đã được xử lý. Trang này nói về quyết định tiếp theo: trang web của bạn được xây dựng và triển khai như thế nào. Một adapter đóng gói ứng dụng SvelteKit cho một máy chủ lưu trữ (máy chủ tệp tĩnh, máy chủ Node hoặc một dịch vụ như Vercel hay Cloudflare), còn thiết lập prerender theo từng trang quyết định trang đó được chuyển thành tệp HTML thuần từ trước hay được kết xuất mới ở mỗi lượt truy cập. Hai lựa chọn này quyết định trình thu thập dữ liệu nhận HTML nhanh đến đâu — và SvelteKit sẽ không tạo sitemap hay robots.txt cho bạn, nên bạn phải tự bổ sung chúng.
Adapter là gì (nói một cách đơn giản)
Nếu đã xây dựng một trang SvelteKit, bạn biết rằng nó gửi HTML thực đến trình duyệt — nội dung đã có sẵn trước khi JavaScript chạy. Tốt. Như vậy, bài toán SEO khó đã được giải quyết (còn nếu trường hợp của bạn chưa được giải quyết, bài viết về kiến thức nền tảng SvelteKit trong cùng phần này trình bày các chế độ kết xuất và cái bẫy “vỏ rỗng” mà bạn cần tránh trước tiên).
Một adapter là plugin nhỏ nhận bản dựng SvelteKit đã hoàn tất và chuyển nó thành dạng mà một máy chủ lưu trữ cụ thể có thể chạy. Bằng chứng cho nhận định này SvelteKit adapters transform a built application for deployment to a particular environment. Phạm vi: SvelteKit adapters. Độ tin cậy: cao · Đã xác minh: SvelteKit: Adapters Cùng một trang web, cách đóng gói khác nhau:
adapter-staticbiến mỗi trang thành một tệp HTML thuần, được xây dựng một lần. Rất phù hợp cho blog, tài liệu hoặc trang tiếp thị không thay đổi theo từng khách truy cập.adapter-nodebọc ứng dụng của bạn trong một máy chủ Node.js do bạn tự vận hành.adapter-vercel,adapter-netlify,adapter-cloudflaređóng gói ứng dụng cho các dịch vụ lưu trữ tương ứng; các dịch vụ này kết xuất trang theo yêu cầu — đôi khi trên các máy chủ “ở biên”, nằm gần khách truy cập về mặt địa lý.
Nội dung giống hệt nhau trong mọi trường hợp. Điều thay đổi là HTML được tạo ra khi nào (từ trước hoặc theo từng yêu cầu) và ở đâu (trên một máy chủ hoặc một mạng lưới toàn cầu).
Vì sao đây là một quyết định SEO, không chỉ là quyết định kỹ thuật
Điều quan trọng nhất: tốc độ. Một trang đã là tệp tĩnh sẽ tải gần như tức thì. Một trang phải được tạo trên máy chủ sẽ mất một chút thời gian. Và Google đã nói rõ rằng nếu trang web của bạn “phản hồi nhanh trong một thời gian, giới hạn sẽ tăng lên, nghĩa là có thể sử dụng nhiều kết nối hơn để thu thập dữ liệu. Nếu trang web chậm lại… giới hạn sẽ giảm xuống và Google thu thập dữ liệu ít hơn.” Vì vậy, một phương án triển khai chậm không chỉ gây khó chịu cho người dùng — nó còn có thể khiến Google đọc được ít nội dung hơn trên trang web của bạn.
Phiên bản đơn giản của quyết định này
- Trang web nội dung (blog, tài liệu, tiếp thị) → dùng
adapter-staticvà kết xuất trước mọi thứ. Nhanh nhất có thể, không có gì để hỏng. - Trang web nội dung có một vài phần động (tìm kiếm, bình luận) → dùng adapter máy chủ (
node/vercel/cloudflare) và đánh dấu các trang nội dung bằngprerender = true, còn các phần động được kết xuất theo yêu cầu. - Ứng dụng hoặc bảng điều khiển có các trang đăng nhập, được cá nhân hóa → kết xuất trên máy chủ (SSR), chỉ kết xuất trước các trang tiếp thị công khai.
Đừng quên hai tệp mà SvelteKit sẽ không tạo cho bạn
SvelteKit không tự động tạo sitemap.xml hoặc robots.txt. Bạn phải tự thêm chúng — thường là một tệp endpoint nhỏ (sitemap.xml/+server.js) và một tệp trong thư mục static/, hoặc một endpoint khác cho robots.txt. Bằng chứng cho nhận định này SvelteKit can serve static assets from its static directory and create custom responses with +server route files. Phạm vi: Mechanisms for robots.txt and sitemap.xml; files are not generated automatically. Độ tin cậy: cao · Đã xác minh: SvelteKit: Project structure SvelteKit: Routing Điều này rất dễ bị bỏ quên vì hầu hết framework kết xuất HTML cho bạn đều tạo cảm giác “đầy đủ”. Hai tệp này thì không.
Bạn muốn xem phiên bản chuyên sâu hơn — mỗi adapter tác động thế nào đến việc kết xuất, prerender = 'auto' xử lý một trang web hỗn hợp ra sao, vì sao các hàm edge không thể đọc tệp và chiến lược sitemap thay đổi thế nào theo adapter? Hãy chuyển sang tab Advanced.
TL;DR — Adapter không thay đổi SvelteKit kết xuất nội dung gì — nó thay đổi ở đâu và khi nào: dạng tĩnh tại thời điểm build (
adapter-static), theo yêu cầu trên máy chủ do bạn vận hành (adapter-node), hoặc theo yêu cầu trên các hàm serverless/edge (adapter-vercel/-netlify/-cloudflare).prerender = truetheo từng route tạo HTML tĩnh và loại route khỏi manifest động;prerender = 'auto'vừa kết xuất trước vừa giữ route trong manifest — công cụ dành cho các trang hỗn hợp/blog/[slug]. Runtime edge chạy trên các isolate V8: không cófscủa Node, và cold start làm TTFB xấu đi, từ đó ảnh hưởng đến LCP và (theo tài liệu của Google về crawl budget) khả năng thu thập dữ liệu. SvelteKit không tạo sitemap.xml hay robots.txt — hãy xây dựng chúng dưới dạng endpoint+server.js, đồng thời lưu ý rằng chiến lược phụ thuộc vào adapter. Đây là bài viết đồng hành có phạm vi hẹp hơn, tập trung vào triển khai, với bài kiến thức nền tảng về SEO cho SvelteKit trong phần này; tôi giả định bạn đã biết SvelteKit mặc định dùng SSR và sẽ không tranh luận lại điều đó ở đây.
Một ý tưởng giúp mọi thứ trở nên sáng tỏ
Adapter không thay đổi nội dung được kết xuất. Nó thay đổi ở đâu và khi nào. Chỉ có vậy. Tài liệu SvelteKit diễn đạt rất chính xác: adapter “nhận ứng dụng đã build làm đầu vào và tạo đầu ra để triển khai.” Bằng chứng cho nhận định này SvelteKit adapters take the built application as input and generate deployment-specific output. Phạm vi: Deployment output; adapter choice can still constrain supported runtime features. Độ tin cậy: cao · Đã xác minh: SvelteKit: Adapters Các component, hàm load và metadata <svelte:head> của bạn — đều giống hệt nhau trên mọi adapter. Điểm khác biệt là:
- HTML được tạo ra khi nào: tại thời điểm build (tĩnh/được kết xuất trước) hoặc tại thời điểm yêu cầu (SSR trên máy chủ, hàm serverless hoặc hàm edge).
- HTML được tạo ra ở đâu: trên một máy chủ gốc duy nhất, một hàm serverless theo khu vực hoặc một mạng edge gần khách truy cập.
Mọi nội dung bên dưới đều là hệ quả của hai trục này.
Vì sao lựa chọn triển khai cũng là lựa chọn SEO
Chuỗi quan hệ này ngắn và có tài liệu rõ ràng: TTFB → LCP → khả năng thu thập dữ liệu.
Time to first byte là khoảng thời gian máy chủ lưu trữ cần để bắt đầu gửi phản hồi. Một tệp được kết xuất trước và phục vụ từ bộ nhớ đệm CDN có TTFB gần bằng không. Một máy chủ phải kết xuất trang có TTFB cao hơn. Một hàm serverless hoặc edge phải cold start có thể có TTFB cao hơn nhiều ở lượt truy cập đầu tiên. TTFB là đầu vào trực tiếp của Largest Contentful Paint — bạn không thể hiển thị thứ mình chưa nhận được — và LCP là một tín hiệu Core Web Vitals.
Về khía cạnh thu thập dữ liệu, Google đưa ra tuyên bố rõ ràng nhất. Theo tài liệu về crawl budget: “Nếu trang web phản hồi nhanh trong một thời gian, giới hạn sẽ tăng lên, nghĩa là có thể sử dụng nhiều kết nối hơn để thu thập dữ liệu. Nếu trang web chậm lại hoặc phản hồi bằng lỗi máy chủ, giới hạn sẽ giảm xuống và Google thu thập dữ liệu ít hơn.” Và dòng hướng dẫn thực hành tốt nhất: “Hãy làm cho các trang của bạn tải hiệu quả. Nếu Google có thể tải và kết xuất các trang nhanh hơn, chúng tôi có thể đọc được nhiều nội dung hơn từ trang web của bạn.” Một hàm edge cold start phản hồi chậm chịu tác động theo cùng cơ chế với một máy chủ gốc chậm.
Một lưu ý thẳng thắn ngay từ đầu: Google không công bố hướng dẫn dành riêng cho SvelteKit. Không có tài liệu hay tập Search Off the Record nào nêu tên adapter SvelteKit, prerender = 'auto' hoặc cold start ở edge. Điều tôi làm ở đây là áp dụng hướng dẫn chung của Google về kết xuất và crawl budget vào cơ chế cụ thể của SvelteKit — không phải trích lời một đại diện từng bình luận về SvelteKit, vì chưa có ai làm vậy. Nhận định của Google rằng “kết xuất phía máy chủ hoặc kết xuất trước vẫn là một ý tưởng tuyệt vời vì nó giúp trang web nhanh hơn cho người dùng và trình thu thập dữ liệu, đồng thời không phải bot nào cũng có thể chạy JavaScript” là cơ sở chính thức gần nhất và không phụ thuộc framework.
Chọn adapter để đạt kết quả SEO mong muốn
adapter-auto — lựa chọn mặc định không cần cấu hình và giới hạn của nó
Các dự án SvelteKit mới đi kèm adapter-auto. Nó phát hiện nền tảng — Vercel, Netlify, Cloudflare Pages, Azure, AWS — và cài đặt adapter tương ứng tại thời điểm build. Đây là điểm khởi đầu ổn, nhưng có một giới hạn cứng đáng biết: adapter-auto không nhận bất kỳ tùy chọn nào. Ngay khi cần { edge: true }, binding Cloudflare, Vercel ISR hoặc bất kỳ cấu hình riêng cho nền tảng nào, bạn phải cài trực tiếp adapter nền tảng (adapter-vercel, adapter-cloudflare, v.v.). Hãy xem auto là bộ khung ban đầu, không phải quyết định cho môi trường production.
adapter-static — SSG toàn phần, dành cho trang web ưu tiên nội dung
adapter-static kết xuất trước toàn bộ trang web thành các tệp tĩnh tại thời điểm build. Không có máy chủ nào chạy; máy chủ lưu trữ phục vụ HTML phẳng. Bằng chứng cho nhận định này adapter-static prerenders a SvelteKit site as static files. Phạm vi: Routes must be prerenderable; performance outcomes depend on hosting and page design. Độ tin cậy: cao · Đã xác minh: SvelteKit: Static site generation Với một trang web ưu tiên nội dung, đây là cấu hình SEO mạnh nhất bạn có thể có — TTFB thấp nhất, không có cold start, không có gì để ngừng hoạt động. Yêu cầu duy nhất chính là cái bẫy được trình bày kỹ trong bài kiến thức nền tảng: SSR phải được bật trong quá trình build, nếu không bạn sẽ nhận được các vỏ rỗng thay vì HTML đã kết xuất. Ngoài việc lưu ý điểm đó, tôi sẽ không giải thích lại ở đây.
Điểm đánh đổi là sự cứng nhắc. Bất kỳ thứ gì thực sự cần logic máy chủ theo từng yêu cầu (tìm kiếm thực, nội dung theo từng người dùng, xử lý biểu mẫu mà không có endpoint bên thứ ba) đều không thể tồn tại trong một bản dựng hoàn toàn tĩnh — và đó chính là mục đích của các adapter tiếp theo.
adapter-node — máy chủ do bạn kiểm soát
adapter-node tạo ra một máy chủ Node.js độc lập. Bạn vận hành nó, mở rộng quy mô cho nó và chịu trách nhiệm về TTFB. Đây là lựa chọn linh hoạt nhất và ít gây bất ngờ nhất về runtime — có đầy đủ API Node, bao gồm fs. Nó phù hợp khi bạn đã có hạ tầng, cần các thư viện Node mà runtime edge không chạy được hoặc muốn thời gian phản hồi có thể dự đoán từ một máy chủ đang ấm (không phải cold start). Đánh đổi nằm ở vận hành: bạn đang chạy một máy chủ, và tốc độ cùng thời gian hoạt động của nó giờ trở thành khả năng thu thập dữ liệu của bạn.
adapter-vercel — serverless, edge và ISR
Theo mặc định, adapter-vercel triển khai lên các hàm serverless của Vercel, với một số công cụ điều chỉnh liên quan đến SEO được thiết lập theo từng route qua export const config:
runtime: 'edge'chuyển route đó sang runtime edge của Vercel (xem thêm bên dưới).regionskiểm soát nơi các hàm serverless chạy — gần người dùng (hoặc cơ sở dữ liệu) hơn nghĩa là độ trễ thấp hơn.isrbật Incremental Static Regeneration:isr: { expiration: 60 }phục vụ một tài nguyên tĩnh đã được lưu trong bộ nhớ đệm và tái tạo nó sau khoảng thời gian đó, mang lại “lợi thế về hiệu năng và chi phí của nội dung được kết xuất trước cùng tính linh hoạt của nội dung được kết xuất động.” ISR là con đường thứ tư thực sự giữa hoàn toàn tĩnh và hoàn toàn SSR — nhưng hãy lưu ý cảnh báo trong chính tài liệu: “Việc dùng ISR trên một route cóexport const prerender = truesẽ không có tác dụng, vì route đó đã được kết xuất trước tại thời điểm build.” ISR và prerender là các phương án thay thế, không thể xếp chồng.
adapter-cloudflare — Workers/Pages, edge toàn cầu
adapter-cloudflare nhắm đến Cloudflare Workers và Pages — SSR trên một mạng edge toàn cầu, thường cho TTFB thấp nhất với nhóm người dùng phân bố rộng về địa lý. Hạn chế quan trọng là runtime: Workers chạy trên các isolate V8, không phải Node. Theo tài liệu: “Bạn không thể dùng fs trong Cloudflare Workers.” Một số API Node chỉ hoạt động khi bật cờ tương thích nodejs_compat, và ngay cả khi đó mức hỗ trợ cũng không tương đương hoàn toàn. Nếu bạn đang đọc tệp tại thời điểm yêu cầu (bản đồ chuyển hướng, tệp dữ liệu, đầu vào ảnh OG tùy chỉnh), đoạn mã đó cần được thiết kế lại — phần về edge bên dưới sẽ trình bày vấn đề này.
(adapter-cloudflare-workers cũ đã ngừng được khuyến nghị; dự án mới dùng adapter-cloudflare, hỗ trợ cả Workers lẫn Pages. Nếu bạn vẫn dùng adapter cũ, chuyển đổi sang adapter mới là hướng được khuyến nghị.)
adapter-netlify — functions hoặc Edge Functions (Deno)
Theo mặc định, adapter-netlify triển khai lên các hàm dựa trên Node của Netlify, hoặc lên Edge Functions dựa trên Deno với edge: true. Mô hình giống Vercel: mặc định là serverless và có thể chọn dùng edge. Một lưu ý riêng cho SvelteKit — Netlify Forms yêu cầu trang chứa biểu mẫu phải được kết xuất trước để Netlify có thể phát hiện markup của biểu mẫu tại thời điểm triển khai; đây là một yêu cầu nhỏ “hãy kết xuất trước route này” bổ sung trên lựa chọn adapter.
Quyết định, mỗi lựa chọn trong một dòng
- Trang web thuần nội dung →
adapter-static, kết xuất trước mọi thứ. - Trang web nội dung có các phần động →
adapter-node/-vercel/-cloudflare, dùngprerender = truecho nội dung vàfalse/'auto'cho các route động. - Ứng dụng/bảng điều khiển có cá nhân hóa → ưu tiên SSR (node hoặc edge), chỉ kết xuất trước phần khung tĩnh (tiếp thị, đăng nhập).
- Nhóm người dùng toàn cầu, TTFB có tính quyết định → dùng adapter edge cho các route động, đồng thời chấp nhận hạn chế của API Node và thực tế về cold start.
(Tab Decision Tree trình bày quyết định này dưới dạng một luồng phân nhánh.)
Chiến lược kết xuất trước cho các trang web hỗn hợp
true / false / 'auto' thực sự làm gì
export const prerender là một tùy chọn trang theo từng route (hoặc từng layout), và ba giá trị này không chỉ đơn giản là bật/tắt:
true— tạo HTML tĩnh cho route này tại thời điểm build. Điểm quan trọng là route đó “bị loại khỏi các manifest dùng cho SSR động, khiến máy chủ (hoặc các hàm serverless/edge) nhỏ hơn.” Sau khi được kết xuất trước, route không thể quay về kết xuất động — nó là tĩnh, hoàn toàn như vậy.false— luôn kết xuất theo yêu cầu. Không có tệp tĩnh.'auto'— công cụ cho trang web hỗn hợp. Nó kết xuất trước route và giữ route trong manifest máy chủ động, vì vậy cùng một route có thể được phục vụ dưới dạng tĩnh cho các đường dẫn đã biết và được kết xuất phía máy chủ cho phần còn lại. Cơ chế này được xây dựng chính xác cho trường hợp mà tài liệu mô tả: một route như/blog/[slug], “nơi bạn muốn kết xuất trước nội dung mới nhất/phổ biến nhất nhưng kết xuất phía máy chủ phần đuôi dài.”
Vì các route được kết xuất trước làm giảm kích thước gói máy chủ, một trang web phần lớn được kết xuất trước với vài route 'auto'/false sẽ triển khai một hàm nhỏ hơn, rẻ hơn và nhanh hơn — một lợi ích hiệu quả độc lập với SEO.
Route động cần một hàm entries
Trình thu thập dữ liệu của quá trình prerender khám phá trang bằng cách đi theo các liên kết <a> từ những điểm đầu vào. Cách này hiệu quả với route tĩnh, nhưng một route động như /blog/[slug] không có URL cố định để trình thu thập dữ liệu tìm thấy. Nếu không có gì liên kết đến một slug cụ thể, SvelteKit sẽ không biết slug đó tồn tại — và bạn sẽ gặp lỗi build kinh điển rằng các route “được đánh dấu là có thể kết xuất trước nhưng chưa được kết xuất trước.”
Cách khắc phục là dùng một hàm entries rõ ràng (hoặc config.kit.prerender.entries) để liệt kê các giá trị tham số:
// src/routes/blog/[slug]/+page.server.js
export const prerender = true;
export function entries() {
return [
{ slug: 'hello-world' },
{ slug: 'sveltekit-deployment-seo' },
];
}Trong thực tế, bạn tạo danh sách đó từ CMS hoặc thư mục nội dung. Nếu không có danh sách này, quá trình prerender chỉ bao phủ các slug mà trình thu thập liên kết tình cờ tìm thấy.
Mẫu /blog/[slug] trong thực tế
Kết hợp hai phần lại, bạn có cấu hình chuẩn cho trang web hỗn hợp: prerender = 'auto' cùng một hàm entries trả về các bài viết mới và phổ biến. Những bài đó nhận HTML tĩnh tại thời điểm build; bất kỳ bài nào không có trong danh sách sẽ chuyển sang SSR theo yêu cầu. Bài viết mới được kết xuất động cho đến khi bản build tiếp theo kết xuất trước chúng. Đây là điểm cân bằng thực dụng giữa “kết xuất trước toàn bộ 40.000 bài viết ở mỗi lần build” và “kết xuất mọi bài viết ở mọi yêu cầu”.
Các hạn chế của runtime edge ảnh hưởng đến SEO
config.runtime = 'edge' áp dụng theo từng route (trên Vercel)
Edge không phải là một công tắc tất-cả-hoặc-không-gì. Trên Vercel, đây là một tùy chọn trang theo từng route:
// +page.server.js or +server.js
export const config = { runtime: 'edge' };Điều đó có nghĩa là bạn có thể đẩy các route có lưu lượng cao, có thể lưu trong bộ nhớ đệm ra edge để có TTFB thấp, trong khi vẫn giữ các route phụ thuộc Node trên runtime serverless (Node) tiêu chuẩn trong cùng một lần triển khai. Hãy kết hợp có chủ đích.
Không có fs, không có các API Node tùy ý
Các runtime edge — Cloudflare Workers, Vercel Edge Functions, Netlify Deno Edge Functions — không cung cấp fs của Node. Tài liệu Cloudflare nói: “Bạn không thể dùng fs trong Cloudflare Workers.” Tài liệu Vercel nói: “Bạn không thể dùng fs trong các hàm edge.” Cả hai đều chỉ ra hai lối thoát giống nhau: dùng trợ giúp read từ $app/server để truy cập tài nguyên được đóng gói, hoặc “kết xuất trước các route liên quan” để việc truy cập tệp diễn ra tại thời điểm build thay vì thời điểm yêu cầu.
Các trường hợp liên quan gián tiếp đến SEO mà hạn chế này gây vướng mắc gồm: tạo ảnh OG động có đọc tệp phông chữ hoặc mẫu, bản đồ chuyển hướng dựa trên tệp, hoặc endpoint sitemap đọc nội dung từ đĩa. Mỗi trường hợp phải chuyển sang read() của $app/server hoặc chuyển sang thời điểm prerender/build. Đây không phải rào cản — mà là hạn chế “cần biết trước khi chọn edge”.
Cold start và TTFB — khi nào edge hữu ích và khi nào không
Các hàm edge vẫn có cold start. Một hàm edge lạnh ở yêu cầu đầu tiên có thể chậm hơn máy chủ Node đã ấm, và chậm hơn đáng kể so với tệp được kết xuất trước phục vụ từ bộ nhớ đệm. Edge phát huy lợi thế khi hàm luôn ấm hoặc khi được kết hợp với chiến lược lưu đệm mạnh để phần lớn yêu cầu không bao giờ chạm đến hàm. Nó không tự động là lựa chọn nhanh nhất — “triển khai ra edge” không đồng nghĩa với “nhanh hơn”. Với trang web nội dung, đầu ra tĩnh được kết xuất trước luôn thắng edge SSR về TTFB, vì không có hàm nào cần khởi động.
Tạo sitemap.xml và robots.txt (SvelteKit sẽ không làm việc này)
Đây là khoảng trống mà hầu hết hướng dẫn SvelteKit bỏ qua và hầu hết cuộc kiểm tra phát hiện ra. SvelteKit không tự động tạo sitemap.xml và cũng không tự động tạo robots.txt — bất kể adapter nào, bất kể bạn kết xuất trước bao nhiêu trang. Một trang web hoàn toàn tĩnh với hàng nghìn trang được kết xuất trước vẫn không có sitemap nếu bạn không tự xây dựng nó.
Mẫu endpoint +server.js
Cách viết sitemap theo đúng lối SvelteKit là một endpoint route trả về XML với Content-Type phù hợp:
// src/routes/sitemap.xml/+server.js
export const prerender = true; // needed on adapter-static
export async function GET() {
const urls = await getAllUrls(); // from your CMS/content
const body = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map((u) => ` <url><loc>${u}</loc></url>`).join('\n')}
</urlset>`;
return new Response(body, {
headers: { 'Content-Type': 'application/xml' },
});
}Chiến lược phụ thuộc vào adapter của bạn
Đây là phần liên kết toàn bộ bài viết: chiến lược sitemap của bạn là hệ quả phía sau của lựa chọn adapter.
- Trên
adapter-static, endpoint sitemap cầnexport const prerender = trueđể được đưa vào đầu ra tĩnh — không có máy chủ lúc runtime để tạo sitemap theo yêu cầu. Sitemap được tạo sẵn tại thời điểm build, nghĩa là độ mới của nó chỉ bằng lần build gần nhất. - Trên adapter Node/serverless/edge, cùng endpoint đó có thể tạo sitemap động theo từng yêu cầu từ CMS hoặc cơ sở dữ liệu — luôn cập nhật, không cần build lại. (Trên adapter edge, hãy nhớ hạn chế
fs: lấy URL từ API hoặc binding, không đọc từ đĩa.)
Vì vậy, câu hỏi “sitemap của tôi nên là tĩnh hay động?” không phải một quyết định riêng — câu trả lời phát sinh từ adapter bạn đã chọn.
robots.txt: tệp tĩnh hay endpoint
Có hai lựa chọn. Đặt một tệp robots.txt thuần trong thư mục static/ (tự động được phục vụ tại /robots.txt); đây là lựa chọn đơn giản nhất và phù hợp với hầu hết trang web. Hoặc tạo nó từ endpoint src/routes/robots.txt/+server.js khi bạn cần nội dung khác nhau theo môi trường (chẳng hạn chặn trình thu thập dữ liệu trên staging và cho phép chúng trên production). Dù theo cách nào, đừng chặn gói /_app/ hoặc CSS — điều đó làm hỏng việc kết xuất đối với các công cụ tìm kiếm có thực hiện kết xuất.
Nếu bạn tiếp cận vấn đề này từ góc nhìn rộng hơn về framework hoặc JavaScript SEO, logic “việc kết xuất diễn ra ở đâu và khi nào” tại đây cũng là logic chi phối JavaScript SEO nói chung; bài kiến thức nền tảng SvelteKit trong phần này trình bày các chế độ kết xuất và mẫu metadata mà bài viết này xây dựng dựa trên.
Tóm tắt bằng AI
Phiên bản cô đọng của phần Advanced:
- Adapter thay đổi ở đâu và khi nào, không phải nội dung gì. Adapter “nhận ứng dụng đã build làm đầu vào và tạo đầu ra để triển khai” — cùng nội dung, khác thời điểm (build so với thời điểm yêu cầu) và vị trí (máy chủ gốc so với edge).
- Vì sao đây là quyết định SEO: TTFB → LCP → khả năng thu thập dữ liệu. Google: nếu trang web “phản hồi nhanh… giới hạn sẽ tăng… Nếu trang web chậm lại… Google thu thập dữ liệu ít hơn.” Không có hướng dẫn nào của Google nêu cụ thể SvelteKit — đây là hướng dẫn chung được áp dụng vào cơ chế SvelteKit.
- Adapter:
adapter-auto(không cần cấu hình, không có tùy chọn);adapter-static(SSG, trang nội dung, TTFB thấp nhất);adapter-node(máy chủ do bạn kiểm soát, đầy đủ API Node);adapter-vercel(serverless + edge + ISR);adapter-cloudflare(Workers edge toàn cầu, không cófs;adapter-cloudflare-workersđã ngừng được khuyến nghị);adapter-netlify(functions hoặc Deno Edge Functions). - Prerender:
truetạo HTML tĩnh và loại route khỏi manifest động;falseluôn dùng SSR;'auto'vừa kết xuất trước vừa giữ route ở dạng động — công cụ cho trang web hỗn hợp với/blog/[slug](kết xuất trước nội dung phổ biến, SSR phần đuôi dài). - Route động cần một hàm
entries, nếu không bạn sẽ gặp lỗi “được đánh dấu là có thể kết xuất trước nhưng chưa được kết xuất trước”. - Hạn chế của edge:
runtime: 'edge'áp dụng theo từng route (Vercel); không cófs(“Bạn không thể dùng fs trong Cloudflare Workers” / các hàm edge) — dùngread()của$app/serverhoặc kết xuất trước; cold start có thể khiến edge chậm hơn máy chủ đã ấm hoặc tệp tĩnh. - Không có sitemap/robots.txt tích hợp sẵn. Xây dựng endpoint
sitemap.xml/+server.js(prerender = truetrênadapter-static; động trên adapter server/edge). robots.txt quastatic/hoặc một endpoint. - ISR ≠ prerender-plus: “Việc dùng ISR trên một route có
export const prerender = truesẽ không có tác dụng.” Chúng là các phương án thay thế.
Tài liệu chính thức
Tài liệu nguồn chính thức từ SvelteKit và các công cụ tìm kiếm.
SvelteKit
- Adapters • Tài liệu SvelteKit — tổng quan: adapter nhận ứng dụng đã build và tạo đầu ra triển khai.
- Triển khai không cần cấu hình (adapter-auto) • Tài liệu SvelteKit — khả năng phát hiện theo từng nền tảng và hạn chế “does not take any options” Bản dịch: “không nhận bất kỳ tùy chọn nào”.
- Máy chủ Node (adapter-node) • Tài liệu SvelteKit — máy chủ Node độc lập, biến môi trường, tắt máy chủ an toàn.
- Tạo trang tĩnh (adapter-static) • Tài liệu SvelteKit — SSG cho toàn bộ website, yêu cầu về SSR và cảnh báo SEO đối với phương án dự phòng SPA.
- Vercel (adapter-vercel) • Tài liệu SvelteKit —
runtime,regions,splittheo từng route và Tái tạo tĩnh tăng dần. - Cloudflare (adapter-cloudflare) • Tài liệu SvelteKit — Workers/Pages, các binding
platform.env,nodejs_compatvà hạn chế củafs. - Cloudflare Workers (adapter-cloudflare-workers, không còn được khuyến nghị) • Tài liệu SvelteKit — adapter cũ không còn được khuyến nghị và lộ trình di chuyển.
- Netlify (adapter-netlify) • Tài liệu SvelteKit — Node Functions so với Edge Functions dựa trên Deno (
edge: true) và yêu cầu prerender cho Forms. - Tùy chọn trang (prerender, ssr, csr, config) • Tài liệu SvelteKit —
prerender = true/false/'auto', hàmentriesvàconfigtheo từng route, bao gồmruntime: 'edge'.
- Tìm hiểu kiến thức cơ bản về SEO JavaScript — hàng đợi kết xuất và nhận định “not all bots can run JavaScript.” Bản dịch: “không phải bot nào cũng có thể chạy JavaScript”.
- Tối ưu hóa ngân sách thu thập dữ liệu — khả năng thu thập dữ liệu gắn với tốc độ phản hồi; “make your pages efficient to load.” Bản dịch: “hãy giúp các trang tải hiệu quả”.
Bing / Microsoft
- Loạt bài về bingbot: JavaScript, Dynamic Rendering và Cloaking. Trời ơi! — khuyến nghị của Bing về prerender/dynamic rendering và phần làm rõ về cloaking.
- Hiệu suất front-end nhanh cho Microsoft Bing — kiến trúc SSR + CDN/nút biên của chính Bing như một minh chứng thực tế.
Trích dẫn từ nguồn
Các phát biểu công khai trong tài liệu SvelteKit, Google và Bing. Mỗi liên kết là một liên kết sâu dẫn thẳng đến đoạn được trích trên trang nguồn.
Tài liệu SvelteKit — adapter và tùy chọn trang
- “adapter-auto does not take any options.” Bản dịch: “adapter-auto không nhận bất kỳ tùy chọn nào.” — nói về adapter mặc định không cần cấu hình. Chuyển đến trích dẫn
- Về
prerender = true— các route được prerender sẽ “excluded from manifests used for dynamic SSR, making your server (or serverless/edge functions) smaller.” Bản dịch: “bị loại khỏi các manifest dùng cho SSR động, giúp máy chủ (hoặc các hàm serverless/edge) nhỏ hơn.” Chuyển đến trích dẫn - Về
'auto'— trường hợp/blog/[slug]khi bạn muốn “prerender your most recent/popular content but server-render the long tail.” Bản dịch: “prerender nội dung mới nhất/phổ biến nhất nhưng kết xuất phía máy chủ phần đuôi dài.” Chuyển đến trích dẫn - Về hạn chế
fsở edge — “You can’t use fs in Cloudflare Workers.” Bản dịch: “Bạn không thể dùng fs trong Cloudflare Workers.” Chuyển đến trích dẫn - Về Vercel ISR so với prerender — “Using ISR on a route with export const prerender = true will have no effect, since the route is prerendered at build time.” Bản dịch: “Dùng ISR trên một route có export const prerender = true sẽ không có tác dụng, vì route đó được prerender tại thời điểm build.” Chuyển đến trích dẫn
Google — kết xuất và ngân sách thu thập dữ liệu
- “Keep in mind that server-side or pre-rendering is still a great idea because it makes your website faster for users and crawlers, and not all bots can run JavaScript.” Bản dịch: “Hãy nhớ rằng kết xuất phía máy chủ hoặc kết xuất trước vẫn là một ý tưởng tuyệt vời vì giúp website nhanh hơn cho người dùng và trình thu thập dữ liệu, đồng thời không phải bot nào cũng có thể chạy JavaScript.” Chuyển đến trích dẫn
- “If the site responds quickly for a while, the limit goes up, meaning more connections can be used to crawl. If the site slows down or responds with server errors, the limit goes down and Google crawls less.” Bản dịch: “Nếu website phản hồi nhanh trong một khoảng thời gian, giới hạn sẽ tăng lên, nghĩa là có thể dùng nhiều kết nối hơn để thu thập dữ liệu. Nếu website chậm lại hoặc phản hồi bằng lỗi máy chủ, giới hạn sẽ giảm và Google thu thập dữ liệu ít hơn.” Chuyển đến trích dẫn
- “Make your pages efficient to load. If Google can load and render your pages faster, we might be able to read more content from your site.” Bản dịch: “Hãy giúp các trang của bạn tải hiệu quả. Nếu Google có thể tải và kết xuất trang nhanh hơn, chúng tôi có thể đọc được nhiều nội dung hơn từ website của bạn.” Chuyển đến trích dẫn
Bing — prerender và kiến trúc edge của chính Bing
- “We encourage detecting our bingbot user agent, prerendering the content on the server side and outputting static HTML for such sites…” Bản dịch: “Chúng tôi khuyến khích phát hiện user agent bingbot, prerender nội dung ở phía máy chủ và xuất HTML tĩnh cho những website như vậy…” — Fabrice Canel & Frédéric Dubut, Microsoft Bing. Chuyển đến trích dẫn
- “User traffic routes first to the closest CDN node (called an ‘edge node’).” Bản dịch: “Lưu lượng người dùng trước tiên được định tuyến đến nút CDN gần nhất (được gọi là ‘nút biên’).” — Bing Search Quality Insights, nói về kiến trúc SSR + edge của chính Bing. Chuyển đến trích dẫn
Checklist SEO khi triển khai SvelteKit
Một lượt kiểm tra để xác nhận cách thiết lập adapter, prerender và sitemap không gây hại cho trình thu thập dữ liệu:
- Bạn đã chuyển khỏi
adapter-autosang một adapter cụ thể nếu cần bất kỳ cấu hình nào (edge, ISR, binding). - Adapter phù hợp với loại website —
adapter-staticcho nội dung thuần túy, adapter máy chủ/edge cho mọi trường hợp có logic theo từng request. - Các route nội dung dùng
prerender = true(hoặc'auto'); chỉ những route thực sự động mới được để cho SSR. - Các route động hỗn hợp (
/blog/[slug]) dùngprerender = 'auto'cùng hàmentriesliệt kê các đường dẫn đã biết. - Không còn lỗi build “marked as prerenderable, but were not prerendered” chưa được xử lý.
- Nếu có route nào dùng
runtime: 'edge', route đó không gọifscủa Node — việc truy cập tệp dùng$app/servervớiread()hoặc được prerender. - Bạn đã tính đến cold start trên edge/serverless — có thể cache, tĩnh hoặc được làm ấm ở nơi TTFB quan trọng.
- Có endpoint sitemap.xml (
prerender = truetrênadapter-static; động trên adapter máy chủ/edge). - Có robots.txt (trong
static/hoặc dưới dạng endpoint+server.js) và tệp này không chặn/_app/hoặc CSS. - Bạn không cố xếp chồng ISR lên một route có
prerender = true(việc đó không có tác dụng). - Bạn đã xác minh HTML được kết xuất và tốc độ phản hồi trong công cụ Kiểm tra URL của GSC và PageSpeed Insights.
Các mô hình tư duy
1. Ở đâu và khi nào, không phải cái gì. Adapter không bao giờ thay đổi nội dung — nó thay đổi khi nào HTML được tạo (thời điểm build so với thời điểm request) và ở đâu (máy chủ gốc so với edge). Mọi câu hỏi SEO về triển khai đều quy về hai trục này. Hãy hỏi hai câu đó trước khi chỉnh config.
2. Prerender loại một route khỏi máy chủ.
prerender = true không chỉ có nghĩa là “biến nó thành tĩnh” — nó đưa route ra khỏi
manifest động. Điều đó làm hàm của bạn nhỏ hơn và loại bỏ phương án dự phòng động.
'auto' là ngoại lệ: vừa được prerender vừa vẫn nằm trong manifest.
3. Cách tách /blog/[slug].
Mẫu mặc định cho các website nội dung thực tế: prerender những mục bạn có thể liệt kê
(hàm entries trả về nội dung gần đây/phổ biến), dùng SSR cho phần đuôi dài. 'auto' là
công tắc giúp cả hai điều cùng đúng một lúc.
4. Edge là một sự đánh đổi, không phải bản nâng cấp.
Edge mang lại khoảng cách địa lý gần hơn (TTFB thấp khi đã ấm) nhưng đổi lại là mất các API Node
(không có fs) và có rủi ro cold start. Nó chỉ đôi khi nhanh hơn máy chủ Node đã ấm, và
luôn thua đầu ra tĩnh được prerender về TTFB. Hãy chọn nó vì một lý do cụ thể, không phải theo
mặc định.
5. Sitemap đi theo adapter.
“Sitemap tĩnh hay động?” không phải một quyết định riêng biệt. adapter-static →
sitemap được prerender, chỉ mới tại thời điểm build. Adapter máy chủ/edge → sitemap theo từng request,
luôn cập nhật. Adapter đã trả lời câu hỏi đó rồi.
6. Không có gì tự tạo hai tệp này. SvelteKit không tạo sitemap.xml hay robots.txt cho bất kỳ adapter nào. Nếu bạn chưa viết chúng thì chúng không tồn tại. Hãy đưa điều này vào checklist ra mắt.
Tôi nên chọn tổ hợp adapter + prerender nào?
Câu hỏi cốt lõi “tôi nên đi theo hướng nào?” khi triển khai SvelteKit là website này nên được xuất bản theo cách nào? Hãy lần lượt đánh giá website theo quy trình sau:
1. Có trang nào cần logic máy chủ theo từng request — xác thực, cá nhân hóa, tìm kiếm trực tiếp, xử lý biểu mẫu, dữ liệu theo từng người dùng — không? → Không (mọi trang đều giống nhau với mọi khách truy cập): chuyển đến bước 2. → Có: bỏ qua và chuyển đến bước 3.
2. Website nội dung thuần túy (blog, tài liệu, marketing).
→ Dùng adapter-static, đặt prerender = true cho toàn website (hoặc trong layout
gốc). Thêm sitemap.xml/+server.js được prerender (prerender = true) và
static/robots.txt. TTFB thấp nhất, không có cold start, không có gì cần chạy. Dừng ở đây.
3. Toàn bộ website là động hay chỉ một số route? → Chỉ một số route (chủ yếu là nội dung, thêm vài phần động): chuyển đến bước 4. → Phần lớn/toàn bộ là động (ứng dụng, dashboard, thương mại điện tử có dữ liệu theo người dùng): chuyển đến bước 5.
4. Website nội dung có một số khu vực động.
→ Dùng adapter máy chủ/edge (adapter-node, -vercel hoặc
-cloudflare). Đặt prerender = true cho route nội dung và false cho route động.
Với các route kiểu /blog/[slug] có nội dung phổ biến đã biết, dùng
prerender = 'auto' + hàm entries. Tạo sitemap động
từ CMS. Hoàn tất.
5. Ứng dụng / dashboard / thương mại điện tử (ưu tiên SSR). Bây giờ hãy chọn nơi SSR chạy:
→ Độ trễ ổn định, dùng thư viện Node, bạn có hạ tầng: adapter-node
(máy chủ đã ấm, đầy đủ API Node, không có bất ngờ từ cold start).
→ Đối tượng toàn cầu, TTFB là quan trọng nhất, không có dependency Node nặng: một adapter edge
(adapter-cloudflare, hoặc adapter-vercel với runtime: 'edge' theo từng route) —
chấp nhận không có fs (dùng $app/server với read() hoặc prerender) và cold start.
Chỉ prerender phần khung thực sự tĩnh (marketing, đăng nhập).
Hướng thứ tư (chỉ dành cho Vercel): nếu một route “chủ yếu là tĩnh nhưng thỉnh thoảng
thay đổi”, hãy cân nhắc ISR (isr: { expiration }) thay cho prerender = true
— không bao giờ dùng cả hai, vì “ISR on a route with export const prerender = true will have
no effect.” Bản dịch: “ISR trên một route có export const prerender = true sẽ không có tác dụng.”
Sitemap nên là tĩnh hay động?
Đang dùng adapter-static? → Endpoint sitemap tĩnh/được prerender
(prerender = true). Nó được tạo sẵn khi build; phù hợp với các website build lại khi xuất bản.
Đang dùng adapter Node/serverless/edge? → Sitemap động được tạo theo từng request
từ CMS/DB — luôn cập nhật, không cần build lại. (Trên edge, hãy lấy URL từ API hoặc
binding, không đọc fs trên đĩa.)
Không bao giờ: bỏ qua sitemap vì “tất cả trang đều là tĩnh”. Đầu ra tĩnh và khả năng được phát hiện qua sitemap không liên quan đến nhau — SvelteKit không tạo tệp nào trong hai tệp này cho bất kỳ adapter nào.
SEO khi triển khai SvelteKit — bảng tra nhanh
Tổng quan nhanh về adapter
| Adapter | Kết xuất | Môi trường chạy | Ghi chú SEO |
|---|---|---|---|
adapter-static | Thời điểm build (SSG) | không có | TTFB thấp nhất, không có cold start; website nội dung |
adapter-node | Thời điểm request (SSR) | Node | Đầy đủ API Node (fs ✅); bạn vận hành máy chủ |
adapter-vercel | Thời điểm request | serverless / edge | runtime, regions, ISR theo từng route |
adapter-cloudflare | Thời điểm request | V8 edge | Edge toàn cầu; không có fs; nodejs_compat |
adapter-netlify | Thời điểm request | Node / Deno edge | edge: true cho Deno Edge Functions |
adapter-auto | (phát hiện các lựa chọn trên) | — | Không nhận tùy chọn — chỉ dùng khi khởi tạo |
Các giá trị prerender
| Giá trị | HTML tĩnh? | Trong manifest động? | Dùng cho |
|---|---|---|---|
true | ✅ | ❌ (đã loại bỏ) | Các route nội dung tĩnh đã biết |
false | ❌ | ✅ | Các route thực sự động |
'auto' | ✅ | ✅ | /blog/[slug] — prerender nội dung phổ biến, SSR phần đuôi dài |
Quy tắc nhanh
- Route động được prerender → thêm hàm
entries(nếu không sẽ gặp lỗi “not prerendered”). runtime: 'edge'áp dụng theo từng route (Vercel) — có thể kết hợp route edge và Node.- Edge = không có
fs→ dùng$app/servervớiread()hoặc prerender. - Cold start khiến edge chậm hơn máy chủ đã ấm / tệp tĩnh ở lần truy cập đầu tiên.
- ISR ≠ prerender —
isrtrên route cóprerender = truekhông có tác dụng. - Không tự động có sitemap/robots.txt — hãy tạo cả hai. Dùng
prerender = truetrên endpoint sitemap choadapter-static; dùng sitemap động trên máy chủ/edge. - Không bao giờ chặn
/_app/hoặc CSS trong robots.txt.
Một route được prerender bị thiếu trong bản triển khai
Nguyên nhân có thể xảy ra: trình thu thập dữ liệu không thể phát hiện đường dẫn, thiếu một giá trị entries, hoặc prerender thất bại. Cách khắc phục: thêm liên kết có thể thu thập dữ liệu hoặc entry rõ ràng và coi cảnh báo build là lỗi phát hành. Cách xác nhận: manifest đầu ra có chứa route và môi trường production trả về HTML hoàn chỉnh.
adapter-static thất bại trên một route động
Nguyên nhân có thể xảy ra: không thể liệt kê đầy đủ route tại thời điểm build. Cách khắc phục: cung cấp một tập entry hữu hạn, thiết kế lại route hoặc dùng adapter hỗ trợ máy chủ cho đường dẫn đó. Cách xác nhận: adapter đã chọn build thành công và mọi route đại diện đều trả về phản hồi dự kiến.
Triển khai edge phát sinh lỗi hệ thống tệp hoặc API Node
Nguyên nhân có thể xảy ra: mã của route hoặc một dependency giả định có các tính năng Node không khả dụng trong môi trường chạy edge. Cách khắc phục: thay dependency, chuyển công việc sang một dịch vụ tương thích hoặc chọn adapter Node. Cách xác nhận: SSR trên production thành công mà không có ngoại lệ khi chạy.
Sitemap hoặc robots.txt trả về HTML
Nguyên nhân có thể xảy ra: một route dự phòng bắt endpoint hoặc handler +server đặt sai phần thân/header. Cách khắc phục: tạo handler endpoint rõ ràng với content type chính xác. Cách xác nhận: request trực tiếp trả về phản hồi văn bản/XML như mong đợi cùng mã trạng thái 200.
Metadata khác nhau giữa route được prerender và route SSR
Nguyên nhân có thể xảy ra: dữ liệu head được tải qua các luồng mã khác nhau hoặc phụ thuộc vào trạng thái trình duyệt. Cách khắc phục: tập trung hóa việc tạo metadata từ dữ liệu trang an toàn cho máy chủ/build. Cách xác nhận: HTML thô của cả hai loại route chứa logic title, canonical và robots tương đương.
Xác nhận adapter thực sự đã triển khai những gì
Mục đích của việc chọn adapter và prerender là để trình thu thập dữ liệu nhận được HTML đầy đủ, nhanh chóng. Các bước kiểm tra này xác nhận đó chính là điều đã xảy ra — từ phản hồi thô, không phải từ trình duyệt.
Trang có được prerender/SSR không (nội dung có trong HTML thô không)?
Một lệnh curl thông thường không chạy JavaScript, vì vậy nó nhìn thấy chính xác những gì trình thu thập dữ liệu
không kết xuất nhìn thấy.
macOS / Linux
# Raw HTML as the host sends it (no JS executed)
curl -sL "https://example.com/your-page/" -o raw.html
grep -o "Your unique headline text" raw.html # empty = CSR shell, not prerenderedWindows (PowerShell)
Invoke-WebRequest -Uri "https://example.com/your-page/" -OutFile raw.html
Select-String -Path raw.html -Pattern "Your unique headline text"TTFB có nhanh không (hay một hàm đang cold start)?
TTFB tác động đến LCP và khả năng thu thập dữ liệu, vì vậy hãy đo nó. Truy cập URL ở trạng thái cold rồi warm:
# Time to first byte, twice — a big first number then a small one = cold start
for i in 1 2; do
curl -s -o /dev/null -w "TTFB: %{time_starttransfer}s\n" "https://example.com/your-page/"
doneMột trang tĩnh/được prerender phải có độ trễ thấp một cách ổn định. Giá trị đầu tiên lớn rồi giảm ở lần truy cập thứ hai là dấu hiệu điển hình của cold start trên serverless/edge.
Route này được prerender hay phục vụ động?
Các host tĩnh và CDN thường cho biết điều đó trong header (trạng thái cache, age,
x-vercel-cache, cf-cache-status):
curl -sI "https://example.com/your-page/" | grep -iE "cache|age|x-vercel|cf-"HIT (hoặc age khác 0) nghĩa là bạn đang được phục vụ nội dung đã cache/prerender;
MISS/DYNAMIC ở mọi request nghĩa là nội dung được kết xuất theo từng request.
Sitemap có thực sự tồn tại và trả về XML không?
Vì SvelteKit không tạo sitemap, hãy xác minh sitemap của bạn thực sự tồn tại và có đúng content type:
curl -sI "https://example.com/sitemap.xml" | grep -iE "HTTP/|content-type"
# Want: 200 + content-type: application/xml (not text/html or a 404)Lệnh một dòng trong console DevTools
Dán vào console của trình duyệt để so sánh DOM đã kết xuất với nội dung mà trình thu thập dữ liệu cần —
nếu tiêu đề của bạn xuất hiện ở đây nhưng thiếu trong đầu ra curl ở trên thì nó được
kết xuất phía máy khách:
// Is the content in the DOM, and does the sitemap resolve?
console.log('headline in DOM:', document.body.innerText.includes('Your unique headline text'));
fetch('/sitemap.xml').then(r => console.log('sitemap status:', r.status, r.headers.get('content-type')));Kiểm tra để đảm bảo robots.txt không chặn bundle
curl -sL "https://example.com/robots.txt" | grep -iE "disallow.*(/_app|\.js|\.css)"Một dòng Disallow khớp với /_app/ (đầu ra bundle của SvelteKit) hoặc CSS của bạn đồng nghĩa
các công cụ tìm kiếm không thể kết xuất trang — gần như luôn là một sai sót.
Công cụ gỡ lỗi SEO khi triển khai SvelteKit
- Kiểm tra URL (Google Search Console) — nguồn thông tin đáng tin cậy nhất. Kiểm tra trực tiếp một URL và xem HTML đã kết xuất, ảnh chụp màn hình cùng tài nguyên trang để xác nhận nội dung và metadata hiện diện, đồng thời không có gì bị chặn.
- PageSpeed Insights — công cụ do chính tài liệu SvelteKit khuyến nghị; hiển thị TTFB và Core Web Vitals (LCP/INP/CLS) chịu ảnh hưởng nhiều nhất từ lựa chọn adapter.
- WebPageTest — biểu đồ waterfall + filmstrip để chẩn đoán TTFB và thời điểm cold start trên các bản triển khai edge/serverless.
curl -w "%{time_starttransfer}"— cách nhanh nhất để kiểm tra TTFB thô và cold start (xem tab Scripts).- Dashboard của host (Vercel / Cloudflare / Netlify Analytics) — số lần gọi hàm, tỷ lệ cold start và tỷ lệ cache hit theo từng route — bằng chứng thực tế để biết edge/serverless có thật sự nhanh với bạn hay không.
- Screaming Frog SEO Spider — crawl khi bật/tắt kết xuất JS để so sánh HTML thô với HTML đã kết xuất trên toàn website và xác nhận các route được prerender đã hoàn chỉnh.
- Ahrefs Site Audit — phát hiện sitemap bị thiếu/bị chặn, chuỗi chuyển hướng, canonical bị lỗi và vấn đề về khả năng lập chỉ mục ở quy mô lớn.
Tự kiểm tra: SEO khi triển khai SvelteKit
Năm câu hỏi nhanh về adapter, prerender và kết xuất edge trong SvelteKit. Chọn một đáp án cho mỗi câu rồi kiểm tra.
Các tài nguyên đáng dành thời gian
Các bài viết liên quan của tôi
- SEO JavaScript: Hướng dẫn toàn diện — tài liệu tham khảo đầy đủ của tôi về các chế độ kết xuất (SSR, kết xuất tĩnh, prerender và các cạm bẫy của CSR), vốn là nền tảng cho mọi quyết định về adapter ở đây. Như tôi đã viết trong bài đó, bất kỳ hình thức thiết lập SSR, kết xuất tĩnh hoặc prerender nào cũng sẽ phù hợp với công cụ tìm kiếm — đó chính là lớp bảo vệ đứng sau các lựa chọn adapter này.
- Hướng dẫn nhập môn SEO kỹ thuật — vị trí của kết xuất, thu thập dữ liệu và Core Web Vitals trong bức tranh lớn hơn.
Các bài thuyết trình của tôi
- Cách công cụ tìm kiếm hoạt động (SlideShare) — phần trình bày của tôi về thu thập dữ liệu, kết xuất, lập chỉ mục và xếp hạng, tạo bối cảnh cho lý do TTFB và thời điểm kết xuất quan trọng. (Tuyên bố miễn trừ thường trực của tôi vẫn áp dụng: “This is my understanding of systems… not going to be 100% complete or accurate.” Bản dịch: “Đây là hiểu biết của tôi về các hệ thống… sẽ không thể đầy đủ hoặc chính xác 100%.”)
Từ các nguồn trong ngành
- Adapters • Tài liệu SvelteKit — tổng quan chính thức về mọi adapter chính thức và cách chúng được chỉ định trong
svelte.config.js. - Tùy chọn trang (prerender, ssr, csr, config) • Tài liệu SvelteKit — các giá trị
prerendertheo từng route, hàmentriesvàconfigtheo từng route, bao gồmruntime: 'edge', theo chính lời của đội ngũ. - Vercel (adapter-vercel) • Tài liệu SvelteKit — môi trường chạy edge, region và lưu ý về ISR so với prerender.
- Cloudflare (adapter-cloudflare) • Tài liệu SvelteKit — triển khai Workers/Pages, binding và hạn chế của
fs. - SvelteKit • Tài liệu Cloudflare Pages — cơ chế triển khai và binding
platformtừ phía Cloudflare. - SEO SvelteKit: Vũ khí bí mật của bạn (Okupter) — hướng dẫn thực hành về prerender, thẻ meta và mẫu sitemap/RSS bằng
+server.js. - Phân tích sâu các kỹ thuật kết xuất của SvelteKit (This Dot Labs) — cơ chế SSR/SSG/CSR và config theo từng route/layout, cùng sự đánh đổi về tải máy chủ khi “SSR can be expensive” Bản dịch: “SSR có thể tốn kém”.
- Tìm hiểu kiến thức cơ bản về SEO JavaScript (Google Search Central) — hàng đợi kết xuất và nhận định “not all bots can run JavaScript,” Bản dịch: “không phải bot nào cũng có thể chạy JavaScript”, hướng dẫn chung làm nền tảng cho mọi lựa chọn adapter.
Nhật ký thay đổi
Đã cập nhật 24 thg 8, 2026.
Tóm tắt biên tập và chi tiết thay đổi đã ghi nhận.Chi tiết thay đổi
-
Ghi chú thay đổi chi tiết hiện chỉ có bằng tiếng Anh.
Không thể so sánh đầy đủ — không có bản lưu trước đó cho lần sửa đổi này.
Đã cập nhật 24 thg 8, 2026.
Tóm tắt biên tập và chi tiết thay đổi đã ghi nhận.Chi tiết thay đổi
-
Ghi chú thay đổi chi tiết hiện chỉ có bằng tiếng Anh.
Không thể so sánh đầy đủ — không có bản lưu trước đó cho lần sửa đổi này.
Đã cập nhật 24 thg 8, 2026.
Tóm tắt biên tập và chi tiết thay đổi đã ghi nhận.Chi tiết thay đổi
-
Ghi chú thay đổi chi tiết hiện chỉ có bằng tiếng Anh.
Không thể so sánh đầy đủ — không có bản lưu trước đó cho lần sửa đổi này.
Đã cập nhật 24 thg 8, 2026.
Tóm tắt biên tập và chi tiết thay đổi đã ghi nhận.Chi tiết thay đổi
-
Ghi chú thay đổi chi tiết hiện chỉ có bằng tiếng Anh.
Không thể so sánh đầy đủ — không có bản lưu trước đó cho lần sửa đổi này.
Đã cập nhật 8 thg 8, 2026.
Tóm tắt biên tập và chi tiết thay đổi đã ghi nhận.Chi tiết thay đổi
-
Ghi chú thay đổi chi tiết hiện chỉ có bằng tiếng Anh.
Không thể so sánh đầy đủ — không có bản lưu trước đó cho lần sửa đổi này.