lorenzodejong / next-sanity-image Goto Github PK
View Code? Open in Web Editor NEWUtility for using responsive images hosted on the Sanity.io CDN with the Next.js image component.
License: MIT License
Utility for using responsive images hosted on the Sanity.io CDN with the Next.js image component.
License: MIT License
Hello, thanks for your work, but I noticed when the "image" object is empty javascript crashes.
Eg. I have a Hero component that it should have or not the image. How can I handle it? Thanks.
👋
The fix for Next 12 does not remove all the warnings. If you use image transformations, you'll still see a lot of warnings because the imageBuilder returns a w
instead of a width
parameter.
We've discussed this with Sanity, and they suggest to manually add the width as a workaround that satisfies both Next.js and doesn't effect the image from Sanity.
Hoping you or someone else might be able to help me better understand the expected behavior when using next-sanity-image on an image block from a portable text field....to determine if my issues are resolvable.
For some reason, no matter what I do, I have images being served from Sanity's CDN. Even when I explicitly set useCdn to false
. The lqip feature and blur up is also not working.
I use next-sanity-image as following in a component called PortableTextImage.js
import sanityClient from '@lib/sanityClient';
import Image from 'next/image';
import { useNextSanityImage } from 'next-sanity-image';
const PortableTextImage = (props) => {
const configuredSanityClient = sanityClient;
const imageProps = useNextSanityImage(configuredSanityClient, props);
const caption = props.description || (props.asset && props.asset.description) || null;
return (
<div className="md:-mx-16 lg:-mx-32">
<Image
{...imageProps}
className="w-full"
sizes="(max-width: 800px) 100vw, 1200px"
blurDataURL="props.lqip"
placeholder="blur"
// render an alt tag conditionally
alt={props.alt || props.description || props.asset.alt || props.asset.title || props.asset.description || 'Sorry, alt text for this image is missing.'}
/>
{caption ? (
<div className="text-sm lg:text-lg font-serif italic -mt-4 text-stone-500 relative md:mx-16 lg:mx-32">{caption}</div>
) : null}
</div>
);
};
export default PortableTextImage;
My image renders as follows...
...and again, no lqip ...I am throttling the connection to confirm. I took this from development but it's the same in production.
Other relevant pieces of this puzzle might include my use of react-portable-text, used as follows to pass / parse the field and use my PortableTextImage component.
{pageData.body ? (
<PortableText
content={pageData.body}
projectId={process.env.NEXT_PUBLIC_SANITY_PROJECT_ID}
dataset={process.env.NEXT_PUBLIC_SANITY_DATASET}
serializers={{
image: (props) => {
return <PortableTextImage {...props} />;
},
}}
/>
) : null}
Since you just bumped the version I thought I should dbl check that I am using it correctly and have not stumbled on to a bug.
Hi!
I have a case where the sanity image asset might be undefined. I tried to get around this by setting null
conditionally:
const imgProps = useNextSanityImage(sanityClient, image ?? null)
But I then get the following TS error: Type 'null' is not assignable to type 'SanityImageSource'
.
Is there any workaround for this case?
Update to @sanity/client
v3.x, versus the current v2.11.0
Heya - I've just upgraded to Next 13, all seems good except for images that were previously using layout=fill
which has been deprecated for the boolean fill property.
Setting fill
to true results in an error: "Image ... has both "width" and "fill" properties. Only one should be used." Could next-sanity-image treat fill
the same as layout=fill
and omit the width and height properties please? Thanks!
Has anyone seen a spike in sanity bandwidth after installing and implementing this package. I have installed this package last year around September and seen significant upward trend in bandwidth of Sanity.
Just want to understand if this package is causing this issue.
If it's possible may we have a support for next 13?
When an image requested from Sanity is an svg (eg: 600 x 600) and for placeholder svg is called as "blur" and "w=64" but since sanity does not process SVG, it downloads the whole image and causes "Defer Offscreen Image" warning on Lighthouse.
Can this plugin automatically skip placeholder if the format is in SVG even if blurUp is enabled?
Using a very basic configuration, I get an exception configuration must contain projectId
. see below for usage. absolutely certain that the instantiated sanityClient
is working since all my groq queries are fine. Is there anything that I might be missing?
sanity/client 2.1.4
next 10.0.5
// Image wrapper
import Img from 'next/image';
import {useNextSanityImage} from 'next-sanity-image';
import sanityClient from '@/services/sanityClient';
const Image = ({src}) => {
const imageProps = useNextSanityImage(sanityClient, src);
return <Img {...imageProps} />;
};
export default Image;
Did an accidental debug statement slip into the [email protected]
codebase?
I've reinstalled all our modules to exclude any console.log()
statements written in node_modules/*.*
.
Is there a way to download the static image and bundle it into the build assets? I would like to bundle my static assets in with my website when I build it and deploy to a static host (s3).
Currently I can reference images by the Sanity CDN but I'd rather these are on my own URL rather than the Sanity CDN.
It seems like the loader doesn't implement a caching behaviour like the default loader of Nextjs.
https://nextjs.org/docs/api-reference/next/image#caching-behavior
Do you consider adding something like that in the future? It would be great if users wouldn't fetch images directly from the Sanity CDN, but from the domain of my website.
I'm getting the following error when we pass image.alt
but not image.asset
. This plugin should send appropriate error when image.asset
is not found.
In my code, I cannot do the following because hooks cannot call conditionally.
// This won't work
// Not able to call hooks conditionally.
if (!image.asset) {
return null;
}
const imageProps = useNextSanityImage(client, image, {
imageBuilder: CustomImageBuilder
});
Setting .height(...)
in options.imageBuilder
results in "stretched" images, even with position: relative
set to a parent element, likely due to the <Image/>
component from next/image
not being able to handle explicit heights.
FYI: Use in conjunction with .width(...)
(e.g. .width(200).height(200)
) does get expected results — a 200x200 px image.
Hi, thank you for creating this awesome tool, it saved my time.
According to the return type is UseNextSanityImageProps
, I'd wonder if it is possible to run the main function inside getStaticProps
? If that's possible, we won't need to include SanityClient
into our front-end bundle, we can get the imageProps
within build time or server side. Thanks.
05:15:03.422 | npm ERR! Found: @sanity/[email protected]
05:15:03.423 | npm ERR! node_modules/@sanity/client
05:15:03.423 | npm ERR! @sanity/client@"^6.1.0" from the root project
05:15:03.423 | npm ERR! @sanity/client@"^6.0.0" from @sanity/[email protected]
05:15:03.423 | npm ERR! node_modules/@sanity/preview-kit
05:15:03.424 | npm ERR! @sanity/preview-kit@"^1.5.0" from [email protected]
05:15:03.424 | npm ERR! node_modules/next-sanity
05:15:03.424 | npm ERR! next-sanity@"^4.3.2" from the root project
05:15:03.424 | npm ERR! 1 more (next-sanity)
05:15:03.424 | npm ERR!
05:15:03.424 | npm ERR! Could not resolve dependency:
05:15:03.424 | npm ERR! peer @sanity/client@"^5.0.0" from [email protected]
05:15:03.425 | npm ERR! node_modules/next-sanity-image
05:15:03.425 | npm ERR! next-sanity-image@"^6.0.0" from the root project
05:15:03.425 | npm ERR!
05:15:03.426 | npm ERR! Conflicting peer dependency: @sanity/[email protected]
05:15:03.426 | npm ERR! node_modules/@sanity/client
05:15:03.426 | npm ERR! peer @sanity/client@"^5.0.0" from [email protected]
05:15:03.426 | npm ERR! node_modules/next-sanity-image
05:15:03.426 | npm ERR! next-sanity-image@"^6.0.0" from the root project
After trying for a long time to make the crop and hotspot work, I finally landed on a solution.
This ticket aims to help others facing the same issue, but I also believe that the docs should be updated accordingly.
For the hotspot I managed to get it working using the solution by @danieljb #32 (comment)
Hi @zRelux, as far as I understand this library does not respect Sanity’s hotspot feature.
A quick workaround is to set
objectPosition
calculated from Sanity’s image data:import Img from "next/image"; import { useNextSanityImage } from "next-sanity-image"; // untested function ImageComponent({ image }) { /* { "_type": "image", "asset": { "_ref": "image-[…]-jpg", "_type": "reference" }, "crop": { "_type": "sanity.imageCrop", "bottom": 0, "left": 0, "right": 0, "top": 0 }, "hotspot": { "_type": "sanity.imageHotspot", "height": 0.07233187772925773, "width": 0.07423580786026142, "x": 0.5611353711790394, "y": 0.7135109170305682 } } */ const imageProps = useNextSanityImage(client, image); const attributes = {}; if (image.hotspot?.x && image.hotspot?.y) { const { x, y } = image.hotspot; attributes.objectPosition = `${x * 100}% ${y * 100}%`; } return ( <Image {...imageProps} {...attributes} /> ); }This only works in certain
layout
andobjectFit
combinations and depends on CSS styling (e.g. whether the image component is constraint to an aspect ratio). Note, this does not take the hotspot ellipse (width
andheight
attributes) into account.I tried to use a custom url builder to apply image transformations as described in the README but that did not work without manually passing in
fit=crop&crop=focalpoint&fp-x=${image.hotspot.x}&fp-y=${image.hotspot.y}
and disregards the hotspot ellipse, too. There also seems to be a bug #24 pending in Sanity’s image-url.
And for the crop, I got it working by changing the default fit
behavior from the lib to 'crop'
:
const imageProps = useNextSanityImage(client, image, {
imageBuilder: (imageUrlBuilder) => imageUrlBuilder.fit('crop'),
})
Based on this solution, I created this generic Image component that is working perfectly for me so far:
'use client' // Remove this line if you are not using the experimental 'app' folder from Next 13
import { useNextSanityImage } from 'next-sanity-image'
import Img from 'next/image'
import { SanityImageObject } from '@sanity/image-url/lib/types/types'
import client from 'client'
type Props = {
image?: SanityImageObject & { alt?: string }
className?: string
}
const Image = ({ image, className }: Props) => {
const imageProps = useNextSanityImage(client, image, {
imageBuilder: (imageUrlBuilder) => imageUrlBuilder.fit('crop'),
})
if (!image?.asset) return <></>
let objectPosition = undefined
if (image.hotspot?.x && image.hotspot?.y) {
const { x, y } = image.hotspot
objectPosition = `${x * 100}% ${y * 100}%`
}
return (
<Img
{...imageProps}
style={{ objectFit: 'cover', objectPosition: objectPosition }}
alt={image.alt ?? ''}
className={className}
sizes="(max-width: 800px) 100vw, 800px"
/>
)
}
export default Image
Hopefully this will help others :)
Hi there!
It seems like something with Next/Image
's complex types is causing some trouble with the next-sanity-image
library (screenshot below.)
It seems like no matter what useNextSanityImage
returns, next/image
gets mad that src is a string instead of a StaticImport. Any typescript guidance would be appreciated!
import { ImageUrlBuilder } from '@sanity/image-url/lib/types/builder'
import { SanityImageSource } from '@sanity/image-url/lib/types/types'
import { useNextSanityImage, UseNextSanityImageBuilderOptions } from 'next-sanity-image'
import Image from 'next/image'
import React, { FunctionComponent } from 'react'
import configuredSanityClient from './sanity'
// This custom url builder insists on using the images' width as the max width instead of scaling the image up.
// It's likely that we'll need to use different imgBuilders with different behaviors for different Next/Image layout types
const customImageURLBuilder = (
imageUrlBuilder: ImageUrlBuilder,
options: UseNextSanityImageBuilderOptions,
) => {
return imageUrlBuilder
.width(
options.width && options.width != 0
? Math.min(options.originalImageDimensions.width, options.width)
: options.originalImageDimensions.width,
)
.auto('format')
}
const NextSanityImageWithCustomBuilder = (image: SanityImageSource) =>
useNextSanityImage(configuredSanityClient, image, {
imageBuilder: customImageURLBuilder as any,
enableBlurUp: false
})
type NextSanityImageProps = {
alt?: string,
image: SanityImageSource,
layout?: 'fill' | 'fixed' | 'intrinsic' | 'responsive' | undefined
}
const NextSanityImage: FunctionComponent<NextSanityImageProps> = ({
image,
layout = 'intrinsic',
alt,
...rest
}) => {
const imageProps = NextSanityImageWithCustomBuilder(image)
if (layout === 'fill') {
return (
<Image
{...imageProps}
data-gumlet="false"
layout="fill"
alt={alt}
{...rest}
width={undefined}
height={undefined}
/>
)
} else {
return (
<Image alt={alt} {...imageProps} data-gumlet="false" layout={layout} {...rest} />
)
}
}
export default NextSanityImage
Hi,
Previously I have been using the Sanity UrlBuilder and filtering empty fields from there:
import imageUrlBuilder from '@sanity/image-url'
import sanityClient from '../client'
import BlockContent from '@sanity/block-content-to-react'
export default function Blurb({ blurb }) {
const builder = imageUrlBuilder(sanityClient)
function urlFor(source) {
if (!source) {
return
} else {
return builder.image(source)
}
}
return (
<>
<img src={urlFor(blurb.mainImage)} />
<h1>{blurb.heading}</h1>
<div><BlockContent blocks={blurb.body} /></div>
</>
)
}
However I'm having a lot of trouble working out how to do this using the next-sanity plugin. Sorry for this, I am quite new.
I was wondering if this library does take care of focal points
Hi!
Ran into an issue when using this library with the type definition for placeholder
which doesn't match up with the one in next/image
. According to their doc it isn't a string, but instead 'blur' | 'empty' | undefined
.
I put in a workaround with a typeguard in my project, but i figured i'd let you know.
Here is the next docs for this prop
Keep up the good work ✨
I am trying to render block content via Next.js. block-content-to-react
works wonderfully, but unfortunately uses standard HTML <img>
tags. I am not too familiar with BlockContent serializers. I am wondering if this library exposes a default serializer you can use, or if there is example code available with how to write a custom serializer with this library.
Peer deps saying no.
is it on the plans maybe?
Thanks
Hi, thanks for a nice library!
Today I've ran into a problem though - my client uploaded PNG to Sanity and the Next.js Typescript app failed with the following error: TypeError: Cannot assign to read only property 'crop' of object '#<Object>'
.
This is the image in question that I receive from BE (and which I pass as the hook's argument):
{
_type: 'image',
asset: {
_ref: 'image-f5d4883f18beaed14143983cad78110e4e81ce93-1920x969-png',
_type: 'reference'
},
crop: {
_type: 'sanity.imageCrop',
bottom: 0,
left: 0.001763668430335097,
right: 0,
top: 0
},
hotspot: {
_type: 'sanity.imageHotspot',
height: 1,
width: 0.998236331569665,
x: 0.5008818342151675,
y: 0.5
}
}
This is how I use the hook: useNextSanityImage(sanityClient, props.image);
. When I try/catch the error, I see that the hook returns null
. Also I do not have any problem with any other image across the whole app.
"next-sanity-image": "^3.1.5"
Am I missing something obvious? Thanks in advance!
Hey, thank you for your work on this library, it makes working with Sanity assets in Next.js a breeze 😃
I'm trying building an image component, but I'm running into a TypeScript error that I'm not sure how to resolve (I'm still learning TypeScript so please bear with me).
TypeScript is yelling at me, with the error message of:
No overload matches this call.
Overload 1 of 3, '(sanityClient: SanityClientLike, image: null, options?: UseNextSanityImageOptions | undefined): null', gave the following error.
Argument of type 'SanityClient' is not assignable to parameter of type 'SanityClientLike'.
Property 'clientConfig' is missing in type 'SanityClient' but required in type 'SanityClientLike'.
Overload 2 of 3, '(sanityClient: SanityClientLike, image: SanityImageSource, options?: UseNextSanityImageOptions | undefined): UseNextSanityImageProps', gave the following error.
Argument of type 'SanityClient' is not assignable to parameter of type 'SanityClientLike'.
Overload 3 of 3, '(sanityClient: SanityClientLike, image: SanityImageSource | null, options?: UseNextSanityImageOptions | undefined): UseNextSanityImageProps | null', gave the following error.
Argument of type 'SanityClient' is not assignable to parameter of type 'SanityClientLike'.
Here's my code so far:
'use client'
import {
ImageUrlBuilder,
useNextSanityImage,
UseNextSanityImageBuilderOptions,
UseNextSanityImageProps
} from 'next-sanity-image'
import { default as NextImage } from 'next/image'
import { sanityClient } from '../../lib/sanity.client'
type ImageProps = {
image: {
asset: {
altText?: string
metadata: {
lqip: string
palette: {
dominant: {
background: string
}
}
}
}
[key: string]: any
}
priority?: boolean
[key: string]: any
}
/**
* Image component, composes NextImage
*/
const Image = ({ image, priority = false, ...rest }: ImageProps) => {
/**
* Get Sanity image props, allowing for custom imageBuilder transforms
*/
const imageProps: UseNextSanityImageProps = useNextSanityImage(
sanityClient, // ⛔️ <- Here's where TypeScript yells at me!
image,
{
imageBuilder: (
imageUrlBuilder: ImageUrlBuilder,
options: UseNextSanityImageBuilderOptions
) => {
/**
* Destructure options
*/
const {
width = undefined,
// originalImageDimensions = {},
// croppedImageDimensions = {},
quality = undefined
} = options
return imageUrlBuilder
.width(
width ||
Math.min(
options.originalImageDimensions.width,
1920
)
)
.quality(quality || 75)
.fit('clip')
}
}
)
/**
* If no image/asset props return null
*/
if (!imageProps) return null
/**
* Destructure asset props
*/
const {
asset: {
altText = '',
metadata: {
lqip = '',
palette: {
dominant: { background = '' }
}
}
}
} = image
return (
<div className='relative block h-[50vh] w-screen'>
<NextImage
src={imageProps.src}
loader={imageProps.loader}
alt={altText}
priority={priority}
fill
sizes='(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw'
placeholder='blur'
blurDataURL={lqip}
quality={90}
style={{
objectFit: 'cover',
backgroundColor: background
}}
{...rest}
/>
</div>
)
}
export default Image
And here's the file I define the Sanity Client config:
import { createClient } from 'next-sanity'
export const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!
export const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET!
export const apiVersion = process.env.NEXT_PUBLIC_SANITY_API_VERSION!
export const sanityClient = createClient({
projectId,
dataset,
apiVersion,
useCdn: false
})
Whereabouts am I going wrong here? Have I missed something kinda silly? I'm assuming it's something I've missed or typed incorrectly?
I've only been working with TypeScript for a few weeks, here's hoping someone can educate me & point me in the right direction 🤞
It's now required to use base64 image in next/future/image component for blur placeholder.
Old component still works as expected.
const imageProps = useNextSanityImage(
sanityClient,
image,
{
enableBlurUp: false,
},
);
error TS2769: No overload matches this call.
Overload 1 of 2, '(sanityClient: SanityClientLike, image: SanityImageSource | null, options?: (UseNextSanityImageOptions & { enableBlurUp?: true | undefined; }) | undefined): (Required<...> & { ...; }) | null', gave the following error.
Argument of type '{ blurUpImageWidth: number; blurUpImageQuality: number; blurUpAmount: number; } | { enableBlurUp: false; }' is not assignable to parameter of type '(UseNextSanityImageOptions & { enableBlurUp?: true | undefined; }) | undefined'.
Type '{ enableBlurUp: false; }' is not assignable to type 'UseNextSanityImageOptions & { enableBlurUp?: true | undefined; }'.
Type '{ enableBlurUp: false; }' is not assignable to type '{ enableBlurUp?: true | undefined; }'.
Types of property 'enableBlurUp' are incompatible.
Type 'false' is not assignable to type 'true | undefined'.
Overload 2 of 2, '(sanityClient: SanityClientLike, image: SanityImageSource | null, options?: (UseNextSanityImageOptions & { enableBlurUp: false; }) | undefined): (Omit<...> & { ...; }) | null', gave the following error.
Argument of type '{ blurUpImageWidth: number; blurUpImageQuality: number; blurUpAmount: number; } | { enableBlurUp: false; }' is not assignable to parameter of type '(UseNextSanityImageOptions & { enableBlurUp: false; }) | undefined'.
Type '{ blurUpImageWidth: number; blurUpImageQuality: number; blurUpAmount: number; }' is not assignable to type 'UseNextSanityImageOptions & { enableBlurUp: false; }'.
Property 'enableBlurUp' is missing in type '{ blurUpImageWidth: number; blurUpImageQuality: number; blurUpAmount: number; }' but required in type '{ enableBlurUp: false; }'.
Here are the types in the current version of the NPM package:
import { SanityClientLike, SanityImageSource } from '@sanity/image-url/lib/types/types';
import { UseNextSanityImageDimensions, UseNextSanityImageOptions, UseNextSanityImageProps } from './types';
export declare const DEFAULT_BLUR_UP_IMAGE_WIDTH = 64;
export declare const DEFAULT_BLUR_UP_IMAGE_QUALITY = 30;
export declare const DEFAULT_BLUR_UP_AMOUNT = 50;
export declare const DEFAULT_FALLBACK_IMAGE_WIDTH = 1920;
export declare const DEFAULT_FALLBACK_IMAGE_QUALITY = 75;
export declare function getImageDimensions(image: SanityImageSource): UseNextSanityImageDimensions;
export declare function useNextSanityImage(sanityClient: SanityClientLike, image: SanityImageSource | null, options?: UseNextSanityImageOptions & {
enableBlurUp?: true;
}): (Required<UseNextSanityImageProps> & {
placeholder: 'blur';
}) | null;
export declare function useNextSanityImage(sanityClient: SanityClientLike, image: SanityImageSource | null, options?: UseNextSanityImageOptions & {
enableBlurUp: false;
}): (Omit<UseNextSanityImageProps, 'blurDataURL'> & {
placeholder: 'empty';
}) | null;
I believe the issue is that enableBlurUp: false
should be enableBlurUp?: false
.
Hey, I'm having an issue I'm sure is down to me doing something wrong, but hoped someone might be able to help?
The image data appears in the tag's, and as a blurred placeholder, but ultimately doesn't load up.
Here's what is output:
<div class="image">
<span
style="
box-sizing: border-box;
display: block;
overflow: hidden;
width: initial;
height: initial;
background: none;
opacity: 1;
border: 0;
margin: 0;
padding: 0;
position: relative;
"
><span
style="
box-sizing: border-box;
display: block;
width: initial;
height: initial;
background: none;
opacity: 1;
border: 0;
margin: 0;
padding: 0;
padding-top: 81.2%;
"
></span
><img
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
decoding="async"
data-nimg="responsive"
style="
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
box-sizing: border-box;
padding: 0;
border: none;
margin: auto;
display: block;
width: 0;
height: 0;
min-width: 100%;
max-width: 100%;
min-height: 100%;
max-height: 100%;
filter: blur(20px);
background-size: cover;
background-image: url('https://cdn.sanity.io/images/vua524it/production/0ebc49d206053e55855555e84ac6440e90e9b77c-1000x812.png?w=64&blur=50&q=30&fit=clip&auto=format');
background-position: 0% 0%;
" />
<noscript>
<img
sizes="(max-width: 1280px) 100vw, 1280px"
srcset="
https://cdn.sanity.io/images/vua524it/production/0ebc49d206053e55855555e84ac6440e90e9b77c-1000x812.png?w=640&q=75&fit=clip&auto=format 640w,
https://cdn.sanity.io/images/vua524it/production/0ebc49d206053e55855555e84ac6440e90e9b77c-1000x812.png?w=750&q=75&fit=clip&auto=format 750w,
.....etc.....
"
loading="lazy"
/>
</noscript>
</span>
</div>
And here's my component:
import { useNextSanityImage } from "next-sanity-image";
import Image from "next/image";
import { sanityConfig } from "../../../lib/config";
import { Headline } from "../../elements/Headline";
import * as S from "./Italy.styles";
import { Pattern } from "./Pattern";
export function Italy({ data }) {
const imageProps = useNextSanityImage(sanityConfig, data?.image);
console.log(imageProps);
return (
<S.Italy>
<div className="content">
<Headline data={{ headline: data?.headline }} />
</div>
<div className="image">
<Image
{...imageProps}
layout="responsive"
sizes="(max-width: 1280px) 100vw, 1280px"
/>
</div>
<Pattern />
</S.Italy>
);
}
And finally, the output of the console.log(imageProps)
:
{
"src": "https://cdn.sanity.io/images/vua524it/production/0ebc49d206053e55855555e84ac6440e90e9b77c-1000x812.png?q=75&fit=clip&auto=format",
"width": 1000,
"height": 812,
"blurDataURL": "https://cdn.sanity.io/images/vua524it/production/0ebc49d206053e55855555e84ac6440e90e9b77c-1000x812.png?w=64&blur=50&q=30&fit=clip&auto=format",
"placeholder": "blur"
}
Getting the following error when using next-sanity-image
with "next": "^11.1.0",
Code:
const imgOpts = (transform) => transform.width(1920).height(1080).fit('crop');
export default function Component() {
const imageProps = useImage(data.backgroundImage, imgOpts);
return (
<Img
{...imageProps}
/>
)
}
Console:
instrument.js?ea14:109 Image with src "[sanityUrl].jpg?rect=0,137,2640,1485&w=1920&h=1080&q=80&fit=crop&auto=format&dpr=2" has a "loader" property that does not implement width. Please implement it or use the "unoptimized" property instead.
Read more: https://nextjs.org/docs/messages/next-image-missing-loader-width
at Image (webpack-internal:///./node_modules/next/dist/client/image.js:307:20)
The error also links to the following page: https://nextjs.org/docs/messages/next-image-missing-loader-width
This warning was recently added in vercel/next.js#26998
Since updating to Next 11, I am getting a Type error shown below:
Argument of type 'import("/path/to/project/node_modules/@sanity/client/sanityClient").SanityClient' is not assignable to parameter of type 'import("/path/to/project/node_modules/next-sanity-image/node_modules/@sanity/image-url/lib/types/types").SanityClient'.
Types of property 'clientConfig' are incompatible.
My code:
sanity.ts:
import sanityClient from '@sanity/client'
export default sanityClient({
projectId: 'projectId',
dataset: 'production',
useCdn: true,
})
component.ts:
...
const serializers = {
{
types: {
image: function imageSerializer(props){
const imageProps = useNextSanityImage(sanity, props.node)
return (
<div className="w-full rounded-lg">
<Image {...imageProps} sizes="(max-width: 750) 100vw, 750px" />
</div>
)
}
}
}
}
...
It seems like sanity/client and sanity-next-image are not having the same type for the sanity client object
Any help on how to fix this ?
If you have hotspots set or image is cropped using Sanity's built in tools, it's not respected with next-sanity-image. There should be a way to either automatically or via a prop use any crop or hotspots set by the Sanity user.
example schema:
import { FaRegImage } from "react-icons/fa";
export default {
name: "figure",
title: "Image",
type: "image",
options: {
hotspot: true, // if this is set to true, user can set hotspots and crop the image, so their selected preference should follow to display
metadata: ["lqip"],
},
icon: FaRegImage,
fields: [
{
name: "alt",
type: "string",
title: "Alternative text",
description: "Important for SEO and accessibility. Describe the image",
options: {
isHighlighted: true,
},
validation: (Rule) => [Rule.required().error("You need to set Alt text")],
},
],
preview: {
select: {
imageUrl: "asset.url",
title: "alt",
},
},
};
First of all, thanks a lot for this plugin. It makes things easy.
next/image
supports conversion to webp
format on supported browsers. Similarly, Sanity also supports webp
transformations. So, how can I use that feature while using your plugin? is it possible now? if yes, can you show an example? webp
on modern browsers, JPG on old/unsupported browsers.
If no, I have realized you are also planning for a v2 release. Would you consider this feature as well?
Thanks again
~Surjith
Hi, and thanks for a great work 👏
Is it possible to highlight more in the README that this library change the default layout from intrinsic
to responsive
? We find it very confusing now since the Next.js API documents intrinsic
as default and it took quite a long time before we realized that this is changed to responsive
by this library 😅
Would be awesome to get this updated to React 18!
The package is currently on ^17.0.2
and preventing us from upgrading to [email protected]
.
Hello,
I'm creating a component that may or may not receive an image from Sanity, so the image type is "string | null". However TS is not happy with it (using version 3.1.4), as I get Argument of type 'string | null' is not assignable to parameter of type 'null'. Type 'string' is not assignable to type 'null'.
when passing the image to useNextSanityImage
. It does the same if I replace string by SanityImageSource.
As the hook can handle null images, it should be ok to pass this argument, shouldn't it?
NextJS 11 released with a new burred placeholder feature. The @sanity/image-url
package already has support for blurred images, so it would be awesome to implement the feature in the next-sanity-image
package.
Links:
Currently getting Image with src "/_next/static/media/logo.215ee7a5.png" is missing "loader" prop.
How to make it compatible with already existing Next Images?
Warning:
Image with src "https://cdn.sanity.io/images/blabla-667x500.jpg?q=75&fit=clip&auto=format" and "layout='fill'" has unused properties assigned. Please remove "width" and "height".
When using the plugin like this:
{coverImage && imageUrl && (
<Image {...coverImageProps} alt={alt} layout="fill" objectFit="cover" />
)}
Would there be any interest in adding a pre-load state that uses the LQIP metadata when provided? It seems like that'd be super useful, inspired by https://www.sanity.io/plugins/gatsby-plugin-sanity-image
At the moment it appears the only values passed on to a custom imageBuilder
is width and originalImageDimensions
, but Next/Image allows for setting quality as well in a loader.
I know I'd find this valuable
Whenever I add the images
part to my next.config.js
:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
images: {
domains: ["cdn.sanity.io"],
loader: "custom",
},
};
module.exports = nextConfig;
The following message pops up:
error - Error: Image with src "[object Object]" is missing "loader" prop.
Read more: https://nextjs.org/docs/messages/next-image-missing-loader
at Image (webpack-internal:///./node_modules/next/dist/client/image.js:64:19)
}
null
Do I need some additional configuration somewhere?
Seems that the loader property is not optimized.
Hi,
Thanks for your work on the plugin : )
I'm trying to process a bunch of "product" images and came up with this function:
function imageProps(i, imgNumber) {
return useNextSanityImage(
sanityClient,
products[i].[imgNumber]
)
}
however when I try to call it more than once in the component I get this error:
Unhandled Runtime Error
Error: Rendered more hooks than during the previous render.
Source
components/ProductSliders.js (11:8) @ imageProps
9 | function imageProps(i, imgNumber) {
10 | return useNextSanityImage(
> 11 | sanityClient,
| ^
12 | products[i].[imgNumber]
13 | )
14 | }
Your help much appreciated.
I'm using the package without @sanity/client
by providing a SanityClientLike
object without problems.
As I'm using graphql I didn't want to bring in the entire sanity client (and rxjs etc), but I didn't realise the first time around that I was able to just provide the project/dataset configuration myself and skip the client
This works just fine for me:
const clientLike: SanityClientLike = {
clientConfig: {
projectId: "my-project",
dataset: "my-dataset",
apiHost: "https://cdn.sanity.io",
},
};
const imageProps = useNextSanityImage(clientLike, image);
Happy to make a PR documenting it, although as I saw there's some issues about client versions you could probably go as far as removing it as a peerDep
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.