In my nextjs app, I have a StrapiImage
component that accepts an image object from my strapi backend api as a prop. It assigns the width, height and url + any aditional props. (It's basically a shortcut for a regular next/image)
import Image from "next/image";
import { getStrapiMedia } from "../../lib/media";
export default function StrapiImage({ image, ...props })
return <Image src={getStrapiMedia(image)} // the getStrapiMedia function basically just returns the url to the image.
width={image.attributes.width}
height={image.attributes.height}
alt=""
{...props} />
}
Now, I wanted to add a blur placeholder for this image using placeholder="blur"
but since this is an external image, I have to provided a base64 image in the blurDataUrl
prop.
I wanted to generate an image like this with the plaiceholder
library similarly to this sollution I found.
There's a problem with this though, to generate the image, I need to use an await statement. In getStaticProps
, this wouldn't be a problem as I could just make the function async
, but I'm doing this inside a component and components must regular non-async functions.
The 'obvious' sollution would be to use the useEffect
hook like so:
import Image from "next/image";
import { getStrapiMedia } from "../../lib/media";
import { useEffect, useState } from "react";
import { getPlaiceholder } from "plaiceholder";
export default function StrapiImage({ image, ...props })
const [blur64, setBlur64]
useEffect(() => {
async function generatePlaceholder() {
// generate base64 image here
}
generatePlaceholder();
}, [])
return <Image src={getStrapiMedia(image)}
width={image.attributes.width}
height={image.attributes.height}
alt=""
placeholder="blur"
blurDataURL={blur64}
{...props} />
}
This would technically work, but it would only run only on the client-side, ultimately defeating the purpose of ssr and the whole image optimisation. (Especially considering plaiceholder's huge js bundle)
Is there any other way that I could do this without useEffect
but still in the component file? Ideally, I'd like it to run only on the server-side.
I'm using nextjs@13
I fixed the issue by using a strapi plugin to generate the placeholder image on the backend rather than on the frontend.
The issue in the title still remains unsolved though. Running pre-renderable async code at component-level doesn't seem to be officialy supported by nextjs. (with the pages directory)
Here's some "sollutions" I've found: (mostly workarounds)
useSSE
. I haven't looked into this too much but it looks like you can use the useSSE
library to run server-side at component-level. Here's an article covering this.