Các framework JavaScript phía máy khách
React, Vue, Angular, Svelte và SolidJS có chung một vấn đề SEO — kết xuất phía máy khách tạo ra một khung HTML trống — cùng một cách khắc phục: quản lý phần head kết hợp với chiến lược kết xuất.
React, Vue, Angular, Svelte và SolidJS là các thư viện giao diện người dùng thường gửi một khung HTML gần như trống theo mặc định rồi dựng trang trong trình duyệt bằng JavaScript. Vì vậy, trình thu thập dữ liệu chỉ nhận được một trang trống cho đến khi JavaScript chạy — Google có thể kết xuất trang, nhưng phải qua một hàng đợi riêng; khả năng của các trình thu thập dữ liệu khác như Bing và bot AI kém ổn định hơn nhiều. Cách khắc phục gồm hai phần giống nhau cho cả năm công nghệ: (1) dùng công cụ quản lý phần head để mỗi tuyến có thẻ meta riêng và (2) chọn chiến lược kết xuất như kết xuất trước, SSR hoặc chuyển sang meta-framework tương ứng. Bài tổng quan này giải thích vấn đề và cách khắc phục chung, sau đó dẫn đến hướng dẫn chuyên sâu cho từng framework.
Tóm tắt — React, Vue, Angular, Svelte và SolidJS là những công cụ giúp nhà phát triển xây dựng các trang web tương tác. Theo mặc định, chúng gửi đến trình duyệt một trang HTML gần như trống, rồi mới dựng nội dung thực bằng JavaScript. Cách làm này thuận tiện cho người dùng nhưng tiềm ẩn rủi ro SEO vì trình thu thập dữ liệu tìm kiếm có thể chỉ gặp một trang trống. Cách khắc phục giống nhau cho tất cả: quản lý
<title>và thẻ meta theo từng trang, đồng thời bảo đảm nội dung đã có trong HTML trước khi JavaScript chạy.
Framework phía máy khách là gì
Framework phía máy khách có thể kết xuất nội dung của tuyến trong trình duyệt sau phản hồi HTML ban đầu. Bằng chứng cho nhận định này Primary standard or official documentation supporting the adjacent article claim. Phạm vi: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Độ tin cậy: cao · Đã xác minh: MDN: Client-side frameworks Google có thể kết xuất JavaScript, nhưng tài nguyên sẵn có và quá trình kết xuất vẫn ảnh hưởng đến nội dung được xử lý. Bằng chứng cho nhận định này Primary standard or official documentation supporting the adjacent article claim. Phạm vi: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Độ tin cậy: cao · Đã xác minh: Google: JavaScript SEO basics
Framework phía máy khách là thư viện JavaScript dựng trang ngay trong trình duyệt của khách truy cập. Năm công nghệ bạn thường gặp nhất là React, Vue, Angular, Svelte và SolidJS. Phần lớn ứng dụng web và bảng điều khiển hiện đại được xây dựng bằng những công nghệ này.
Điểm cần lưu ý nằm ở cụm từ phía máy khách. Theo mặc định, các framework này gửi một tệp HTML rất nhỏ, có dạng gần giống như sau:
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>Tệp HTML đó chưa có nội dung, chỉ có một vùng chứa trống và một đoạn mã. Trình duyệt tải đoạn mã xuống, chạy nó, rồi sau đó tiêu đề, văn bản, liên kết và mọi thành phần khác mới xuất hiện. Hành vi mặc định này được gọi là kết xuất phía máy khách (CSR); một website được xây dựng theo cách này thường được gọi là ứng dụng đơn trang (SPA).
Vì sao điều này gây vấn đề cho SEO
Trình thu thập dữ liệu tìm kiếm không phải là người dùng đang nhấp qua các trang. Khi Googlebot hoặc một trình thu thập dữ liệu khác truy xuất trang, thứ đầu tiên nó nhận được là khung HTML trống. Nếu không chạy JavaScript, nó sẽ thấy một trang trống, không có nội dung để lập chỉ mục.
Google có thể chạy JavaScript nên thường sẽ nhìn thấy nội dung sau đó. Tuy nhiên:
- Việc này có độ trễ vì kết xuất là một bước riêng nằm trong hàng đợi.
- Các trình thu thập dữ liệu khác — như Bing và những bot AI cung cấp dữ liệu cho các công cụ như ChatGPT — kém ổn định hơn nhiều khi chạy JavaScript.
Vì vậy, “it works in my browser” (bản dịch) «nó hoạt động trong trình duyệt của tôi» không đồng nghĩa với “search engines can see it” (bản dịch) «các công cụ tìm kiếm có thể nhìn thấy nó».
Cách khắc phục giống nhau cho cả năm framework
Dù chọn framework nào, giải pháp vẫn gồm hai phần:
- Quản lý phần head. Mỗi trang cần có
<title>và mô tả meta riêng. Một ứng dụng CSR đơn giản chỉ có một tệp HTML, nên nếu không can thiệp thì mọi trang sẽ dùng chung tiêu đề. Mỗi framework đều có gói nhỏ hoặc API để giải quyết việc này (xem thêm trong thẻ Nâng cao). - Chọn chiến lược kết xuất. Đưa nội dung vào HTML trước khi JavaScript chạy bằng kết xuất trước (tạo sẵn HTML tĩnh), kết xuất phía máy chủ (SSR) hoặc chuyển sang meta-framework tương ứng (Next.js cho React, Nuxt cho Vue, v.v.).
Bạn muốn biết chi tiết cho từng framework — nên dùng gói quản lý head nào, chọn phương án kết xuất nào và Google thực sự xử lý các ứng dụng này ra sao? Hãy chuyển sang thẻ Nâng cao, rồi mở hướng dẫn riêng cho framework của bạn.
Tóm tắt — React, Vue, Angular, Svelte và SolidJS đều là các thư viện giao diện người dùng thường mặc định dùng kết xuất phía máy khách: chúng gửi một khung HTML gần như trống rồi dựng DOM trong trình duyệt. Vấn đề SEO giống nhau ở cả năm công nghệ: trình thu thập dữ liệu nhận được khung trống, còn nội dung chỉ tồn tại sau khi JavaScript chạy. Google có thể kết xuất những ứng dụng này nhưng phải qua một hàng đợi riêng có độ trễ; Bing và các trình thu thập dữ liệu AI kém ổn định hơn nhiều. Cách khắc phục cũng giống nhau: (1) quản lý phần head (gói theo từng tuyến cho
<title>/meta) và (2) chiến lược kết xuất (kết xuất trước, SSR hoặc chuyển sang meta-framework tương ứng). Điểm khác nhau giữa các framework chủ yếu là dùng gói nào và chọn chiến lược nào — được trình bày trong từng hướng dẫn chuyên sâu bên dưới.
Chúng là thư viện chứ không phải framework hoàn chỉnh — đó là gốc rễ vấn đề
Kiến trúc framework rất đa dạng, vì vậy kết xuất phía máy khách không tự động dẫn đến thất bại trong việc lập chỉ mục. Bằng chứng cho nhận định này Primary standard or official documentation supporting the adjacent article claim. Phạm vi: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Độ tin cậy: cao · Đã xác minh: MDN: Client-side frameworks Kết xuất phía máy chủ hoặc kết xuất trước giúp giảm sự phụ thuộc vào việc trình thu thập dữ liệu chạy JavaScript, nhưng không bảo đảm nội dung sẽ được lập chỉ mục. Bằng chứng cho nhận định này Primary standard or official documentation supporting the adjacent article claim. Phạm vi: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Độ tin cậy: cao · Đã xác minh: Google: JavaScript SEO basics
React, Vue, Angular, Svelte và SolidJS chủ yếu là thư viện kết xuất giao diện người dùng. Nhiệm vụ của chúng là chuyển dữ liệu thành DOM và đồng bộ DOM khi trạng thái thay đổi. Ngay khi mới cài đặt, DOM được dựng trong trình duyệt — chính điều đó tạo cảm giác nhanh như ứng dụng, đồng thời cũng tạo ra vấn đề SEO.
Bản dựng mặc định gửi một khung HTML có nút gắn kết trống (<div id="root">, <div id="app">, <app-root>) cùng một gói JavaScript. Mọi thứ mà công cụ tìm kiếm quan tâm — tiêu đề, nội dung thân trang, liên kết nội bộ, dữ liệu có cấu trúc — chỉ được gói mã đó chèn vào sau khi tải xuống và chạy. Trước khi JS chạy, chúng chưa tồn tại.
Đó là kết xuất phía máy khách — hành vi ban đầu của thư viện thuần túy trước khi bạn thêm meta-framework hoặc bước kết xuất trước ở thời điểm dựng. Đây không phải lỗi mà là điểm khởi đầu mặc định. Tuy nhiên, “mặc định” không có nghĩa là “vĩnh viễn” hay “phổ quát”: hành vi có thể thay đổi theo phiên bản, CLI hoặc bộ khởi tạo, và hai tuyến trong cùng một ứng dụng có thể dùng hai chế độ kết xuất khác nhau tùy cách xây dựng (chẳng hạn trang tiếp thị được kết xuất trước còn bảng điều khiển vẫn dùng CSR hoàn toàn). Đừng suy đoán hành vi từ tên framework; hãy kiểm tra đầu ra thực tế của từng tuyến trong từng bản dựng.
Vấn đề chung: khung HTML trống
Google nêu rõ rằng họ xử lý ứng dụng JS theo các giai đoạn — thu thập dữ liệu, kết xuất, lập chỉ mục — và rằng “without rendering Google might not see that content” (bản dịch) «nếu không kết xuất, Google có thể không nhìn thấy nội dung đó». Với ứng dụng CSR, toàn bộ nội dung nằm sau bước kết xuất. Điều này dẫn đến ba hệ quả:
- Kết xuất có độ trễ và thời gian chờ không cố định. Kết xuất là bước riêng trong hàng đợi sau khi thu thập dữ liệu. Google mô tả thu thập dữ liệu, kết xuất và lập chỉ mục là ba giai đoạn khác nhau, nhưng không cam kết một thời gian chờ chung cho mọi trang. Độ trễ thay đổi theo URL và nguồn lực Google có tại thời điểm đó; nội dung chưa tồn tại để lập chỉ mục cho đến khi bước kết xuất thực sự hoàn tất, dù trang đó mất bao lâu.
- Không thể mặc định các trình thu thập dữ liệu ngoài Google cũng làm được. Bing kết xuất JavaScript thiếu nhất quán, còn phần lớn trình thu thập dữ liệu AI (các bot lấy trang cho LLM và công cụ tìm kiếm AI) chỉ chạy rất ít hoặc không chạy JS. Đây là các công ty có hạ tầng riêng nên tài liệu của Google không thể đại diện cho tất cả. Hãy kiểm tra hành vi hiện tại của từng nhà cung cấp thay vì giả định họ giống Google hoặc giống kết quả thử nghiệm năm trước. Website chỉ dùng CSR có nguy cơ gần như vô hình với những bot không kết xuất, trong khi bot AI đang chiếm tỷ trọng truy cập ngày càng lớn.
- Thiếu metadata riêng cho từng trang. Một tệp HTML đồng nghĩa mọi tuyến có chung một
<title>và một mô tả meta, trừ khi bạn chủ động quản lý phần head theo từng tuyến.
Phần một của cách khắc phục chung: quản lý phần head
Vì SPA chỉ có một tài liệu HTML, bạn cần mã cập nhật phần head của tài liệu khi người dùng (và trình kết xuất của bot) di chuyển giữa các tuyến. Mỗi framework đều có gói tiêu chuẩn hoặc API tích hợp cho việc này:
- React →
react-helmet-async(hoặc API metadata của framework nếu bạn đã chuyển sang Next.js). - Vue →
@unhead/vue(công cụ nền tảng cho các tiện ích SEO của Nuxt). - Angular → các dịch vụ
TitlevàMetatích hợp sẵn từ@angular/platform-browser— không cần thêm phần phụ thuộc. - Svelte → phần tử
<svelte:head>tích hợp sẵn. - SolidJS →
@solidjs/meta(và SolidStart cho hướng triển khai SSR).
Quản lý phần head giúp tạo thẻ meta chính xác, riêng biệt nhưng không tự giải quyết vấn đề khung HTML trống. Các thẻ vẫn chỉ xuất hiện sau khi JS chạy. Vì vậy bạn còn cần phần thứ hai.
Phần hai của cách khắc phục chung: chiến lược kết xuất
Để đưa nội dung thực (và các thẻ trong head) vào HTML trước khi JavaScript chạy, bạn chọn một trong ba phương án. Xếp theo mức độ giảm rủi ro SEO:
- Kết xuất trước / tạo trang tĩnh (SSG). Tạo HTML tĩnh cho từng tuyến tại thời điểm dựng. Đây là phương án rủi ro thấp nhất với nội dung không thay đổi theo từng yêu cầu. Mỗi thư viện đều có hướng kết xuất trước (ví dụ tính năng tích hợp của SolidJS, plugin kết xuất trước cho Vue và tính năng kết xuất trước của Angular).
- Kết xuất phía máy chủ (SSR). Kết xuất HTML trên máy chủ cho từng yêu cầu rồi hydration trong trình duyệt. Đây là vai trò của các meta-framework: Next.js (React), Nuxt (Vue), Angular SSR (trước đây là Angular Universal), SvelteKit (Svelte) và SolidStart (SolidJS). Với phần lớn website nội dung cần xếp hạng, dùng meta-framework tương ứng là cách khắc phục gọn gàng nhất.
- Tiếp tục dùng CSR hoàn toàn nhưng làm cho nội dung có thể thu thập. Cách này đôi khi phù hợp với bề mặt giống ứng dụng nằm sau đăng nhập và không cần xếp hạng, nhưng không nên là lựa chọn mặc định cho nội dung bạn muốn xuất hiện trong tìm kiếm.
Hãy quyết định theo từng tuyến, không phải theo toàn bộ ứng dụng. Trang tiếp thị và bảng điều khiển sau đăng nhập trong cùng một codebase hoàn toàn có thể nằm ở hai phương án khác nhau. Với từng tuyến, hãy hỏi:
- Đầu ra — nội dung có cần nằm trong phản hồi ban đầu hay xuất hiện sau khi JS chạy cũng được?
- Độ mới — nội dung có đủ ổn định để dựng một lần (kết xuất trước) hay thay đổi theo từng yêu cầu (SSR)?
- Cá nhân hóa — nội dung có khác nhau với từng khách truy cập không? Kết xuất trước không giải quyết được trường hợp này; bạn phải chọn giữa SSR và CSR.
- Chi phí máy chủ — SSR dùng thêm tài nguyên tính toán cho mỗi yêu cầu; kết xuất trước chuyển chi phí đó sang thời điểm dựng.
- Mức phụ thuộc JS — giá trị sử dụng của tuyến phụ thuộc đến đâu vào việc JavaScript phía máy khách phải chạy?
- Hành vi khi lỗi — nếu JS lỗi hoặc bị chặn, tuyến có giảm cấp thành nội dung vẫn dùng được hay không còn gì cả?
Cuộc thảo luận để ra quyết định giống nhau với mọi framework: nội dung này có cần xếp hạng hoặc được trích dẫn không? Nếu có, hãy đưa nó vào HTML được kết xuất phía máy chủ hoặc kết xuất trước. Nếu chỉ là giao diện ứng dụng tương tác, CSR vẫn phù hợp.
Google xử lý các ứng dụng này ra sao (và vì sao không nên suy rộng sang bot khác)
Google có thể kết xuất cả năm framework này — họ chạy Chrome không giao diện luôn được cập nhật và thực thi JS. Tuy nhiên, việc này diễn ra trong một hàng đợi trì hoãn; trình kết xuất không lưu trạng thái (không giữ cookie/localStorage, không có service worker, không tương tác — không cuộn hoặc nhấp). Vì vậy, các quy tắc JS-SEO trong bài JavaScript SEO vẫn áp dụng cùng với lựa chọn framework: dùng liên kết <a href> thực, bảo đảm DOM thô và DOM sau kết xuất tương đương, không giấu nội dung sau thao tác và không chèn noindex bằng JS.
Bên ngoài Google, tình hình kém thuận lợi hơn. Khả năng kết xuất JS của Bing thiếu ổn định, còn các trình thu thập dữ liệu AI phần lớn không kết xuất. Với ứng dụng CSR, nội dung có thể tồn tại cho Google (sau một khoảng chờ) nhưng không tồn tại với Bing hay những công cụ AI mà ngày càng nhiều người dùng để tìm kiếm. SSR hoặc kết xuất trước khép lại khoảng trống này cho tất cả chứ không chỉ Google — đây là lý do thuyết phục nhất để không phát hành nội dung chỉ có CSR.
Tổng quan về năm framework
| Framework | Mặc định | Quản lý phần head | SSR / meta-framework | Ghi chú SEO |
|---|---|---|---|---|
| React | CSR | react-helmet-async | Next.js (Metadata API) | SPA ưu tiên CSR phổ biến nhất; Next.js là cách khắc phục SEO tiêu chuẩn |
| Vue | CSR | @unhead/vue | Nuxt (useSeoMeta()) | Nuxt mặc định dùng SSR; Vue thuần cần kết xuất trước hoặc Nuxt |
| Angular | CSR (SPA) | dịch vụ Title/Meta tích hợp | Angular SSR (trước đây là Universal) | Phù hợp với SPA lớn; Angular hiện đại bổ sung SSR và hydration tăng dần |
| Svelte | CSR (Svelte) / SSR (SvelteKit) | <svelte:head> | SvelteKit (mặc định SSR) | SvelteKit mặc định dùng SSR — lưu ý bẫy tĩnh ssr:false |
| SolidJS | CSR | @solidjs/meta | SolidStart | Phản ứng ở mức chi tiết; SolidStart bổ sung SSR và kết xuất trước |
Mô hình luôn nhất quán: mặc định CSR, một gói quản lý head và một chiến lược kết xuất (thường là meta-framework tương ứng). Điểm khác biệt nằm ở tên công cụ và một số góc cạnh dễ gây lỗi.
Bước tiếp theo: hướng dẫn chuyên sâu cho từng framework
Bài tổng quan này là bản đồ. Mỗi framework có hướng dẫn riêng về gói, cấu hình và những điểm dễ mắc lỗi:
- SEO cho React — vì sao React ưu tiên CSR tạo rủi ro lập chỉ mục, React Router và History API,
react-helmet-async, cùng thời điểm nên dùng Next.js. - SEO cho Vue — mặc định CSR của Vue 3,
createWebHistory(),@unhead/vue, kết xuất trước không cần meta-framework và thời điểm Nuxt là lựa chọn phù hợp. - SEO cho Angular — mặc định SPA của Angular,
@angular/ssr, các dịch vụTitlevàMetatích hợp, kết xuất trước và hydration tăng dần. - SEO cho Svelte — Svelte so với SvelteKit, SSR mặc định trong SvelteKit,
<svelte:head>, bẫyadapter-static+ssr: falsevà ảnh hưởng với bot AI. - SEO cho SolidJS — mặc định CSR của SolidJS,
@solidjs/meta, SolidStart cho SSR và kết xuất trước, cùng ảnh hưởng của mô hình phản ứng chi tiết đến đầu ra đã kết xuất.
Để tìm hiểu chính các chế độ kết xuất (CSR, SSR, SSG, ISR, hydration, kết xuất động) và những quy tắc rộng hơn về kết xuất/tính tương đương, hãy xem bài tổng quan JavaScript SEO.
Tóm tắt bằng AI
Bản rút gọn của phần Nâng cao:
- Một điểm khởi đầu chung. React, Vue, Angular, Svelte và SolidJS thường mặc định dùng kết xuất phía máy khách khi mới cài đặt — một khung HTML gần như trống (
<div id="root">+ gói mã) sẽ dựng DOM trong trình duyệt. Hành vi mặc định thay đổi theo phiên bản, bộ khởi tạo và meta-framework, thậm chí có thể khác nhau theo từng tuyến trong cùng ứng dụng. Hãy kiểm tra đầu ra thực tế thay vì suy đoán từ tên framework. - Google kết xuất được nhưng thời gian chờ không cố định. Kết xuất là bước riêng nằm trong hàng đợi sau khi thu thập dữ liệu, nhưng Google không cam kết một độ trễ chung cho mọi trang; nó thay đổi theo URL. Trình kết xuất cũng không lưu trạng thái và không cuộn hoặc nhấp.
- Không thể mặc định bot khác cũng làm được. Bing kết xuất JS thiếu nhất quán; phần lớn trình thu thập dữ liệu AI hoàn toàn không kết xuất. Đây là các công ty riêng, nên tài liệu của Google không thể đại diện cho họ; hãy xác minh hành vi hiện tại của từng nhà cung cấp.
- Một cách khắc phục chung gồm hai phần. (1) Quản lý phần head — gói theo từng tuyến cho
<title>/meta:react-helmet-async(React),@unhead/vue(Vue),Title/Metatích hợp (Angular),<svelte:head>(Svelte),@solidjs/meta(SolidJS). (2) Chiến lược kết xuất — kết xuất trước/SSG, SSR hoặc chuyển sang meta-framework tương ứng (Next.js / Nuxt / Angular SSR / SvelteKit / SolidStart). - Chỉ quản lý phần head là chưa đủ — các thẻ vẫn chỉ xuất hiện sau khi JS chạy; bạn vẫn cần chiến lược kết xuất để lấp đầy khung HTML.
- Quyết định theo từng tuyến, cân nhắc thời điểm có đầu ra, độ mới, cá nhân hóa, chi phí máy chủ, mức phụ thuộc JS và hành vi khi lỗi — không quyết định chung cho cả ứng dụng. Nếu một tuyến cần xếp hạng hoặc được trích dẫn, hãy đưa nó vào HTML được kết xuất phía máy chủ hoặc kết xuất trước. Nếu chỉ là giao diện sau đăng nhập, CSR vẫn phù hợp.
Tài liệu chính thức
Tài liệu nguồn sơ cấp từ các công cụ tìm kiếm và framework.
- Tìm hiểu kiến thức cơ bản về SEO cho JavaScript — các giai đoạn thu thập dữ liệu → kết xuất → lập chỉ mục, liên kết có thể thu thập và cách kiểm tra HTML đã kết xuất.
- Khắc phục vấn đề JavaScript liên quan đến Tìm kiếm — xử lý soft-404 sau định tuyến phía máy khách, History API và giới hạn của trình kết xuất.
- Hướng dẫn chuyên sâu về cách Google Search hoạt động — vị trí của kết xuất trong chuỗi thu thập dữ liệu → lập chỉ mục → phân phối kết quả.
Bing / Microsoft
- Loạt bài về bingbot: JavaScript, Dynamic Rendering và Cloaking — quan điểm của Bing về kết xuất JS và lý do kết xuất động tồn tại.
Các framework (phần head + kết xuất)
- Tài liệu React — thư viện phổ biến hóa SPA ưu tiên CSR; xem thêm metadata của Next.js.
- Vue.js — Kết xuất / SSR và tiện ích SEO của Nuxt.
- Angular — Kết xuất phía máy chủ và các dịch vụ
Title/Meta. - SvelteKit — Tùy chọn trang (SSR/kết xuất trước) và
<svelte:head>. - SolidStart — SSR và kết xuất trước cùng
@solidjs/meta.
Trích dẫn từ nguồn
Các phát biểu công khai dưới đây là cơ sở cho vấn đề CSR chung và cách khắc phục. Mỗi liên kết của công cụ tìm kiếm dẫn thẳng đến đoạn được trích dẫn.
Google — kết xuất và lý do khung HTML quan trọng
- “Google processes JavaScript web apps in three main phases: 1. Crawling 2. Rendering 3. Indexing.” (bản dịch) «Google xử lý ứng dụng web JavaScript theo ba giai đoạn chính: 1. Thu thập dữ liệu 2. Kết xuất 3. Lập chỉ mục.» Mở đoạn trích
- “Rendering is important because websites often rely on JavaScript to bring content to the page, and without rendering Google might not see that content.” (bản dịch) «Kết xuất rất quan trọng vì website thường dựa vào JavaScript để đưa nội dung lên trang; nếu không kết xuất, Google có thể không nhìn thấy nội dung đó.» Mở đoạn trích
- “Google can only discover your links if they are <a> HTML elements with an href attribute.” (bản dịch) «Google chỉ có thể phát hiện liên kết nếu chúng là phần tử HTML <a> có thuộc tính href.» — áp dụng cho bộ định tuyến của mọi framework. Mở đoạn trích
- “Google Search does not interact with your page.” (bản dịch) «Google Search không tương tác với trang của bạn.» — trình kết xuất sẽ không cuộn hoặc nhấp để làm lộ nội dung. Mở đoạn trích
Patrick Stox (bài viết của tôi — JavaScript SEO: A Definitive Guide)
- “Any kind of SSR, static rendering, and prerendering setup is going to be fine for search engines.” (bản dịch) «Mọi cách thiết lập SSR, kết xuất tĩnh và kết xuất trước đều sẽ phù hợp với công cụ tìm kiếm.» — nguyên tắc xuyên suốt cho mọi framework trong bài tổng quan này.
- Trình kết xuất áp dụng chỉ thị robots hạn chế nhất giữa HTML thô và HTML đã kết xuất. Vì vậy, một framework chèn
noindexở phía máy khách có thể khiến trang bị loại khỏi chỉ mục ngay cả khi khung HTML ghiindex.
Checklist SEO cho framework phía máy khách
Áp dụng như nhau cho React, Vue, Angular, Svelte và SolidJS:
- Bạn biết hiện tại ứng dụng dùng CSR, SSR hay kết xuất trước (kiểm tra View Source: nội dung có trong HTML thô hay chỉ có nút gắn kết trống?).
- Nội dung phải xếp hạng hoặc được trích dẫn đã nằm trong HTML được kết xuất phía máy chủ hoặc kết xuất trước, không chỉ được chèn sau khi JS chạy.
-
<title>và mô tả meta được quản lý theo từng tuyến (bằng gói head hoặc API tích hợp) và có giá trị riêng trên mỗi trang trong HTML đã kết xuất. - Liên kết của bộ định tuyến là phần tử neo
<a href>thực (định tuyến bằng History API, không dùng mảnh#hoặconclicktrên<div>). - JavaScript và CSS không bị chặn trong
robots.txt(Google không thể kết xuất từ tệp bị chặn). - Không có nội dung nào bị giấu sau thao tác cuộn, nhấp hoặc di chuột.
- Màn hình “không tìm thấy” phía máy khách trả về mã
404thực hoặc cónoindex(không dùng khung soft-404). - Không có JS chèn
noindextrái với HTML thô (Google áp dụng chỉ thị hạn chế nhất). - Bạn đã tính đến Bing và trình thu thập dữ liệu AI, không chỉ Google; SSR/kết xuất trước là phương án ổn định duy nhất cho các bot đó.
- Bạn đã xác minh bằng URL Inspection (HTML đã kết xuất + ảnh chụp + console), không chỉ bằng trình duyệt của mình.
Những phép kiểm tra trên gộp nhiều đầu ra riêng biệt vào một trang. Hãy xác minh từng giai đoạn riêng vì một tuyến có thể vượt qua giai đoạn này nhưng thất bại ở giai đoạn kế:
| Giai đoạn | Nội dung cần kiểm tra |
|---|---|
| Phản hồi trực tiếp (JS bị tắt/chặn) | Truy xuất URL khi tắt JS. Tiêu đề và nội dung thân trang riêng của tuyến có sẵn hay chỉ có nút gắn kết? |
| Các khối truyền theo luồng (nếu dùng streaming) | Nội dung có đến dần hay một khối chậm làm trì hoãn toàn bộ phần phía sau? |
| DOM đã kết xuất (JS đã chạy) | Sau khi gói mã chạy, DOM cuối cùng có đầy đủ tiêu đề, liên kết và dữ liệu có cấu trúc không? |
| Hydration | Phía máy khách có tiếp quản trơn tru hay console xuất hiện lỗi/không khớp khi hydration? |
| Điều hướng phía máy khách | Khi đổi tuyến trong ứng dụng, URL, tiêu đề và canonical có cập nhật giống như khi tải trực tiếp không? |
| Mã trạng thái | Tuyến 404/410/5xx thực có trả thẳng mã đó hay chỉ hiển thị thông báo phía máy khách trong phản hồi 200? |
| Metadata | <title>, mô tả, canonical và chỉ thị robots sau kết xuất có đúng theo từng tuyến, chứ không chỉ đơn thuần tồn tại? |
Tổng quan nhanh: framework → cách khắc phục
| Framework | Kết xuất mặc định | Quản lý phần head | SSR / meta-framework | Hướng kết xuất trước |
|---|---|---|---|---|
| React | CSR | react-helmet-async | Next.js | SSG của Next.js / react-snap |
| Vue | CSR | @unhead/vue | Nuxt | Nuxt nuxi generate / plugin kết xuất trước |
| Angular | CSR (SPA) | Title / Meta tích hợp | Angular SSR (trước đây là Universal) | kết xuất trước bằng ng build |
| Svelte | CSR (Svelte) / SSR (SvelteKit) | <svelte:head> | SvelteKit | adapter-static (lưu ý ssr:false) |
| SolidJS | CSR | @solidjs/meta | SolidStart | kết xuất trước bằng SolidStart |
Ghi nhớ cách khắc phục gồm hai phần
- Quản lý phần head →
<title>/ meta riêng cho từng tuyến. - Chiến lược kết xuất → kết xuất trước (SSG) hoặc SSR hoặc meta-framework tương ứng. Chỉ quản lý phần head sẽ không lấp đầy khung HTML trống.
Thang rủi ro (từ thấp nhất → cao nhất)
| Phương án | Rủi ro SEO | Trường hợp phù hợp |
|---|---|---|
| Kết xuất trước / SSG | Thấp nhất | Nội dung ổn định theo từng yêu cầu |
| SSR (meta-framework) | Thấp | Nội dung động/theo từng yêu cầu cần xếp hạng |
| Hydration (đồng hình) | Thấp | Kết hợp ứng dụng và nội dung |
| CSR hoàn toàn | Cao nhất | Giao diện ứng dụng sau đăng nhập không cần xếp hạng |
Kiểm tra thực tế về trình thu thập dữ liệu
| Trình thu thập dữ liệu | Có chạy JS không? |
|---|---|
| Googlebot | Có — nhưng có độ trễ, nằm trong hàng đợi, không lưu trạng thái |
| Bingbot | Không nhất quán |
| Trình thu thập dữ liệu AI (LLM / tìm kiếm AI) | Phần lớn là không |
Nội dung chỉ có CSR là một canh bạc ở mọi nơi ngoài Google — và ngay cả tại Google nó vẫn bị trì hoãn. SSR/kết xuất trước loại bỏ rủi ro này cho tất cả.
Các vấn đề SEO thường gặp với framework phía máy khách
Công cụ tìm kiếm hiển thị trang trống hoặc chỉ có khung ứng dụng
Triệu chứng: HTML thô chỉ chứa phần tử gắn kết như #root, #app hoặc app-root, trong khi trang hiển thị có nội dung thực. Nguyên nhân có khả năng nhất: Tuyến được kết xuất hoàn toàn ở phía máy khách. Cách khắc phục: Kết xuất trước các tuyến ổn định hoặc chuyển tuyến sang meta-framework hỗ trợ SSR. Xác nhận bằng cách truy xuất URL khi tắt JavaScript và tìm tiêu đề cùng nội dung thân trang riêng trong phản hồi.
Mọi tuyến đều có cùng tiêu đề hoặc canonical
Triệu chứng: Nhiều URL kết xuất giao diện khác nhau nhưng dùng chung tiêu đề, mô tả hoặc canonical. Nguyên nhân có khả năng nhất: Khung HTML dùng chung nắm phần head và việc đổi tuyến không cập nhật nó. Cách khắc phục: Dùng API head dành cho framework và đặt metadata từ dữ liệu tuyến. Xác nhận DOM cuối của mỗi tuyến có một canonical tự tham chiếu và tiêu đề riêng.
Liên kết hoạt động với người dùng nhưng bot không phát hiện được tuyến
Triệu chứng: Điều hướng hoạt động trong trình duyệt nhưng các tuyến được liên kết vẫn không được phát hiện. Nguyên nhân có khả năng nhất: Trình xử lý nhấp trên nút hoặc phần tử div đã thay thế phần tử neo có thể thu thập. Cách khắc phục: Kết xuất liên kết <a href="..."> thực và để bộ định tuyến tăng cường chúng. Xác nhận đích xuất hiện dưới dạng href trong DOM đã kết xuất mà không cần nhấp.
Console báo lỗi hydration hoặc nội dung không khớp
Triệu chứng: HTML được kết xuất phía máy chủ/kết xuất trước trông đúng, nhưng console trình duyệt ghi cảnh báo hydration, hoặc nội dung nhấp nháy rồi thay đổi ngay sau khi tải. Nguyên nhân có khả năng nhất: Đầu ra máy chủ và lần kết xuất đầu tiên của máy khách không khớp — thường do định dạng ngày/ngôn ngữ, ID ngẫu nhiên hoặc mã phụ thuộc window chạy trong lần kết xuất ban đầu. Cách khắc phục: Làm cho máy chủ và máy khách kết xuất tất định với cùng đầu vào; chuyển logic chỉ dành cho trình duyệt sang chạy sau hydration, không chạy trong quá trình đó. Xác nhận bằng cách tải tuyến khi bật JS và kiểm tra console không có lỗi hydration.
Tuyến đổi trạng thái trong trình duyệt nhưng URL trực tiếp cho kết quả khác
Triệu chứng: Nhấp qua ứng dụng tạo ra trang hoạt động, nhưng yêu cầu trực tiếp cùng URL đó (hoặc làm mới trang) trả về kết quả khác — khung chung, mã trạng thái sai hoặc metadata cũ. Nguyên nhân có khả năng nhất: Điều hướng phía máy khách cập nhật giao diện trong trình duyệt nhưng không có trình xử lý tuyến tương ứng ở phía máy chủ, nên trạng thái sau chuyển tiếp phía máy khách chưa từng là một trang thực có thể yêu cầu độc lập. Cách khắc phục: Bảo đảm mọi tuyến người dùng có thể truy cập bằng điều hướng cũng có thể yêu cầu trực tiếp và trả về cùng nội dung, trạng thái, metadata. Xác nhận bằng cách tải mới URL (không nhấp vào URL đó), trước tiên khi tắt JS rồi sau đó khi bật JS.
Tự kiểm tra: framework phía máy khách
Năm câu hỏi nhanh về vấn đề SEO chung và cách khắc phục cho React, Vue, Angular, Svelte và SolidJS. Hãy chọn một đáp án cho từng câu rồi kiểm tra kết quả.
Các tài nguyên đáng đọc
Bài viết liên quan của tôi
- JavaScript SEO: A Definitive Guide — hướng dẫn đầy đủ của tôi về kết xuất, tính tương đương của DOM, quy tắc chọn chỉ thị hạn chế nhất và cách chọn cấu hình kết xuất. Đây là nền tảng cho mọi framework trong bài tổng quan này.
- The Beginner’s Guide to Technical SEO — vị trí của kết xuất phía máy khách và JavaScript SEO trong bức tranh lớn hơn.
Bài thuyết trình của tôi
- How Search Works (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. (Tuyên bố miễn trừ thường trực của tôi: “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 đầy đủ hoặc chính xác 100%.»)
Nguồn trong ngành
- web.dev — Rendering on the Web — bài giải thích chuẩn của nhóm Chrome về CSR, SSR, SSG và hydration; mô hình tư duy tốt nhất không phụ thuộc framework cho phần chiến lược kết xuất của cách khắc phục.
- Google Search Central — Kiến thức cơ bản về JavaScript SEO — tài liệu nguồn sơ cấp chính thức về quá trình thu thập dữ liệu → kết xuất → lập chỉ mục và các liên kết có thể thu thập.
- Google Search Central — Khắc phục vấn đề JavaScript liên quan đến tìm kiếm — soft-404s sau định tuyến phía máy khách và History API, những vấn đề mọi bộ định tuyến SPA đều gặp.
- Danh sách phát JavaScript SEO của Martin Splitt — loạt video chính thức của Google về cách họ xử lý ứng dụng JS, không phụ thuộc framework.
- Onely — Trung tâm JavaScript SEO — các bài kỹ thuật chuyên sâu về kết xuất và kiểm tra JS-SEO từ một đơn vị chuyên môn.
Nhật ký thay đổi
Đã cập nhật 7 thg 9, 2026.
Tóm tắt biên tập và chi tiết thay đổi đã ghi nhận.Tóm tắt
Khôi phục toàn bộ văn bản tiếng Việt từ nguồn đã khóa bằng tuyến Sol ở mức suy luận cao, loại bỏ phần văn xuôi trộn tiếng Anh nhưng vẫn giữ nguyên cấu trúc, URL, mã, trích dẫn và ranh giới bằng chứng.
Chi tiết thay đổi
-
Đồng bộ lại bài viết, bộ nhớ dịch, văn bản thành phần và các ledger trực tiếp; bản thảo vẫn bị cách ly, chờ người bản ngữ đánh giá và chưa được xuất bản.
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.Tóm tắt
Tái tạo bản dịch tiếng Việt từ nguồn đã khóa bằng tuyến Luna để sửa phần tiếng Anh còn sót và giữ nguyên cấu trúc, mã, URL, trích dẫn và ranh giới bằng chứng.
Chi tiết thay đổi
-
Đã bản địa hóa lại các trường văn bản, bảo toàn token giao thức và hoàn tất sidecar thành phần; vẫn chờ native review và không mở xuất bản.
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 17 thg 7, 2026.
Tóm tắt biên tập và chi tiết thay đổi đã ghi nhận.Tóm tắt
Đã sửa cách diễn đạt tuyệt đối về khung HTML trống và độ trễ cố định theo phần đánh giá bằng chứng trong brief, bổ sung danh sách quyết định kết xuất theo từng tuyến, đồng thời mở rộng phần checklist và khắc phục sự cố bằng các trường hợp xác thực theo tuyến và theo giai đoạn.
Chi tiết thay đổi
-
Diễn đạt lại hành vi mặc định tạo khung HTML trống theo phạm vi phiên bản/bản dựng thay vì coi đó là hành vi cố định phổ quát, đồng thời loại bỏ con số trung vị không có nguồn về độ trễ trong hàng đợi kết xuất của Google.
-
Bổ sung danh sách quyết định theo từng tuyến (đầu ra, độ mới, cá nhân hóa, chi phí máy chủ, mức phụ thuộc JavaScript và hành vi khi lỗi) vào phần chiến lược kết xuất.
-
Bổ sung bảng xác thực theo từng giai đoạn vào checklist và hai mục khắc phục sự cố mới (không khớp khi hydration và khác biệt giữa điều hướng phía máy khách với truy cập URL trực tiếp).
Không thể so sánh đầy đủ — không có bản lưu trước đó cho lần sửa đổi này.