Skip to content

Commit a81c89b

Browse files
authored
Image blur server (#589)
* remove useclient on datafetch * improve logging
1 parent c7c1a13 commit a81c89b

3 files changed

Lines changed: 35 additions & 29 deletions

File tree

‎components/cover-image.tsx‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1-
"use client";
21
import { CloudinaryAsset } from "@/sanity.types";
32
import CloudinaryImage from "@/components/cloudinary-image";
43
import { getCldImageUrl } from "next-cloudinary";
5-
import { useEffect, useState } from "react";
64

75
interface CoverImageProps {
86
image: CloudinaryAsset | null | undefined;
97
priority?: boolean;
108
className?: string;
119
width?: number;
1210
height?: number;
13-
quality?: number;
11+
quality?: number | `${number}`
1412
}
1513

16-
export default function CoverImage(props: CoverImageProps) {
14+
export default async function CoverImage(props: CoverImageProps) {
1715
const {
1816
image: originalImage,
1917
priority,
@@ -22,12 +20,6 @@ export default function CoverImage(props: CoverImageProps) {
2220
height,
2321
quality,
2422
} = props;
25-
const [dataUrl, setDataUrl] = useState("");
26-
27-
useEffect(() => {
28-
if (!originalImage?.public_id) return;
29-
getImageUrl(originalImage?.public_id);
30-
}, [originalImage?.public_id]);
3123

3224
const getImageUrl = async (src: string) => {
3325
const imageUrl = getCldImageUrl({
@@ -38,25 +30,23 @@ export default function CoverImage(props: CoverImageProps) {
3830
const arrayBuffer = await response.arrayBuffer();
3931
const buffer = Buffer.from(arrayBuffer);
4032
const base64 = buffer.toString("base64");
41-
setDataUrl(`data:${response.type};base64,${base64}`);
33+
return `data:${response.type};base64,${base64}`
4234
};
4335

4436
let image;
45-
if (originalImage?.public_id && dataUrl) {
37+
if (originalImage?.public_id) {
4638
image = (
4739
<CloudinaryImage
4840
className={className || "w-full h-auto aspect-video"}
4941
width={width || 1920}
5042
height={height || 1080}
5143
priority={priority}
5244
quality={quality || "auto"}
53-
sizes="(max-width: 768px) 100vw,
54-
(max-width: 1200px) 50vw,
55-
33vw"
45+
sizes="(max-width: 768px) 100vw,(max-width: 1200px) 50vw, 33vw"
5646
alt={originalImage?.context?.custom?.alt || ""}
5747
src={originalImage?.public_id}
5848
placeholder="blur"
59-
blurDataURL={dataUrl}
49+
blurDataURL={await getImageUrl(originalImage.public_id)}
6050
config={{
6151
url: {
6252
secureDistribution: "media.codingcat.dev",

‎next.config.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ module.exports = {
44
// Used to guard against accidentally leaking SANITY_API_READ_TOKEN to the browser
55
taint: true,
66
},
7+
compiler: {
8+
removeConsole: process.env.NODE_ENV === 'production' ? {
9+
exclude: ['error'],
10+
} : false,
11+
},
712
};
813

914

‎sanity/lib/fetch.ts‎

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import type { ClientPerspective, QueryParams } from "next-sanity";
1+
import type { ClientPerspective, FilteredResponseQueryOptions, QueryParams } from "next-sanity";
22
import { draftMode } from "next/headers";
33

44
import { client } from "@/sanity/lib/client";
55
import { token } from "@/sanity/lib/token";
6-
console.debug('env', process.env.VERCEL_ENV)
76
/**
87
* Used to fetch data in Server Components, it has built in support for handling Draft Mode and perspectives.
98
* When using the "published" perspective then time-based revalidation is used, set to match the time-to-live on Sanity's API CDN (60 seconds)
@@ -26,8 +25,19 @@ export async function sanityFetch<QueryResponse>({
2625
perspective?: Omit<ClientPerspective, "raw">;
2726
stega?: boolean;
2827
}) {
28+
29+
let config: FilteredResponseQueryOptions = {
30+
stega,
31+
perspective: "published",
32+
// The `published` perspective is available on the API CDN
33+
useCdn: true,
34+
// Only enable Stega in production if it's a Vercel Preview Deployment, as the Vercel Toolbar supports Visual Editing
35+
// When using the `published` perspective we use time-based revalidation to match the time-to-live on Sanity's API CDN (60 seconds)
36+
next: { revalidate: 60 },
37+
}
38+
2939
if (perspective === "previewDrafts") {
30-
return client.fetch<QueryResponse>(query, params, {
40+
config = {
3141
stega,
3242
perspective: "previewDrafts",
3343
// The token is required to fetch draft content
@@ -36,15 +46,16 @@ export async function sanityFetch<QueryResponse>({
3646
useCdn: false,
3747
// And we can't cache the responses as it would slow down the live preview experience
3848
next: { revalidate: 0 },
39-
});
49+
}
4050
}
41-
return client.fetch<QueryResponse>(query, params, {
42-
stega,
43-
perspective: "published",
44-
// The `published` perspective is available on the API CDN
45-
useCdn: true,
46-
// Only enable Stega in production if it's a Vercel Preview Deployment, as the Vercel Toolbar supports Visual Editing
47-
// When using the `published` perspective we use time-based revalidation to match the time-to-live on Sanity's API CDN (60 seconds)
48-
next: { revalidate: 60 },
49-
});
51+
52+
53+
console.debug({
54+
// replace "\n" with carriage return
55+
query: query.replace(/\n/g, ""),
56+
params,
57+
config
58+
})
59+
60+
return client.fetch<QueryResponse>(query, params, config);
5061
}

0 commit comments

Comments
 (0)