How toGet the absolute URL in Remix's MetaFunction
Let's say you want to add Open Graph image to a route in Remix, one first approach could be to import the image and use MetaFunction to add it:
app/routes/something.tsx import og from "./og.png"; export const meta: MetaFunction = () => { return [ { property: "og:image", content: og } ]; }
The problem with this is that unless you have configured your publicPath
in remix.config.mjs
to use a full URL you're going to get a relative URL from the import, so og
will be something like /build/_assets/og-HASH.png
, and og:image
needs to be absolute URLs.
One solution for that is to add the rest of the URL to the og
.
{ property: "og:image", content: new URL(og, "https://sergiodxa.com").href }
Now it will be a full URL, but here we're always using the same domain, what happens if our apps handles multiple domains? Or when testing locally? It will use the incorrect URL.
You may want to reach for environment variable, so you can replace the hard-coded domain with that.
{ property: "og:image", content: new URL(og, process.env.PUBLIC_HOST).href }
But because MetaFunction runs client-side you can't use env variables there, so what's our option? Well, MetaFunction receives the loader data, so we can use our loader!
app/routes/something.tsx export async function loader({ request }: LoaderFunctionArgs) { let ogUrl = new URL(og, request.url) return json({ ogUrl }) } export const meta: MetaFunction<typeof loader> = ({ data }) => { return [ { property: "og:image", content: data.ogUrl }, ]; }
Now our og:image
will be a full URL computed from the request.url
. But the loader may fail, so we have to handle that case too.
app/routes/something.tsx export const meta: MetaFunction<typeof loader> = ({ data }) => { if (!data) return []; // return empty list if loader failed return [ { property: "og:image", content: data.ogUrl }, ]; }