Skip to content

Instantly share code, notes, and snippets.

@DanielPantle
Last active January 17, 2024 13:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DanielPantle/aed00cc00823e49d57cd00215e96cc36 to your computer and use it in GitHub Desktop.
Save DanielPantle/aed00cc00823e49d57cd00215e96cc36 to your computer and use it in GitHub Desktop.
Next.js ImageLoader for Strapi
// reads the breakpoints from strapi config and generates strapi-breakpoints.json
const fs = require('fs');
const strapiPluginsConfig = require('../../../../backend/config/plugins.ts');
const dir = './src/data';
const preBuildStrapiBreakpoints = async () => {
const strapiBreakpoints = strapiPluginsConfig().upload.config.breakpoints;
var breakpoints = [];
for (var breakpoint in strapiBreakpoints) {
breakpoints.push({
breakpoint: breakpoint,
width: strapiBreakpoints[breakpoint],
});
}
breakpoints.sort((a, b) => a.width - b.width);
fs.writeFileSync('src/data/strapiBreakpoints.json', JSON.stringify(breakpoints));
};
preBuildStrapiBreakpoints();
// generated by build-strapi-breakpoints.js, but can also be used static
[{"breakpoint":"xs","width":64},{"breakpoint":"s","width":500},{"breakpoint":"m","width":750},{"breakpoint":"l","width":1000},{"breakpoint":"xl","width":1920}]
{
"image": {
"width": 3672,
"height": 4896,
"formats": {
"l": {
"url": "/uploads/l_Image_4bde836c29.JPG",
...
},
"m": {
"url": "/uploads/m_Image_4bde836c29.JPG",
...
},
"s": {
"url": "/uploads/s_Image_4bde836c29.JPG",
...
},
"xl": {
"url": "/uploads/xl_Image_4bde836c29.JPG",
...
},
"thumbnail": {
"url": "/uploads/thumbnail_Image_4bde836c29.JPG",
...
}
},
"hash": "Image_4bde836c29",
"mime": "image/jpeg",
"url": "/uploads/Image_4bde836c29.JPG",
...
}
}
// custom Next.js component for displaying Strapi images with a custom loader
// NEXT_PUBLIC_BACKEND_URL_IMAGES needs to be set in the .env file, e.g.: NEXT_PUBLIC_BACKEND_URL_IMAGES=http://localhost:1337
// For placeholders to work, install strapi-plugin-placeholder
'use client';
import { default as NextImage, ImageLoader, ImageProps } from 'next/image';
import _strapiBreakpoints from '/src/data/preBuild/strapiBreakpoints.json';
export interface IStrapiImage {
alternativeText?: string;
caption?: string;
width: number;
height: number;
formats?: {
[key: string]: IImageFormat;
};
url: string;
placeholder?: string;
}
interface IImageFormat {
url: string;
}
export type IStrapiImageComponent = Partial<ImageProps> & {
image: IStrapiImage;
};
interface IStrapiBreakpoint {
breakpoint: string;
width: number;
}
const StrapiImage: React.FC<IStrapiImageComponent> = ({ image, ...rest }) => {
const strapiBreakpoints = _strapiBreakpoints as IStrapiBreakpoint[];
const imageLoader: ImageLoader = ({ width }) => {
const closestBreakpoint = strapiBreakpoints.find((b) => width < b.width);
const url = closestBreakpoint && image.formats && closestBreakpoint.breakpoint in image.formats
? image.formats[closestBreakpoint.breakpoint].url
: image.url;
return process.env.NEXT_PUBLIC_BACKEND_URL_IMAGES + url;
};
return (
<NextImage
loader={imageLoader}
blurDataURL={image.placeholder}
placeholder={image.placeholder ? 'blur' : 'empty'}
src={image.url}
alt={image.alternativeText || image.caption || ''}
{...rest}
/>
);
};
export default StrapiImage;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment