ServerSide fetching for metatags

Hi I am looking for server side fetching for open graph metatags. I want to execute fetch on server side and then render page with title and metatags filled in. If returned result from fetch has length of 0 redirect user to /404 page. My meta tags setup
const [texturepack] = useAPIFetch(`texturepacks?id=${id}`);
return (
<>
<Suspense>
<Show when={texturepack()}>
<Title>{texturepack()?.[0]?.title || "Texture Pack"}</Title>

<MetaPageProvider
title={`Lisia Nora.pl - See texturepack ${
texturepack()?.[0]?.title
}! 🦊`}
url={`lisia-nora.pl/textures?id=${id}`}
description={texturepack()?.[0]?.description || "No description"}
image_url={texturepack()?.[0]?.thumbnail || ""}
/>
</Show>
</Suspense>
</>
);
const [texturepack] = useAPIFetch(`texturepacks?id=${id}`);
return (
<>
<Suspense>
<Show when={texturepack()}>
<Title>{texturepack()?.[0]?.title || "Texture Pack"}</Title>

<MetaPageProvider
title={`Lisia Nora.pl - See texturepack ${
texturepack()?.[0]?.title
}! 🦊`}
url={`lisia-nora.pl/textures?id=${id}`}
description={texturepack()?.[0]?.description || "No description"}
image_url={texturepack()?.[0]?.thumbnail || ""}
/>
</Show>
</Suspense>
</>
);
It works but does show nothing when the link is sent. Source code of MetaPageProvider
import { MetaProvider, Meta, Link } from "@solidjs/meta";

interface Props {
description: string;
image_url: string;
title: string;
url: string;
}

export default function MetaPageProvider({
description,
image_url,
title,
url,
}: Props) {
image_url = `https://lisia-nora.pl/${image_url}`;

return (
<MetaProvider>
<Meta property="og:description" content={description} />
<Meta property="og:locale" content="pl_PL" />
<Meta property="og:url" content={url} />
<Meta property="og:title" content={title} />
<Link rel="image_src" href={image_url} />
<Meta property="og:type" content="webapp" />
<Meta property="og:image" content={image_url} />
</MetaProvider>
);
}
import { MetaProvider, Meta, Link } from "@solidjs/meta";

interface Props {
description: string;
image_url: string;
title: string;
url: string;
}

export default function MetaPageProvider({
description,
image_url,
title,
url,
}: Props) {
image_url = `https://lisia-nora.pl/${image_url}`;

return (
<MetaProvider>
<Meta property="og:description" content={description} />
<Meta property="og:locale" content="pl_PL" />
<Meta property="og:url" content={url} />
<Meta property="og:title" content={title} />
<Link rel="image_src" href={image_url} />
<Meta property="og:type" content="webapp" />
<Meta property="og:image" content={image_url} />
</MetaProvider>
);
}
17 Replies
Jason.json
Jason.jsonOP3w ago
Source code of useAPIFetch
export function production() {
return process.env.NODE_ENV === "production";
}

const devServer = "http://localhost:3000";
const prodServer = "myserver base url";

export function useAPIFetch(url: string, options: RequestInit = {}) {
const baseUrl = production() ? prodServer : devServer;
const fullUrl = `${baseUrl}/api/${url}`;

return createResource(async () => {
try {
const response = await fetch(fullUrl, options);

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error:", error);
throw error;
}
});
}
export function production() {
return process.env.NODE_ENV === "production";
}

const devServer = "http://localhost:3000";
const prodServer = "myserver base url";

export function useAPIFetch(url: string, options: RequestInit = {}) {
const baseUrl = production() ? prodServer : devServer;
const fullUrl = `${baseUrl}/api/${url}`;

return createResource(async () => {
try {
const response = await fetch(fullUrl, options);

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error:", error);
throw error;
}
});
}
Brendonovich
Brendonovich3w ago
Add { deferStream: true} to the createResource, that'll delay the server from sending a response until the data is ready
Jason.json
Jason.jsonOP3w ago
Ok ok I'll try that
Brendonovich
Brendonovich3w ago
Ah also, don't destructure props in MetaPageProvider
Jason.json
Jason.jsonOP3w ago
Why?
Brendonovich
Brendonovich3w ago
Destructuring props is a no-no in solid
Jason.json
Jason.jsonOP3w ago
Oh dear I used to do this when I was using react I use it every where tbh 🤣
Brendonovich
Brendonovich3w ago
If it's really a problem you can add this https://github.com/orenelbaum/babel-plugin-solid-undestructure
GitHub
GitHub - orenelbaum/babel-plugin-solid-undestructure: A Babel plugi...
A Babel plugin for SolidJS that allows you to destructure component props without losing reactivity. - orenelbaum/babel-plugin-solid-undestructure
Jason.json
Jason.jsonOP3w ago
Oh ok ok
Brendonovich
Brendonovich3w ago
Also, assigning to image_url in the component body may not have the effect you expect, since the component body only runs once if the image_url prop changes (which it probably will when depending on a resource) then the url you're constructing won't update Make it a function that you call in the jsx instead
const full_image_url = () => `https://lisia-nora.pl/${props.image_url}`;
const full_image_url = () => `https://lisia-nora.pl/${props.image_url}`;
Jason.json
Jason.jsonOP3w ago
I mean i get the image URL from api
{
"id": "24746dd2-b3fe-11ef-a5c9-3cecef0f5064",
"title": "Sukuna [32x]",
"author": "Hiiro",
"version": "1.16^",
"description": "TexturPack dostosowany do PvP. Pozytywnie wpływa na twoją wydajność.",
"download": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/Sukuna [32x].zip",
"thumbnail": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/thumbnail.webp",
"icon": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/icon.webp"
}
{
"id": "24746dd2-b3fe-11ef-a5c9-3cecef0f5064",
"title": "Sukuna [32x]",
"author": "Hiiro",
"version": "1.16^",
"description": "TexturPack dostosowany do PvP. Pozytywnie wpływa na twoją wydajność.",
"download": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/Sukuna [32x].zip",
"thumbnail": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/thumbnail.webp",
"icon": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/icon.webp"
}
Brendonovich
Brendonovich3w ago
That's fine, i mean it'll change when rendering It'll start as undefined and then update to the actual value once fetched Or maybe start as "" since you've got a default value there But yeah since the component body doesn't re-run the full url won't get recalculated unless you do it in its own function
Jason.json
Jason.jsonOP3w ago
One more question do you suggest that I should build components like this instead of deconstructing their props?
interface Props {
myProp: string;
}

export default function Component(props:Props) {

return <p>props.myProp</p>
}
interface Props {
myProp: string;
}

export default function Component(props:Props) {

return <p>props.myProp</p>
}
Brendonovich
Brendonovich3w ago
Yeah
Jason.json
Jason.jsonOP3w ago
ok is it a good practise?
Brendonovich
Brendonovich3w ago
Yeah since things won't work properly if you destructure
Jason.json
Jason.jsonOP3w ago
I am not gonna lie my project got kinda messy I will clean it up. That's why I am asking I will refactor it a little bit
Want results from more Discord servers?
Add your server