Next.js: [WIP] Next.js Image Component

Created on 22 Oct 2020  路  20Comments  路  Source: vercel/next.js

Keeping track of the feedback so far:

  • [x] #18195 Lazy loading flickers a <img> with empty or not found src icon
  • [x] #18123 Images that are rendered in a flexbox are not lazy loaded (@timneutkens)
  • [x] #18123 Lazy loading has to be the default (@timneutkens)
  • [x] #18123 Throw error when width and height are missing and unsized is not set (@styfle)
  • [x] #18138 Rename lazy=true to loading=lazy to match web standard (@styfle)
  • [x] #18147 Prevent upscaling images, API should never return an image width larger than the source image width (@styfle)
  • [x] #18107 Add documentation for next/image and automatic image optimization (@styfle)
  • [x] #18149 Correctly encode the url parameter (@ijjk)
  • [x] #18151 Add missing w param for old browsers like IE that dont support srcset (@styfle)
  • [x] #18178 Add support for string width and height attributes (use parseInt and error) (@styfle)
  • [x] #18152 Errors from image optimization need to be surfaced, ie better message when absolute url is not in domains (@ijjk)
  • [ ] Lazy loading can probably be converted to effect + state (@atcastle @devknoll)
  • [x] #18217 Limit maximum number of images.domains and images.sizes to 50, maximum value of size to 10000
  • [x] #18179 Ignore svg for optimization (vector images can be considered already optimized) (@styfle)
  • [x] [#5321](https://github.com/vercel/vercel/pull/5321) Only enable Vercel API in @vercel/next when loader=default (@styfle)
  • [x] #18211 Only enable Next API when loader=default (@styfle)
  • [x] #18236 Fix srcset to ensure the components width is the largest possible image (@styfle)
  • [x] #18267 Separate deviceSizes and iconsSizes (@styfle)
  • [x] #18224 The quality attribute should allow number or string like width (@ykzts)
  • [x] #18298 Fix redirect in next dev for /_next/image/ to /_next/image (@styfle)
  • [ ] E2E tests to compare next dev and Vercel deployments
  • [x] #18424 #18325 Add err.sh links for all errors
  • [x] Deploy to nextjs.org (start with /next/conf) (@leerob)
  • [ ] Deploy to vercel.com (start with @geist/image/new)
21

Most helpful comment

So excited about this component and all the work around it. Thanks to all involved!

馃悰 Hope this isn't the wrong place to mention this, but I just noticed when testing the Image component that src attributes starting with a double slash, e.g. //images.ctfassets.net for Contentful images, seem to be treated as local assets instead of hosted assets. I'm getting around this for now by rewriting // to https://, but I suspect this might not be too deep of an edge case for hosted images 馃槃

All 20 comments

I could lend a hand with these if needed.
_Throw error when width and height are missing and unsized is not set_
_Add err.sh links for all errors_

  • [ ] Support AMP
  • [ ] Support AMP

Given the current <img> usage requires replacement with amp-img it's not a goal of the RFC to support AMP initially. Should be relatively straight-forward to add support for it later though given we'll enforce width and height which AMP does as well.

Great work on this, I've been following the RFC, canary developments and the above pull requests. In the RFC it was mentioned that there should be support for multiple CDNs at the same time.

We're modelling the way we save user-generated images now and notice that just saving the absolute url might not be enough, since then we can't make proper use of the next/image component. Now we're thinking of saving the root url, relative path, dimensions and source / provider (e.g. imgix / cloudinary).

According to the docs, loaders should be defined like this:

module.exports = {
  images: {
    loader: 'imgix',
    path: 'https://example.com/myaccount/',
  },
}

Now what if we are initially using cloudinary, later want to move to imgix or our own solution?

The RFC mentioned the following:

Support for files from multiple sources
It鈥檚 not uncommon for an application to feature images served from multiple image hosts. The Image component will support this through an optional host attribute that lets the user specify from one of multiple hosts declared in the next.config.js file. The component will use both the host substring and the loader registered to go along with that host in constructing the URL.

If no host attribute is supplied, the default host and loader will be used

I don't see any (work in process) PR's open for this functionality and it's not clear on how to implement this yet, is someone working on this and is this planned for the coming release?

I don't see any (work in process) PR's open for this functionality and it's not clear on how to implement this yet, is someone working on this and is this planned for the coming release?

Support for it was removed for the initial release given that it adds significant complexity in both implementation and configuration. It also caused more code than necessary to be shipped to the browser. We'll address it later if there's enough need for it. In general it's uncommon to be hosting on both imgix and cloudinary at the same time.

I am excited to see the new Image component. I would like to know if there will be an example how to deal with an Image which is part of a 2 column flexrow element (lets say on a grid with 50% or 30% width) on tablet/desktop. But on a mobile its 100% width. Is there any example in place how that should be done?

Support for it was removed for the initial release given that it adds significant complexity in both implementation and configuration. It also caused more code than necessary to be shipped to the browser. We'll address it later if there's enough need for it. In general it's uncommon to be hosting on both imgix and cloudinary at the same time.

Does this comment include removing support for a single, custom service loader? In our case, we have an in-house image service that doesn't conform to the path patterns for any of the options I saw in the documentation (default, imgix, cloudinary, akamai).

Is there a way to disable the loader and simply pass the path through to the Image component (maybe something like loader: 'none')? Being able to get the performance benefits of the Image component while building our own path would be great.

Apologies if this is the wrong place to ask, but it doesn't seem like the Image component currently supports optimizing images during the build phase for completely static sites. Is this something that has been considered?

So excited about this component and all the work around it. Thanks to all involved!

馃悰 Hope this isn't the wrong place to mention this, but I just noticed when testing the Image component that src attributes starting with a double slash, e.g. //images.ctfassets.net for Contentful images, seem to be treated as local assets instead of hosted assets. I'm getting around this for now by rewriting // to https://, but I suspect this might not be too deep of an edge case for hosted images 馃槃

Is there a way to disable the loader and simply pass the path through to the Image component (maybe something like loader: 'none')? Being able to get the performance benefits of the Image component while building our own path would be great.

Here BUILT IN LOADERS are.
https://github.com/vercel/next.js/blob/5d7f7a47afa554e5b04c15aebb7ee1f9d3628cfd/packages/next/client/image.tsx#L383-L459

I feel like these functions are simple.

I want to create a custom Loader func which receives LoaderProps, and set it in next.config.js as loader. When will that be implemented or not?

_P.S._
The following is my custom loader. Default loader is a little different than mine.

function myLoader({ root, src, width, quality }: LoaderProps): string {
  const paramsString = `width=?${width}&quality=${quality || 75}`
  return `${root}${normalizeSrc(src)}${paramsString}`
}

Edit
@atcastle already had referred to custom loader. 馃檹

https://github.com/vercel/next.js/discussions/16832#discussion-16805

Support for self-hosted images
Though the Image component is designed with CDNs in mind, it will also work with locally hosted images. The application developer simply needs to add an image compression/resizing step into their build process, and write a custom loader that generates URLs pointing to the output paths used by that build process.

This shouldn鈥檛 be too difficult, as there are a variety of popular build tools for resizing images, and a custom loader can be as simple as a template string.

The // prefix won't work because the Image Optimization API needs to make the upstream request before optimizing and serving the image. We can't rely on the scheme/protocol because many Node.js servers run as HTTP with a HTTPS proxy in front. If we rely on headers, they can be faked.

It's best to use https:// when referencing external images.

So excited about this component and all the work around it. Thanks to all involved!

馃悰 Hope this isn't the wrong place to mention this, but I just noticed when testing the Image component that src attributes starting with a double slash, e.g. //images.ctfassets.net for Contentful images, seem to be treated as local assets instead of hosted assets. I'm getting around this for now by rewriting // to https://, but I suspect this might not be too deep of an edge case for hosted images 馃槃

@colepeters Having trouble with this. What does your next.config.js look like?

Edit: forgot to add domains: ['images.ctfassets.net'],. Works now with prepending https: to src.

@styfle Just to be clear, the // prefix is being used by Contentful (and possibly other CMSes) as the prefix for URLs for image assets. I agree it'd be best to use https when referencing external images, but at the moment there is some user-level intervention required to do this, at least when referencing images served by Contentful. :)

@AlexandraKlein Here's what I've got:

module.exports = {
  images: {
    domains: [
      'images.ctfassets.net'
    ]
  }
}

What I'm doing is prepending https: to my src when using the Image component.

With Contentful, when the image src prop changes within the same react component on route change, Image component isn't swapping out old image for new. @colepeters have you seen this?

Takes a browser reload to see new image.

Though adding a key prop triggers rerender populating correct image.

@AlexandraKlein Sounds like another case of #18369

I'm wondering if there's plans for a Contentful loader?

Contentful has an Image API similar to Imgix or Cloudinary, wondering it makes sense to use that directly?

I'm wondering if there are plans to add support for custom loaders? Maybe, for example, user could pass a loader callback to <Image>, which receives LoaderProps and returns image url? I think it will be much easier for users to write their own loaders, than to wait for them to be added to Next.js

Anyway, are there plans for Cloudflire Resize loader? I think I could contribute...

@laSinteZ
Check #18450 out.

@styfle Just to be clear, the // prefix is being used by Contentful (and possibly other CMSes) as the prefix for URLs for image assets. I agree it'd be best to use https when referencing external images, but at the moment there is some user-level intervention required to do this, at least when referencing images served by Contentful. :)

@AlexandraKlein Here's what I've got:

module.exports = {
  images: {
    domains: [
      'images.ctfassets.net'
    ]
  }
}

What I'm doing is prepending https: to my src when using the Image component.

This works fine locally for me but urls give me 400 errors in production with "url" parameter is required response.

Source url with 400 error: https://mywebsite.com/_next/image?url=https%3A%2F%2Fimages.ctfassets.net%2F1xkvhwkgcr51%2F6HODBVSFqUTbEKI7ilXx%2Ff9f16ab3552e973b764c922f06db181a%2Fmy-image.png&w=1200&q=75

Source url locally with no error: http://localhost:3000/_next/image?url=https%3A%2F%2Fimages.ctfassets.net%2F1xkvhwkgcr51%2F6HODBVSFqUTbEKI7ilXx%2Ff9f16ab3552e973b764c922f06db181a%2Fmy-image.png&w=1200&q=75

I'm wondering if there's plans for a Contentful loader?

Contentful has an Image API similar to Imgix or Cloudinary, wondering it makes sense to use that directly?

PR in progress: https://github.com/vercel/next.js/pull/19117

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rauchg picture rauchg  路  208Comments

timneutkens picture timneutkens  路  250Comments

robinvdvleuten picture robinvdvleuten  路  74Comments

Timer picture Timer  路  60Comments

iamstarkov picture iamstarkov  路  119Comments