how to use blob with next/image? issues with RSC
Answered
Chinese softshell turtle posted this in #help-forum
Chinese softshell turtleOP
export default async function Profile(props: any) {
let session = auth.getSession()
const client = session.client
const authenticated = await session.isSignedIn()
let authData
let publicData
let imageBlob
if (authenticated) {
authData = await e
.select(e.Post, (post) => ({
name: true,
photoUrl: true,
filter: e.op(post.created_by, "?=", e.global.current_user),
}))
.run(client)
const r2Client = new CloudflareR2Client({
// Cloudflare AWS Credentials
accessKeyId: "",
secretAccessKey:
"",
// Cloudflare Account ID
accountId: "",
// Cloudflare Bucket name
bucket: "",
})
imageBlob = await r2Client.get("github-profile")
console.log(imageBlob, "img blob")
} else {
publicData = await e
.select(e.Post, (post) => ({
name: true,
}))
.run(client)
}
return (
<>
{authData && imageBlob && (
<header className="flex justify-between items-center pb-4">
<div>Authenticated data:</div>
{JSON.stringify(authData)}
<Image
src={imageBlob}
width={500}
height={500}
alt="Picture of the author"
unoptimized
/>
</header>
)}have above code
Answered by joulev
you cannot(*) fetch an image and render it in an <img> (or next/image for that matter) like that because <img> is fundamentally client side fetching. you give it an URL, it fetches the image on that URL in the client side, separate from the page.
so instead of fetching the file directly, you should instead generate a URL from which the browser can use to fetch the image. then use that generated URL as the
(*) technically you can, if you convert the image to base64 and render the <img> with the base64. I wouldn't recommend that though, it is not optimised.
so instead of fetching the file directly, you should instead generate a URL from which the browser can use to fetch the image. then use that generated URL as the
src.(*) technically you can, if you convert the image to base64 and render the <img> with the base64. I wouldn't recommend that though, it is not optimised.
104 Replies
Chinese softshell turtleOP
i stipped creds but I get a
Blobfrom cloudflare R2 back
this if I log it
how do I pass it to next/image?
google says unoptimised should work, it does not
https://nextjs.org/docs/pages/api-reference/components/image#unoptimized
https://nextjs.org/docs/pages/api-reference/components/image#unoptimized
it wants
String or StaticImportfails too
gpt-4 rec'd I do
imageBlob = await r2Client.get("github-profile")
imageUrl = URL.createObjectURL(imageBlob)im so confused, everyone says it should work
thats how you turn a file blob into something
img or Image from next.js getsdo i have to base64 encode it or what
fails too
or maybe i should drop next/image for this?
now that i try
<img i am getting this if (authenticated) {
authData = await e
.select(e.Post, (post) => ({
name: true,
photoUrl: true,
filter: e.op(post.created_by, "?=", e.global.current_user),
}))
.run(client)
const r2Client = new CloudflareR2Client({
// Cloudflare AWS Credentials
accessKeyId: "",
secretAccessKey:
"",
// Cloudflare Account ID
accountId: "",
// Cloudflare Bucket name
bucket: "",
})
imageBlob = await r2Client.get("github-profile")
imageUrl = URL.createObjectURL(imageBlob)on this code
import e from "@/dbschema/edgeql-js"
import { auth } from "@/edgedb-next-client"
import { CloudflareR2Client } from "cloudflare-r2-edge"
import Image from "next/image"
export default async function Profile(props: any) {
let session = auth.getSession()
const client = session.client
const authenticated = await session.isSignedIn()
let authData
let publicData
let imageBlob
let imageUrl
if (authenticated) {
authData = await e
.select(e.Post, (post) => ({
name: true,
photoUrl: true,
filter: e.op(post.created_by, "?=", e.global.current_user),
}))
.run(client)
const r2Client = new CloudflareR2Client({
// Cloudflare AWS Credentials
accessKeyId: "",
secretAccessKey:
"",
// Cloudflare Account ID
accountId: "",
// Cloudflare Bucket name
bucket: "",
})
imageBlob = await r2Client.get("github-profile")
imageUrl = URL.createObjectURL(imageBlob)
// imageUrl = blobToBase64(imageBlob)
} else {
publicData = await e
.select(e.Post, (post) => ({
name: true,
}))
.run(client)
}
return (
<>
{authData && imageBlob && (
<header className="flex justify-between items-center pb-4">
<div>Authenticated data:</div>
{JSON.stringify(authData)}
<img src={imageUrl} />
{/* <Image
src={imageUrl}
width={500}
height={500}
alt="Picture of the author"
unoptimized
/> */}
</header>
)}
{publicData && (
<header className="flex justify-between items-center pb-4">
<div>Public data:</div>
{JSON.stringify(publicData)}
</header>
)}
</>
)
}
function blobToBase64(blob: any) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = function () {
const dataUrl = reader.result
const base64EncodedString = dataUrl.split(",")[1] // Extract base64 part from the Data URL
resolve(base64EncodedString)
}
reader.onerror = function () {
reject(new Error("Error converting blob to base64"))
}
reader.readAsDataURL(blob)
})
}full code
its like it doesn't want me to await inside RSC?
its async though
yea why can i not do await in rsc
its async
is err
@Chinese softshell turtle now that i try `<img` i am getting this
it could be that nextjs's simulated edge environment doesnt have the
File class https://github.com/maccman/cloudflare-r2-edge/blob/master/src/index.ts#L77Chinese softshell turtleOP
mm
is there another way to work around it
wait are you using edge runtime here?
Chinese softshell turtleOP
i dont mind forking the repo
i just am doing
bun dev locallynot sure about whats happening
but like is there any
export const runtimeChinese softshell turtleOP
not in my code
ok then its not that
Chinese softshell turtleOP
is my code
i have an image stored in cloudflare
its a blob
actually i can store the blob in db
and have the the next.js get image from db
this should avoid this File business
but in what format should i store
so next is happy
i get a Blob
whatever that means
from r2
my db is postgres
@Chinese softshell turtle js
export default async function Profile(props: any) {
let session = auth.getSession()
const client = session.client
const authenticated = await session.isSignedIn()
let authData
let publicData
let imageBlob
if (authenticated) {
authData = await e
.select(e.Post, (post) => ({
name: true,
photoUrl: true,
filter: e.op(post.created_by, "?=", e.global.current_user),
}))
.run(client)
const r2Client = new CloudflareR2Client({
// Cloudflare AWS Credentials
accessKeyId: "",
secretAccessKey:
"",
// Cloudflare Account ID
accountId: "",
// Cloudflare Bucket name
bucket: "",
})
imageBlob = await r2Client.get("github-profile")
console.log(imageBlob, "img blob")
} else {
publicData = await e
.select(e.Post, (post) => ({
name: true,
}))
.run(client)
}
return (
<>
{authData && imageBlob && (
<header className="flex justify-between items-center pb-4">
<div>Authenticated data:</div>
{JSON.stringify(authData)}
<Image
src={imageBlob}
width={500}
height={500}
alt="Picture of the author"
unoptimized
/>
</header>
)}
have above code
you cannot(*) fetch an image and render it in an <img> (or next/image for that matter) like that because <img> is fundamentally client side fetching. you give it an URL, it fetches the image on that URL in the client side, separate from the page.
so instead of fetching the file directly, you should instead generate a URL from which the browser can use to fetch the image. then use that generated URL as the
(*) technically you can, if you convert the image to base64 and render the <img> with the base64. I wouldn't recommend that though, it is not optimised.
so instead of fetching the file directly, you should instead generate a URL from which the browser can use to fetch the image. then use that generated URL as the
src.(*) technically you can, if you convert the image to base64 and render the <img> with the base64. I wouldn't recommend that though, it is not optimised.
Answer
Chinese softshell turtleOP
what is a good way to do this
i have image in r2
its like hash table
@Chinese softshell turtle what is a good way to do this
reread my message
Chinese softshell turtleOP
s3
@joulev you cannot(\*) fetch an image and render it in an <img> (or next/image for that matter) like that because <img> is fundamentally client side fetching. you give it an URL, it fetches the image on that URL _in the client side_, separate from the page.
so instead of fetching the file directly, you should instead generate a URL from which the browser can use to fetch the image. then use that generated URL as the `src`.
(\*) technically you can, if you convert the image to base64 and render the <img> with the base64. I wouldn't recommend that though, it is not optimised.
yeah thats the true solution, i just wanted to work out the error from the lib
Chinese softshell turtleOP
i see
i agree with what joulev said, but i will add if every asset can be public you can skip the sign url step and just make bucket public
if the bucket is already public then simply provide the public URL to next/image or <img>. if the bucket is private then generate a signed URL, then use that URL for next/image or <img>
if you want to use the blob pattern, you still need an URL. then on the client side, fetch that URL manually, convert the body to blob, then you can use that blob for next/image and <img>. it has to be a client side blob, not a server side blob
Chinese softshell turtleOP
I have a signed url
https://kuskus.e1a1737083ffd849ad2638b7e6069dec.r2.cloudflarestorage.com/github-profile?X-Amz-Expires=3600&X-Amz-Date=20240501T150941Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=4b9db796d0eecc94ddc55e4681d21b0b%2F20240501%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=accept-encoding%3Bhost&X-Amz-Signature=379f324c8c9d25897286c136b774782298cf9c1981fcd62a76fec807eee3b43ahowever its not public
even though it should be in theory
not sure what to do
thats the only options i have
hmm you have a domain then it should already be public
you can try it too
i think you won't have access
that error is because you must not have done signing correctly
no, this link as you said doesn't work. a link that works will start with
images.kuskus.appbut i tried on your custom domain https://images.kuskus.com/github-profile, and it seems kinda broken?
Chinese softshell turtleOP
yep
seems to fail
is package i am using
used this code to upload the image as buffer
its here though
yeah then just
<Image src="https://images.kuskus.app/github-profile" /> why notChinese softshell turtleOP
trying to resolve this now
remotePatterns i think i needthis i guess
or maybe it can just be
domainsalthough its 2022 answer
yea that fails even on restart
there is this too i guess
but thats bit insecure
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'kuskus.app',
},
],
},
}
module.exports = nextConfigwhat i have now
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
domains: ['images.kuskus.app']
}
}
module.exports = nextConfigok trying this
neat, it worked
ok thank you all ❤️
Chinese softshell turtleOP
not sure if there is something like
/solved or?p.s. @riský https://github.com/RiskyMH/EmailThing cool repo
yay thanks
@Chinese softshell turtle not sure if there is something like `/solved` or?
right click on message -> apps -> mark as solved