Optimize safe url generation for og images
This commit is contained in:
parent
af672dfcf4
commit
1994f3bfba
@ -3,7 +3,7 @@
|
|||||||
import { Photo } from '@/photo';
|
import { Photo } from '@/photo';
|
||||||
import { NextImageSize } from '@/platforms/next-image';
|
import { NextImageSize } from '@/platforms/next-image';
|
||||||
import { IS_PREVIEW } from '@/app/config';
|
import { IS_PREVIEW } from '@/app/config';
|
||||||
import { getOptimizedUrlsForPhotos } from '@/photo/storage';
|
import { getDataUrlsForPhotos } from '@/photo/storage';
|
||||||
|
|
||||||
export default async function ImagePhotoGrid({
|
export default async function ImagePhotoGrid({
|
||||||
photos,
|
photos,
|
||||||
@ -52,7 +52,7 @@ export default async function ImagePhotoGrid({
|
|||||||
const cellHeight= height / rows -
|
const cellHeight= height / rows -
|
||||||
(rows - 1) * gap / rows;
|
(rows - 1) * gap / rows;
|
||||||
|
|
||||||
const photoUrls = await getOptimizedUrlsForPhotos(
|
const photoUrls = await getDataUrlsForPhotos(
|
||||||
photos,
|
photos,
|
||||||
optimizedSuffix,
|
optimizedSuffix,
|
||||||
nextImageWidth,
|
nextImageWidth,
|
||||||
@ -60,7 +60,7 @@ export default async function ImagePhotoGrid({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const renderPhoto = (
|
const renderPhoto = (
|
||||||
{ id, url }: typeof photoUrls[number],
|
{ id, urlData }: typeof photoUrls[number],
|
||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
) =>
|
) =>
|
||||||
@ -75,7 +75,7 @@ export default async function ImagePhotoGrid({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img {...{
|
<img {...{
|
||||||
src: url,
|
src: urlData,
|
||||||
style: {
|
style: {
|
||||||
...imageStyle,
|
...imageStyle,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
uploadFileFromClient,
|
uploadFileFromClient,
|
||||||
} from '@/platforms/storage';
|
} from '@/platforms/storage';
|
||||||
import { Photo } from '..';
|
import { Photo } from '..';
|
||||||
|
import { fetchBase64ImageFromUrl } from '@/utility/image';
|
||||||
|
|
||||||
const PREFIX_PHOTO = 'photo';
|
const PREFIX_PHOTO = 'photo';
|
||||||
const PREFIX_UPLOAD = 'upload';
|
const PREFIX_UPLOAD = 'upload';
|
||||||
@ -157,39 +158,35 @@ export const getStorageUrlsForPhoto = async ({ url }: Photo) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getOptimizedUrlsForPhotos = async (
|
export const getDataUrlsForPhotos = async (
|
||||||
photos: Photo[],
|
photos: Photo[],
|
||||||
optimizedSuffix: OptimizedSuffix,
|
optimizedSuffix: OptimizedSuffix,
|
||||||
nextImageWidth: NextImageSize,
|
nextImageWidth: NextImageSize,
|
||||||
addBypassSecret: boolean,
|
addBypassSecret: boolean,
|
||||||
) =>
|
) =>
|
||||||
Promise.all(photos
|
Promise.all(photos
|
||||||
.map(async({ id, url: _url }) => {
|
.map(async({ id, url }) => {
|
||||||
// Check for optimized image first
|
// Check for optimized image first
|
||||||
const optimizedUrl =await getSignedUrlForUrl(
|
const optimizedUrl =await getSignedUrlForUrl(
|
||||||
getOptimizedPhotoUrlForSuffix(_url, optimizedSuffix),
|
getOptimizedPhotoUrlForSuffix(url, optimizedSuffix),
|
||||||
'GET',
|
'GET',
|
||||||
);
|
);
|
||||||
const optimizedUrlExists = await fetch(optimizedUrl)
|
const optimizedUrlData = await fetchBase64ImageFromUrl(optimizedUrl);
|
||||||
.then(res => res.ok)
|
|
||||||
.catch(() => false);
|
|
||||||
|
|
||||||
if (optimizedUrlExists) {
|
if (optimizedUrlData) {
|
||||||
return { id, url: optimizedUrl };
|
return { id, urlData: optimizedUrlData };
|
||||||
} else {
|
} else {
|
||||||
// Fall back on `next/image` if optimized image is not available
|
// Fall back on `next/image` if optimized image is not available
|
||||||
const nextImageUrl = getOptimizedPhotoUrl({
|
const nextImageUrl = getOptimizedPhotoUrl({
|
||||||
imageUrl: _url,
|
imageUrl: url,
|
||||||
size: nextImageWidth,
|
size: nextImageWidth,
|
||||||
addBypassSecret,
|
addBypassSecret,
|
||||||
});
|
});
|
||||||
const nextImageUrlExists = await fetch(nextImageUrl)
|
const nextImageUrlData = await fetchBase64ImageFromUrl(nextImageUrl);
|
||||||
.then(res => res.ok)
|
return { id, urlData: nextImageUrlData };
|
||||||
.catch(() => false);
|
|
||||||
return { id, url: nextImageUrlExists ? nextImageUrl : undefined };
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.then(urls =>(urls.every(url => Boolean(url))
|
.then(urls =>(urls.every(({ urlData }) => Boolean(urlData))
|
||||||
? urls
|
? urls
|
||||||
// If any url is defined, return an empty array
|
// If any url is undefined, return an empty array
|
||||||
: []) as { id: string, url: string }[]);
|
: []) as { id: string, urlData: string }[]);
|
||||||
|
|||||||
@ -1,15 +1,24 @@
|
|||||||
|
import { getFileNamePartsFromStorageUrl } from '@/platforms/storage';
|
||||||
|
|
||||||
export const removeBase64Prefix = (base64: string) => {
|
export const removeBase64Prefix = (base64: string) => {
|
||||||
return base64.match(/^data:image\/[a-z]{3,4};base64,(.+)$/)?.[1] ?? base64;
|
return base64.match(/^data:image\/[a-z]{3,4};base64,(.+)$/)?.[1] ?? base64;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchBase64ImageFromUrl = (
|
export const fetchBase64ImageFromUrl = async (
|
||||||
url: string,
|
url: string,
|
||||||
contentType?: string,
|
|
||||||
fetchOptions?: RequestInit,
|
fetchOptions?: RequestInit,
|
||||||
) =>
|
) => {
|
||||||
fetch(url, fetchOptions)
|
const { fileExtension } = getFileNamePartsFromStorageUrl(url);
|
||||||
|
const contentType = fileExtension === 'png' ? 'image/png' : 'image/jpeg';
|
||||||
|
return fetch(url, fetchOptions)
|
||||||
.then(async response => {
|
.then(async response => {
|
||||||
const blob = await response.arrayBuffer();
|
if (response.ok) {
|
||||||
// eslint-disable-next-line max-len
|
const blob = await response.arrayBuffer();
|
||||||
return `data:${contentType ?? response.headers.get('content-type')};base64,${Buffer.from(blob).toString('base64')}`;
|
// eslint-disable-next-line max-len
|
||||||
});
|
return `data:${contentType};base64,${Buffer.from(blob).toString('base64')}`;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => undefined);
|
||||||
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user