11

when I want to export my nextjs app, it says that I cannot export my images on static websites.

Error: Image Optimization using Next.js' default loader is not compatible with next export. Possible solutions: - Use next start to run a server, which includes the Image Optimization API. - Use any provider which supports Image Optimization (like Vercel). - Configure a third-party loader in next.config.js. - Use the loader prop for next/image.

How can I make it so that it does ?

Is there a way for me to simply tell it to render images statically ? I dont want to go throught other onlines images loaders..

Cesarioo
  • 113
  • 1
  • 1
  • 5

3 Answers3

23

I created a npm module so that we can use the Next.js <Image/> component with optimized images while using the static export functionality.

https://www.npmjs.com/package/next-image-export-optimizer

The library wraps the <Image /> component of Next.js and automatically creates optimized images using sharp.js at export time.

It uses a custom loader to create a srcset for the <img /> that the <Image /> component of Next.js creates. Then at build/export time, the images inside the public/images folder (as an example) are optimized with sharp.js and copied into the build folder.

Niels
  • 479
  • 3
  • 4
  • 1
    Thank you thank you thank you! I have a completely static site but need a few images, and the idea of adding node to my deployed environment and losing export functionality was offensive to my senses. Appreciate the great README and good API design. – Freedom_Ben Jun 22 '22 at 19:15
  • AMAZING WORK! It is sad that this functionality is not built in Next. – Sam Magura Oct 05 '22 at 14:46
16

You need to set up a custom image loader in Next.js

In your next.config.js file, add this property to the export:

images: {
  loader: "custom"
}

And make a script called loader.js that exports this:

function imageLoader({ src }) {
  return `/images/${src}`; // REPLACE WITH YOUR IMAGE DIRECTORY
}

module.exports = imageLoader;

For each Image component, set the loader prop manually:

const imageLoader = require("PATH TO loader.js");

<Image loader={imageLoader} />
skara9
  • 4,042
  • 1
  • 6
  • 21
  • Thank you very much for the fast answer. Where should I put my loader.js ? It says in my < Image /> that it does not exist Thank you very much again – Cesarioo Dec 27 '21 at 20:47
  • you can put it wherever you want, maybe in a separate folder outside of your components -- make sure to export the function and import it from each file – skara9 Dec 27 '21 at 20:59
  • 1
    Thank you very much. With some more insights and look on the code of the page, I've found that in the return section we only need the ${src} . Thank you very very much. I hope you are well where you are. You are the reason why I am going to sleep right now thank you sooo much. – Cesarioo Dec 27 '21 at 21:06
  • This approach won't work, you need to provide a URL to a third-party cloud provider (not a local path) where the image is hosted when using a custom loader. The optimization needs to happen somewhere, in this case the third-party service. – juliomalves Dec 28 '21 at 15:18
  • @juliomalves OP wanted to host their images locally so I gave the solution -- may not give you the most optimized images but it will still work – skara9 Dec 28 '21 at 17:23
  • I get you, but it will render the image as is, which kinda defeats the purpose of using the `next/image` component since its main benefit is the optimizations it brings. Might as well just use an `` tag instead when using `next export`. – juliomalves Dec 28 '21 at 18:48
  • 1
    @juliomalves yeah, I guess using an `img` tag would work, but it doesn't behave the exact same way as the `Image` component so it could create inconsistencies -- i just prefer this approach since it's easy to substitute in a different image loader whenever necessary -- doesn't really have much of a drawback either – skara9 Dec 28 '21 at 20:18
4

I'm going to add onto skara9's answer because it didn't quite work for me. I found a thread on github discussing it and the answer there worked for me. It just wraps around the NextJS image component and works pretty flawlessly for me.

// components/Image.js
import NextImage from "next/image";

// opt-out of image optimization, no-op
const customLoader = ({ src }) => {
  return src
}

export default function Image(props) {
  return (
    <NextImage
      {...props}
      loader={customLoader}
    />
  );
}

Make sure you change your imports and update your next.config.js

import Image from '../components/Image.js'
michecode
  • 85
  • 5