Panduan Remix SEO
How Remix's meta(), loader(), headers(), dan tautan() route exports control SEO — plus what changed sebagai Remix v2 became React Router, now pada v8.
Bahasa
TL;DR — Remix adalah sebuah React framework itu renders Anda halaman pada server oleh default — so konten adalah sudah di HTML sebelum Google ever memuat ini. itu goes sebuah panjang cara toward solving biggest JavaScript SEO masalah, though ini doesn’t guarantee pengindeksan atau rankings oleh itself. Anda masih memiliki untuk set Anda judul, deskripsi, dan tag canonical yourself, menggunakan Remix’s per-route
meta()function. SSR adalah foundation, not whole house. Note: Remix v2 merged ke React Router (now v8) — Remix 3 (beta) adalah sebuah separate, newer product; ini halaman covers Remix v2 / React Router route API sebagian besar situs run today.
What Remix adalah
Remix routes dapat render pada server dan menyediakan document metadata melalui route APIs. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Remix: Route meta server-rendered HTML improves initial konten delivery tetapi melakukan not guarantee Search pengindeksan. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Google: JavaScript SEO basics
Remix adalah sebuah meta-framework dibangun pada React. Plain React membangun Anda whole halaman di browser dengan JavaScript — Google gets sebuah nearly empty HTML file dan memiliki untuk run Anda code untuk see anything. Remix flips itu: ini runs Anda React components pada server dan mengirim back finished HTML dengan text, tautan, dan meta tags sudah di ini. server rendering adalah framework default — sebuah project dapat juga menjadi configured untuk statically prerender routes atau run di SPA mode, so confirm which mode sebuah given situs actually menggunakan alih-alih assuming dari framework name alone.
untuk SEO, itu’s sebuah huge head start pada default SSR path. There’s no waiting untuk JavaScript, no “render queue,” (terjemahan) “render queue,” dan crawler itu don’t run JavaScript di semua (banyak AI bot, social preview bot) masih get Anda full konten.
One naming note itu trips people up, dan ini adalah more layered daripada ini digunakan untuk menjadi:
di late 2024 Remix team merged Remix v2’s application APIs ke React
Router v7 — sama route exports (meta, loader, headers, links,
ErrorBoundary), renamed package. React Router memiliki since moved untuk v8 (June
2026), dengan v7 masih receiving security updates. Separately, Remix name now
juga refers untuk Remix 3, sebuah newer beta full-stack framework team describes
sebagai “a different direction” (terjemahan) “sebuah berbeda direction” dari React Router — sebuah distinct product, not hanya sebuah
renamed one. Everything pada ini halaman documents Remix v2 / React Router v7-v8
route API itu sebagian besar production Remix situs run today; ini melakukan not cover Remix 3.
How Anda tambahkan SEO tags di Remix
Remix gives setiap route (setiap halaman) special functions Anda export dari file:
meta()— sets Anda<title>, deskripsi meta, Open Graph tags, dan bahkan data terstruktur. ini adalah main SEO alat.loader()— fetches data pada server (like sebuah blog post dari Anda database) sebelum HTML adalah dikirim. Andameta()dapat gunakan itu data, so judul dapat menjadi dynamic.links()— menambahkan<link>tags like favicons dan stylesheets.headers()— sets respons header HTTP (caching, robots aturan).
Here’s simplest versi dari sebuah judul dan deskripsi:
export const meta = () => {
return [
{ title: "About Us | My Site" },
{ name: "description", content: "Learn about our team and mission." },
];
};itu renders straight ke server HTML — exactly where Google ingin ini.
one mistake untuk hindari
paling umum Remix SEO bug: child halaman quietly lose meta tags set oleh
parent layouts. Remix hanya mempertahankan deepest route’s meta() dan throws away
rest unless Anda tell ini not untuk. jika Anda homepage layout sets sebuah situs-wide
deskripsi dan Anda tentang halaman exports -nya own meta() without merging,
deskripsi disappears pada itu halaman. fix adalah di Advanced tab.
sederhana takeaway
- Remix adalah sebuah safe SEO choice because ini adalah server-rendered oleh default.
- Anda masih memiliki untuk write Anda judul, deskripsi, dan canonicals dengan
meta(). - Watch out untuk child halaman dropping parent meta tags.
ingin nyata versi — loader dan nyata 404s, headers() untuk X-Robots-Tag,
tag canonical two cara, dan React Router v7 migration? Switch untuk
Advanced tab. untuk framework-agnostic background, see
JavaScript SEO dan
JavaScript frameworks hub.
TL;DR — Remix adalah SSR-oleh-default, so konten ships di initial HTML dengan no render-queue dependency — architecture menghapus sebagian besar JS-SEO risk when SSR adalah what’s actually deployed, though ini doesn’t oleh itself guarantee pengindeksan, peringkat, atau Core Web Vitals outcomes. berfungsi adalah di per-route exports:
meta()(judul, deskripsi, OG, JSON-LD, dan dynamic canonicals viatagName: "link"),loader()(server data + nyata HTTP 404s/redirects),headers()(Cache-Control,X-Robots-Tag), danlinks()(static canonicals, preloads). signature gotcha: nested routes drop parent meta unless Anda merge ini viamatchesargument. Naming, dated: Remix v2’s APIs merged ke React Router v7 di 2024; React Router adalah now pada v8 (v7 masih security-didukung); Remix 3 (beta) adalah sebuah separate, newer full-stack framework, not simply React Router renamed. ini halaman covers Remix v2 / React Router v7-v8 route API.
SSR oleh default — why Remix starts ahead
Remix’s server rendering adalah sebuah framework capability whose deployment perilaku depends pada adapter dan route code. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Remix: Route meta Validate delivered HTML dan resources alih-alih assuming sebuah framework default ensures SEO outcomes. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Google: JavaScript SEO basics
Scope note: walkthrough below documents meta() / loader() /
headers() / links() / ErrorBoundary route module API sebagai ini exists di Remix
v2 dan React Router v7-v8 framework mode — what besar majority dari production
Remix/React Router situs run. Remix 3 (beta) adalah sebuah separate, ground-up rewrite
dengan berbeda APIs dan isn’t covered here; periksa which one Anda’re actually pada
sebelum copying anything below.
Bare React (CRA, Vite + React) ships sebuah empty <div id="root"></div> dan membangun
halaman di browser. Google dapat render itu, tetapi Anda’ve signed up untuk
render queue, statelessness, dan DOM-parity masalah covered di
JavaScript SEO. Remix doesn’t memiliki itu default:
ini executes Anda nested route tree (Root → Layout → Route) pada server dan, oleh
default, mengirim konten-complete HTML pada setiap document permintaan. framework mode
dapat juga menjadi configured untuk statically prerender routes di bangun time atau run sebagai sebuah
client-rendered SPA — so untuk apa pun given deployment, confirm actual rendering
mode (via curl/View Source, below) alih-alih assuming SSR dari framework
name.
Google’s own guidance lines up dengan ini. dari JavaScript SEO basics doc:
“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.” (terjemahan) “server-side atau pre-rendering adalah masih sebuah great idea because ini membuat Anda situs web
faster untuk pengguna dan crawler, dan not semua bot dapat run JavaScript.” itu last
clause adalah whole argument untuk Remix — Bingbot renders JS slowly dan incompletely,
dan banyak AI crawler dan social preview bot (Twitterbot, facebookexternalhit)
don’t render di semua. Remix’s SSR output menyajikan semua dari them correctly without special
handling.
setelah initial muat, Remix menggunakan client-side routing untuk subsequent navigations
(like setiap React framework). itu’s fine: Google discovers tautan dari SSR’d
HTML dan melakukan crawl setiap URL sebagai -nya own server permintaan — setiap returning full HTML. ini
doesn’t rely pada watching client-side route transitions. dan because Remix’s <Link>
renders sebuah nyata <a href>, tautan adalah dapat di-crawl oleh construction — Google
“can only discover your links if they are <a> HTML elements with an href
attribute.” (terjemahan) “dapat hanya menemukan Anda tautan jika mereka adalah undefined HTML elements dengan sebuah undefined
attribute.”
meta() export: judul, deskripsi, OG, JSON-LD
setiap route dapat export sebuah meta function returning sebuah array dari descriptor objects.
Because ini dapat read loader data, metadata adalah dynamic dan set di initial HTML
<head> — no JS-injection delay:
// app/routes/blog.$slug.tsx
import type { MetaFunction } from "@remix-run/node";
export const meta: MetaFunction<typeof loader> = ({ data }) => {
if (!data) return [{ title: "Post Not Found" }];
return [
{ title: `${data.post.title} | My Blog` },
{ name: "description", content: data.post.excerpt },
{ property: "og:title", content: data.post.title },
{ property: "og:image", content: data.post.ogImage },
{ property: "og:type", content: "article" },
{
"script:ld+json": {
"@context": "https://schema.org",
"@type": "Article",
headline: data.post.title,
datePublished: data.post.publishedAt,
author: { "@type": "Person", name: data.post.author },
},
},
];
};{ "script:ld+json": {...} } descriptor renders sebuah proper
<script type="application/ld+json"> tag di SSR’d <head> — terlihat untuk Google’s
parser without executing apa pun JavaScript. Martin Splitt’s preference applies:
“We support JSON-LD in dynamically rendered content, but it’s generally better to
have it in the initial HTML.” (terjemahan) “kami mendukung JSON-LD di dynamically rendered konten, tetapi ini adalah umumnya better untuk
memiliki ini di initial HTML.” di Remix, initial HTML adalah default place ini
lands.
Nested routes dan meta inheritance — umum trap
ini adalah Remix SEO mistake. Remix takes last matching route dengan sebuah meta
export and uses that — parent meta is dropped. A child that exports its own
meta() without merging silently loses every tag the root set (site-wide
description, root OG tags, etc.):
// ❌ Root's description is now gone on this route
export const meta: MetaFunction = () => {
return [{ title: "About Us" }];
};fix adalah matches argument — flatten dan spread parent meta:
// ✅ Keep parent meta, append your own
export const meta: MetaFunction = ({ matches }) => {
const parentMeta = matches.flatMap((match) => match.meta ?? []);
return [...parentMeta, { title: "About Us" }];
};
// ✅ Keep parent meta but override only the title
export const meta: MetaFunction = ({ matches }) => {
const parentMeta = matches
.flatMap((match) => match.meta ?? [])
.filter((meta) => !("title" in meta));
return [...parentMeta, { title: "About Us" }];
};jika Anda set global tags, put truly universal ones (charset, viewport) directly di
root.tsx’s JSX where merging tidak pernah strips them, dan reserve meta() untuk
halaman-tingkat signals Anda actually ingin untuk override per route.
loader() function: nyata 404s, nyata redirects, dynamic meta
Loaders run server-side hanya — DB kueri, API panggilan, dan secrets tidak pernah reach Googlebot. SEO payoff adalah correct HTTP kode status:
// app/routes/products.$id.tsx
import { json, redirect } from "@remix-run/node";
import type { LoaderFunctionArgs } from "@remix-run/node";
export async function loader({ params }: LoaderFunctionArgs) {
const product = await db.products.findById(params.id);
if (!product) {
throw new Response("Product not found", { status: 404 });
// ✅ real HTTP 404 — not a soft 404
}
if (product.movedTo) {
throw redirect(`/products/${product.movedTo}/`, 301); // ✅ real 301
}
return json(product);
}ini adalah antidote untuk soft-404 masalah SPAs buat — sebuah 200 OK halaman itu
hanya says “not found.” (terjemahan) “tidak ditemukan.” sebagai John Mueller put ini: “If a page returns a 200 but there’s
no content — that’s a soft 404. That’s problematic because we don’t know to treat it
as a 404. From a crawling standpoint, we’ll just keep trying to crawl it.” (terjemahan) “jika sebuah halaman mengembalikan sebuah 200 tetapi there’s
tanpa konten — itu’s sebuah soft 404. itu’s problematic because kami don’t know untuk treat ini
sebagai sebuah 404. dari sebuah crawling standpoint, kami’ll hanya pertahankan trying untuk crawl ini.” Remix’s
throw new Response(..., { status: 404 }) propagates sebuah genuine 404, which lines up
dengan Google’s instruction untuk “use a meaningful status code, like a 404 for a page
that could not be found.” (terjemahan) “gunakan meaningful kode status, like sebuah 404 untuk sebuah halaman
itu dapat not menjadi ditemukan.”
Whatever sebuah loader mengembalikan adalah exposed untuk client bahkan jika component doesn’t render ini — treat loaders like public API endpoints dan don’t kembalikan secrets.
ini status propagation adalah what happens pada sebuah direct document permintaan ( case sebuah crawler membuat). Client-side navigations setelah hydration adalah sebuah separate code path itu dapat behave differently, dan beberapa hosting adapters rewrite atau intercept thrown respons — verify both direct-permintaan dan post-hydration perilaku pada Anda actual deployment alih-alih assuming ini dari loader code alone.
headers() function: Cache-Control dan X-Robots-Tag
Per-route header HTTP — lever untuk CDN caching (faster TTFB → better Core Web Vitals) dan untuk robots directives itu berfungsi bahkan pada crawler itu don’t read HTML body:
import type { HeadersFunction } from "@remix-run/node";
// CDN-friendly caching
export const headers: HeadersFunction = () => ({
"Cache-Control": "max-age=300, s-maxage=3600, stale-while-revalidate=86400",
});
// HTTP-level noindex — effective for Bingbot and non-rendering crawlers
export const headers: HeadersFunction = () => ({
"X-Robots-Tag": "noindex, nofollow",
});X-Robots-Tag: noindex di header tingkat reaches crawler itu tidak pernah parse
body. oleh default hanya deepest route’s headers() runs di sebuah nested tree, so
simplest pattern adalah untuk define headers pada leaf routes hanya dan hindari merge
complexity.
sebuah meta-noindex caveat worth knowing regardless dari framework, dari Martin Splitt:
“The noindex tag can cause Google to skip rendering entirely. So if you’re trying
to noindex via JavaScript, you may be creating a situation where Google never even
runs the JavaScript to see the noindex.” (terjemahan) “ undefined tag dapat cause Google untuk skip rendering entirely. So jika Anda’re trying
untuk undefined via JavaScript, Anda dapat menjadi membuat sebuah situation where Google tidak pernah bahkan
runs JavaScript untuk see noindex.” Remix sidesteps ini because directive
lands di SSR’d <head> (atau sebuah header HTTP), not di client-hanya JavaScript.
links() export dan tag canonical — two cara
links() injects <link> elements (favicons, stylesheet preloads, static
canonicals). tetapi ini memiliki no access untuk loader data — ini adalah static per route module:
export const links: LinksFunction = () => [
{ rel: "canonical", href: "https://example.com/canonical-url/" },
];untuk dynamic canonicals — paginated, filtered, atau parameterized URLs — gunakan meta()
dengan tagName: "link", which melakukan see data, params, dan location:
export const meta: MetaFunction<typeof loader> = ({ data }) => [
{
tagName: "link",
rel: "canonical",
href: `https://example.com/products/${data.product.slug}/`,
},
];aturan: static canonical → links(); dynamic canonical → meta() dengan
tagName: "link". ini matches Martin Splitt’s advice untuk set canonicals di HTML
alih-alih JavaScript — “set your canonical in the HTML, not with JavaScript… it’s
just more fragile.” (terjemahan) “set Anda canonical di HTML, not dengan JavaScript… ini adalah
hanya more fragile.” Both Remix approaches render ke server HTML. (See
tag canonical deep dive.)
Error boundaries dan 404/5xx halaman
When sebuah loader, tindakan, atau component throws, route’s ErrorBoundary renders — di
place, inside surviving layout (nav, footer stay). Paired dengan sebuah thrown 404
respons, Anda get sebuah nyata 404 status dan sebuah usable halaman:
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";
export function ErrorBoundary() {
const error = useRouteError();
if (isRouteErrorResponse(error) && error.status === 404) {
return <div><h1>404 — Page Not Found</h1></div>;
}
return <div>Something went wrong.</div>;
}sebuah root-tingkat ErrorBoundary di app/root.tsx catches anything route boundaries
don’t. myth itu “throwing a 404 breaks the layout” (terjemahan) “throwing sebuah 404 breaks layout” adalah salah — boundary
renders di dalam route hierarchy.
Sitemaps dan robots.txt sebagai routes
Remix memiliki no dibangun-di sitemap generator; Anda bangun them sebagai resource routes.
bracket notation escapes dot so URL adalah literally /sitemap.xml:
// app/routes/sitemap[.xml].tsx
export async function loader() {
const posts = await db.posts.findMany({ where: { published: true } });
const body = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${posts.map((p) => ` <url><loc>https://example.com/blog/${p.slug}/</loc><lastmod>${p.updatedAt.toISOString()}</lastmod></url>`).join("\n")}
</urlset>`;
return new Response(body, {
headers: { "Content-Type": "application/xml", "Cache-Control": "public, max-age=3600" },
});
}robots.txt mengikuti yang sama app/routes/robots[.txt].tsx pattern, returning
text/plain.
Remix, React Router, dan 2026 product split — sebuah dated timeline
ini memiliki gotten more layered since original 2024 merge, so treat ini sebagai history plus saat ini state alih-alih sebuah single fact:
- Dec 2024 — Remix v2 merges ke React Router v7.
@remix-run/reactdan@remix-run/nodeconsolidate kereact-router;@remix-run/*packages masih berfungsi sebagai sebuah bridge. What’s SEO-relevant dari ini move: routes.ts— sebuah routing config file; routes dapat menjadi defined programmatically untuk more flexible struktur URL.- Static pre-rendering — individual routes dapat opt ke bangun-time HTML generation (SSG-style), atau SPA mode — configuration choices, not automatic.
- End-untuk-end jenis safety —
loaderkembalikan jenis flow kemeta(), reducing bugs di dynamic meta generation. - Vite — default bundler since Remix v2; route-tingkat code splitting mempertahankan client bundles lean (baik untuk TBT/LCP).
- What didn’t perubahan:
meta()/loader()/headers()/links()/ErrorBoundarypattern dan<Meta />/<Links />/<Scripts />components diroot.tsx. Existing Remix v2 SEO code carries di atas dengan minimal perubahan. - June 2026 — React Router v8 ships. React Router v7 remains security-didukung;
Remix v2 dan React Router v6 adalah now end-dari-life. route module SEO API ini
halaman documents (
meta,loader,headers,links,ErrorBoundary) adalah yang sama shape di seluruh v7 dan v8 — periksa Anda installed versi’s changelog untuk apa pun descriptor-tingkat perubahan sebelum copying code verbatim. - juga sebagai dari 2026 — Remix adalah no longer hanya “the old name for React Router.” (terjemahan) “ old name untuk React Router.”
Remix team describes React Router sebagai mereka React meta-framework, dan Remix
(now di sebuah “Remix 3” (terjemahan) “Remix 3” beta) sebagai sebuah separate, newer full-stack framework — “one team,
two projects.” (terjemahan) “one team,
two projects.” jika Anda’re auditing atau membangun pada
@remix-run/*/react-routerroute exports, ini artikel’s API guidance applies directly. jika Anda’re pada Remix 3, verify -nya documentation independently — meta/loader/headers/tautan pattern described here adalah not confirmed untuk carry di atas unchanged.
Bottom line untuk sebagian besar situs di production today: “Remix SEO” (terjemahan) “Remix SEO” dan “React Router SEO” (terjemahan) “React Router SEO” adalah masih yang sama route API dan yang sama practical topic. hanya don’t assume itu juga covers Remix 3.
Anda masih don’t perlu dynamic rendering
Because Remix menyajikan HTML pada server, Anda tidak pernah perlu Rendertron atau Prerender.io. Google deprecated dynamic rendering anyway: “Dynamic rendering was a workaround and not a long-term solution… it creates additional complexities and resource requirements.” (terjemahan) “Dynamic rendering adalah sebuah workaround dan not sebuah panjang-istilah solusi… ini membuat additional complexities dan resource requirements.” SSR adalah recommended path, dan Remix gives ini untuk Anda oleh default.
Auditing sebuah Remix situs
- periksa initial HTML dengan
curlatau View Source — not DevTools Elements (which menampilkan post-hydration DOM). - Verify nyata HTTP kode status pada missing halaman (404, not 200) dan redirects (301/302).
- Test dengan GSC pemeriksaan URL — Remix’s disajikan HTML seharusnya match rendered view.
- cari nested-meta merge bugs — confirm child halaman masih carry situs-wide deskripsi dan OG tags.
- Validate JSON-LD dengan Rich hasil Test, dan run sebuah crawl (Ahrefs situs Audit, Screaming Frog) untuk catch blocked assets dan depth issues.
None dari above adalah sebuah guarantee dari pengindeksan, rankings, atau Core Web Vitals — SSR, correct kode status, dan clean metadata hapus architecture-tingkat risk; rest masih depends pada konten quality, deployment adapter, dan how halaman performs terhadap everything else di SERP.
untuk base library underneath Remix, see React SEO; untuk framework-agnostic rendering aturan, see JavaScript SEO dan JavaScript frameworks hub.
AI summary
sebuah condensed take pada Advanced versi:
- Remix adalah SSR-oleh-default — ini renders nested route tree pada server dan,
oleh default, ships konten-complete HTML pada setiap document permintaan (framework mode
dapat juga menjadi atur ke static prerender atau SPA, so verify actual deployed mode).
No render queue, no empty root
<div>, dan non-rendering crawler (Bingbot, AI bot, social bot) get full konten — though none dari ini guarantees pengindeksan atau rankings oleh itself. meta()adalah primary SEO alat — judul, deskripsi, OG, JSON-LD ("script:ld+json"), dan dynamic canonicals viatagName: "link". ini dapat readloaderdata, so metadata adalah konten-spesifik dan di initial HTML.- ** signature gotcha:** nested routes gunakan deepest route’s
metadan drop parent meta unless Anda merge ini denganmatchesargument. loader()runs server-side;throw new Response("", { status: 404 })gives sebuah nyata 404 (no soft 404) danthrow redirect()gives sebuah nyata 301/302.headers()setsCache-Control(TTFB/CWV) danX-Robots-Tagdi HTTP tingkat — berfungsi bahkan untuk crawler itu don’t read body.links()vsmeta()untuk canonicals:links()adalah static (no loader data);meta()dengantagName: "link"adalah dynamic. Static →links(), dynamic →meta().ErrorBoundaryrenders inside surviving layout dan pairs dengan thrown 404s untuk correct status + usable halaman.- Remix v2’s APIs merged ke React Router v7 (Dec 2024) — sama SEO APIs,
renamed packages (
react-router), baruroutes.ts, optional static pre-rendering, Vite bundling. React Router adalah now pada v8 (June 2026; v7 masih security-didukung). Separately, Remix 3 (beta) adalah sebuah newer, distinct full-stack framework — not hanya React Router di bawah old name. ini artikel covers Remix v2 / React Router v7-v8 route API. No dynamic rendering alat needed untuk itu API either cara.
Official documentation
Primary-source documentation dari Remix / React Router dan mesin pencari.
Remix / React Router
- Remix —
metafunction — per-route meta tags, descriptors, danmatchesmerging. - Remix —
loaderfunction — server-side data fetching dan thrown respons. - Remix —
headersfunction — per-route respons header HTTP. - Remix —
linksfunction —<link>elements (canonical, preload, favicon). - Remix —
ErrorBoundary— route dan root error handling. - React Router v7 announcement — Remix v2 → React Router merge (Dec 2024).
- React Router v8 — saat ini release (June 2026) dan “one team, two projects” (terjemahan) “one team, two projects” note pada how Remix 3 now differs dari React Router.
- React Router docs — where Remix v2-lineage route API now lives, currently pada v8.
- memahami JavaScript SEO basics — three-phase crawl/render/indeks process, kode status,
<a href>tautan, dan SSR guidance. - Dynamic rendering (deprecated) — why dynamic rendering adalah sebuah workaround, not sebuah solusi.
- di-Depth Guide untuk How Google Search berfungsi — where rendering sits di crawl → indeks → sajikan.
Quotes dari source
pada—record statements dari Google itu bear directly pada Remix’s SSR-pertama model. setiap search-mesin tautan adalah sebuah deep tautan itu jumps untuk quoted passage.
Google — why SSR helps
- “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.” (terjemahan) “server-side atau pre-rendering adalah masih sebuah great idea because ini membuat Anda situs web faster untuk pengguna dan crawler, dan not semua bot dapat run JavaScript.” Jump untuk quote
- “Google can only discover your links if they are
<a>HTML elements with anhrefattribute.” (terjemahan) “Google dapat hanya menemukan Anda tautan jika mereka adalah undefined HTML elements dengan sebuah undefined attribute.” Jump untuk quote
Google — kode status ( loader + ErrorBoundary pattern)
- “To tell Googlebot if a page can’t be crawled or indexed, use a meaningful status code, like a 404 for a page that could not be found or a 401 code for pages behind a login.” (terjemahan) “untuk tell Googlebot jika sebuah halaman dapat’t menjadi di-crawl atau terindeks, gunakan meaningful kode status, like sebuah 404 untuk sebuah halaman itu dapat not menjadi ditemukan atau sebuah 401 code untuk halaman behind sebuah login.” Jump untuk quote
Google — dynamic rendering adalah deprecated
- “Dynamic rendering was a workaround and not a long-term solution for problems with JavaScript-generated content in search engines.” (terjemahan) “Dynamic rendering adalah sebuah workaround dan not sebuah panjang-istilah solusi untuk masalah dengan JavaScript-generated konten di mesin pencari.” Jump untuk quote
Remix SEO checklist
sebuah quick pass untuk apa pun Remix / React Router v7 project:
- penting halaman adalah server-rendered ( default) — confirm konten adalah di
View Source /
curl, not hanya post-hydration DOM. - setiap dapat diindeks route sets sebuah
<title>dan deskripsi meta viameta()export. - Child routes itu export
meta()merge parent meta viamatchesargument (no dropped situs-wide tags). - Missing resources
throw new Response(..., { status: 404 })diloader— verify sebuah nyata 404, not sebuah soft 404 (200 + “not found” (terjemahan) “tidak ditemukan”). - Moved URLs
throw redirect(target, 301)dari loader — nyata 301/302. - tag canonical adalah set di HTML:
links()untuk static,meta()dengantagName: "link"untuk dynamic (paginated/filtered/param URLs). -
noindexadalah set di SSR’d<head>atau viaheaders()X-Robots-Tag— tidak pernah client-side hanya. -
headers()sets sensibleCache-Controluntuk CDN caching / TTFB pada leaf routes. - JSON-LD adalah ditambahkan via
{ "script:ld+json": {...} }dimeta()dan validated di Rich hasil Test. -
sitemap.xmldanrobots.txtexist sebagai resource routes (sitemap[.xml].tsx,robots[.txt].tsx) dan adalah submitted di Search Console. - tautan internal gunakan Remix
<Link>(renders nyata<a href>). - No
@remix-run/*→react-routerrename surprises jika Anda’re migrating untuk v7.
mental models
1. SSR adalah floor, not ceiling.
Remix renders pada server oleh default, which menghapus penemuan/rendering risk
class untuk free. ini melakukan not auto-handle judul, deskripsi, canonicals,
data terstruktur, cache headers, atau 404 kode status — setiap adalah sebuah explicit meta(),
headers(), links(), atau loader decision. SSR adalah sebuah prerequisite, not sebuah complete
SEO solusi.
2. right export untuk right signal.
- HTML
<head>tags (judul, deskripsi, OG, JSON-LD, dynamic canonical) →meta() - Static
<link>elements (favicon, preload, static canonical) →links() - HTTP kode status (404, 301, 302) dan server data →
loader() - respons header HTTP (
Cache-Control,X-Robots-Tag) →headers() - Error/404 halaman bodies →
ErrorBoundary
3. meta() beats links() when data penting.
links() dapat’t see loader data; meta() dapat. So anything itu depends pada fetched
konten — sebuah dynamic canonical, sebuah data-driven judul — belongs di meta().
4. nesting default adalah “deepest wins, parents dropped.” (terjemahan) “deepest wins, parents dropped.”
decision aturan: apa pun child itu exports meta() harus consciously choose untuk merge
parent meta (matches) atau ini loses ini. Put universal tags (charset/viewport) di
root.tsx JSX where merging dapat’t strip them.
5. nyata kode status adalah sebuah SEO fitur, not sebuah accident.
throw new Response(..., { status: 404 }) dan throw redirect() adalah how Remix
menghindari soft-404 / fake-redirect failures dari CSR SPAs. Reach untuk thrown respons
alih-alih rendering sebuah error message di sebuah 200.
Remix SEO — cheat sheet
Per-route exports → what mereka control
| Export | Controls | Sees loader data? | SEO gunakan |
|---|---|---|---|
meta() | <head> meta/judul/JSON-LD | Yes | judul, deskripsi, OG, JSON-LD, dynamic canonical |
links() | <link> elements | No | Static canonical, favicon, preload |
loader() | server data + status | n/sebuah (ini adalah data) | nyata 404/301, server-hanya fetching |
headers() | respons header HTTP | via loaderHeaders | Cache-Control, X-Robots-Tag |
ErrorBoundary | Error/404 halaman body | via useRouteError | Usable 404 halaman di-layout |
tag canonical — pick right one
| perlu | gunakan |
|---|---|
| Static, known di bangun | links() → { rel: "canonical", href } |
| Dynamic (depends pada loader data) | meta() → { tagName: "link", rel: "canonical", href } |
kode status dari sebuah loader
throw new Response("Not found", { status: 404 }); // real 404
throw redirect("/new-url/", 301); // real 301Fast facts
- Remix adalah SSR oleh default — konten di initial HTML, no render queue (confirm deployed mode; static prerender/SPA adalah juga configuration options).
- Nested meta: deepest route wins; merge parents via
matchesatau lose them. X-Robots-Tagviaheaders()berfungsi untuk crawler itu don’t render.- Remix v2’s APIs merged ke React Router v7 (Dec 2024), sama route API,
package renamed untuk
react-router. React Router adalah now pada v8 (v7 masih security-didukung). Remix 3 (beta) adalah sebuah separate, newer framework — not covered oleh ini halaman. - Resource routes:
sitemap[.xml].tsx,robots[.txt].tsx(brackets escape dot). - No dynamic rendering alat (Rendertron/Prerender.io) needed — atau recommended.
Verify what crawler actually menerima
Remix renders pada server, tetapi selalu confirm initial HTML alih-alih post-hydration DOM di DevTools.
periksa raw server HTML (konten + tags adalah present sebelum JS runs)
# Title, meta description, canonical — should all be in the raw response
curl -s https://example.com/blog/my-post/ | grep -iE '<title>|name="description"|rel="canonical"'
# Confirm JSON-LD is in the SSR'd head
curl -s https://example.com/blog/my-post/ | grep -i 'application/ld+json'Confirm nyata HTTP kode status (no soft 404s, nyata redirects)
# A missing page must return 404, not 200
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/blog/does-not-exist/
# A moved URL should return 301/302 with a Location header
curl -sI https://example.com/old-url/ | grep -iE 'HTTP/|location'periksa HTTP-tingkat robots / cache headers dari headers()
curl -sI https://example.com/private-route/ | grep -iE 'x-robots-tag|cache-control'sebuah minimal robots.txt resource route
// app/routes/robots[.txt].tsx
export async function loader() {
return new Response(
`User-agent: *\nAllow: /\nSitemap: https://example.com/sitemap.xml\n`,
{ headers: { "Content-Type": "text/plain" } }
);
} alat untuk auditing sebuah Remix situs
curl/ View Source — ground truth untuk what’s di initial SSR’d HTML (judul, deskripsi, canonical, JSON-LD) sebelum hydration. Don’t trust DevTools Elements alone — ini menampilkan post-JS DOM.- Google Search Console — pemeriksaan URL — see how Googlebot di-crawl dan rendered sebuah single Remix URL; untuk SSR halaman disajikan dan rendered HTML seharusnya match.
- Rich hasil Test — validate JSON-LD Anda emit via
"script:ld+json". - Ahrefs situs Audit — crawl whole situs untuk missing/duplicate meta ( nested-meta merge bug surfaces here), broken canonicals, rantai pengalihan, dan depth.
- Screaming Frog SEO Spider — sebuah developer-friendly crawl untuk confirm judul, canonicals, dan kode status di seluruh routes.
vite-bundle-visualizer— inspect client bundles (Remix menggunakan Vite) untuk pertahankan JS lean untuk Core Web Vitals.- Bing Webmaster alat — pemeriksaan URL — verify Bingbot sees SSR’d konten.
Test yourself: Remix SEO
Five quick pertanyaan pada how Remix handles SEO. Pick sebuah jawaban untuk setiap, lalu periksa.
Resources worth Anda time
My writing
- JavaScript SEO: sebuah Definitive Guide — rendering, DOM parity, paling-restrictive-directive aturan, dan choosing sebuah rendering mode — framework-agnostic background untuk everything Remix melakukan oleh default.
- Beginner’s Guide untuk SEO teknis — where rendering dan frameworks fit di bigger picture.
My speaking
- How Search berfungsi (SlideShare) — my walkthrough dari crawling, rendering, pengindeksan, dan peringkat. (My standing disclaimer applies: “This is my understanding of systems… not going to be 100% complete or accurate.” (terjemahan) “ini adalah my understanding dari sistem… not going untuk menjadi 100% complete atau accurate.”)
dari sekitar industry
- Remix docs —
metafunction — primary source untuk per-route metadata danmatchesmerging. - Remix docs —
loaderdanheaders— server data, thrown respons, dan header HTTP. - React Router v7 announcement / React Router v8 / React Router docs — Remix v2 merge, saat ini v8 release, dan where route API now lives (Remix 3 adalah sebuah separate, newer product).
- memahami JavaScript SEO basics (Google) — aturan Remix’s output adalah judged oleh: kode status,
<a href>tautan, SSR guidance. - Dynamic rendering (deprecated) (Google) — why Remix situs tidak pernah perlu Rendertron/Prerender.io.
- web.dev — rendering pada Web — Chrome team’s CSR/SSR/SSG/hydration explainer; conceptual backbone untuk Remix’s server-pertama model.
- r/TechSEO — community untuk framework rendering/pengindeksan debugging.
Log perubahan
Diperbarui 18 Jul 2026.
Ringkasan editorial dan detail perubahan yang tercatat.Detail perubahan
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
Perbandingan lengkap tidak tersedia — tidak ada cuplikan sebelumnya yang diarsipkan untuk revisi ini.