How to mock Next.js Image component in Storybook?

Next.js introduced a new Image component in v10 that’s supposed to be a drop in replacement for the <img> tag.

I’m having an error when trying to view components that import next/image into Storybook:

TypeError: imageData is undefined

I have been trying to override the image object in preview.js (a technique I use for next/router, as documented here) but I get the same error:

// .storybook/preview.js

import Image from 'next/image';

Image = ({ src }) => <img src={src} />;

Any idea how I could override the behaviour of the next/image package in Storybook?

Answer

I finally managed to make it work.

First we need to define an env variable with the default settings to get rid of the error. We can do this by plugging into webpack in .storybook/main.js:

// .storybook/main.js
var webpack = require('webpack');

module.exports = {
  ...
  webpackFinal: (config) => {
    config.plugins.push(new webpack.DefinePlugin({
      'process.env.__NEXT_IMAGE_OPTS': JSON.stringify({
        deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
        imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
        domains: [],
        path: '/',
        loader: 'default',
      }),
    }));
    return config;
  },
};

Now we can override the default export from next/image package with a functional component that returns a simple <img/> tag.

// .storybook/preview.js

import * as nextImage from 'next/image';

Object.defineProperty(nextImage, 'default', {
  configurable: true,
  value: (props) => {
    return <img {...props} />;
  },
});

I’m using the defineProperty static method for this (link to MDN article) since I can’t just assign a new value to Image.default.