DEV Community

Cover image for How to add canonical url to Remix ๐Ÿ’ฟ
Can Rau
Can Rau

Posted on โ€ข Originally published at canrau.com

6 2

How to add canonical url to Remix ๐Ÿ’ฟ

This article has originally been published to canrau.com

Using loader data

This one is probably my fav, as it doesn't require any other function than the most probably already present loader. And because it's part of the loader it gives me full access to the already fetched content ๐Ÿฅฐ

import { homepage } from "/package.json"; // or import from some kind of "/config"
export const loader: LoaderFunction = async ({ params }) => {
  // [..]
  const { frontmatter, code } = await bundleMDX();
  // [..]
  const canonical = `${homepage}/${frontmatter?.lang}${frontmatter?.slug}`;
  return { frontmatter, code, canonical };
};
Enter fullscreen mode Exit fullscreen mode

Then in my root.tsx I have the following Document component, where especially lines 12 - 14 and line 23 are relevant.

function Document({
  children,
  title,
  lang,
}: {
  children: ReactNode;
  title?: string;
  lang: string;
}) {
  // use `export const handle = { hydrate: true };` in any route to enable JS
  const includeScripts = useShouldHydrate(); // from remix-utils
  const matches = useMatches();
  const match = matches.find((match) => match.data && match.data.canonical);
  const canonical = match?.data.canonical;

  return (
    <html lang={lang} className="dark scroll-smooth">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        {title ? <title>{title}</title> : null}
        <Meta />
        {!!canonical && <link rel="canonical" href={canonical} />}
        <Links />
        <link
          rel="alternate"
          type="application/rss+xml"
          href={`${rootUrl}/${lang}/feed.xml`}
          title="Can Rau's XML Feed"
        />
        <link
          rel="alternate"
          type="application/feed+json"
          href={`${rootUrl}/${lang}/feed.json`}
          title="Can Rau's JSON Feed"
        />
      </head>
      <body className="dark:bg-gray-900">
        {children}
        <ScrollRestoration />
        {includeScripts && <Scripts />}
        {process.env.NODE_ENV === "development" && <LiveReload />}
      </body>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

Note: More about the <link rel="alternate" /> in my other article RSS in Remix

More about useMatches in the Remix Package docs and in the Disabling Javscript docs

Remix used to provide the loader data to links, but they had to remove it for prefetching

Related links

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series ๐Ÿ“บ

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series ๐Ÿ‘€

Watch the Youtube series

๐Ÿ‘‹ Kindness is contagious

Please leave a โค๏ธ or a friendly comment on this post if you found it helpful!

Okay