next.js icon indicating copy to clipboard operation
next.js copied to clipboard

Next image optimization not working with storybook, even after applying the storybook nextjs addon

Open encetroc opened this issue 2 years ago • 4 comments

Verify canary release

  • [X] I verified that the issue exists in Next.js canary release

Provide environment information

Operating System:
  Platform: win32
  Arch: x64      
  Version: Windows 10 Home
Binaries:
  Node: 16.14.0
  npm: 8.3.1
  Yarn: 1.22.15
  pnpm: N/A
Relevant packages:
  next: 12.1.6
  react: 18.1.0
  react-dom: 18.1.0

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

After applying all solution in the following tread issue#18393, I still have the following error:

failed to parse src "static/media/public/sofia.png" on `next/image`, if using relative image it must start with a leading slash "/" or be an absolute URL (http:// or https://)

I also used the nextjs storybook addon

I am sure it is about next/image optimization because as soon as I add unoptimized flag to nextjs Image component it works perfectly.

Expected Behavior

Nextjs Image should work with storybook after using nextjs storybook addon

Or after adding the following custom solution

To Reproduce

Create a new Nextjs yarn create next-app --typescript

Add webpack5 resolver to package.json

  "resolutions": {
    "webpack": "^5"
  },

Install webpack resolution yarn

Add storybook to Nextjs npx -y sb init --builder webpack5

Add Storybook Nextjs addon yarn add --dev storybook-addon-next

My tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@public/*": ["public/*"],
    },
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

My storybook main.js:

const path = require('path');

module.exports = {
  stories: [
    "../components/**/*.stories.mdx",
    "../components/**/*.stories.@(js|jsx|ts|tsx)",
  ],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    "storybook-addon-next",
  ],
  framework: "@storybook/react",
  core: {
    builder: "@storybook/builder-webpack5",
  },
  webpackFinal: (config) => {
    config.resolve.alias = {
      ...config.resolve?.alias,
      "@public": path.resolve(__dirname, "../public"),
    };
    return config;
  },
};

My storybook preview.js:

import "../styles/globals.css";
import * as NextImage from 'next/image'

const OriginalNextImage = NextImage.default

Object.defineProperty(NextImage, 'default', {
  configurable: true,
  value: (props) => (
    <OriginalNextImage {...props} unoptimized loader={({ src }) => src} />
  ),
})

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
};

My file structure:

components/
    /Dummy
         index.tsx
         Dummy.stories.tsx
pages/             
tailwind.config.js
next.config.js  
postcss.config.js  
tsconfig.json
next-env.d.ts   
public/            
yarn.lock
node_modules/   
README.md          
yarn-error.log
package.json    
styles/

All my components are in the components folder, images are directly placed in the public folder.

Here is an example of a Dummy component:

// index.js
import Sofia from "@public/sofia.png";
import Image from "next/image";

export function Dummy() {
  console.log(process.env.ENV)
  return (
    <div className="bg-slate-400 text-white w-28">
      dummy
      <Image src={Sofia} layout="responsive" />
    </div>
  );
}

And associated story:

// Dummy.stories.tsx
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Dummy } from ".";

export default {
  title: "Example/Dummy",
  component: Dummy,
} as ComponentMeta<typeof Dummy>;

const Template: ComponentStory<typeof Dummy> = (args) => <Dummy />;

export const Primary = Template.bind({});

encetroc avatar May 17 '22 21:05 encetroc

@encetroc I ran into this when I upgraded to 12.1.5+

There's an updated workaround for preview.js in this comment here: https://github.com/vercel/next.js/issues/36417#issuecomment-1117360509

neverether avatar May 24 '22 08:05 neverether

The workaround of injecting the unoptimised prop into the next/image was working for us with external images until we upgraded Next.js and Storybook. The following code addition found in this discussion solved it once again for Next.js 12.1.6 and Storybook 6.5.6:

import NextImage from 'next/image';

NextImage.propTypes = {
  unoptimized: null,
};

NextImage.defaultProps = {
  unoptimized: true,
};

dbruvers avatar Jul 05 '22 13:07 dbruvers

I was having issues with images in Storybook returning a 404 while using a custom loader such as Imgix. You can solve this by either passing in the full URL to the image in your stories or just adding the base path inside preview.js:

import * as NextImage from 'next/image';

const basePath = '<your base path here>';
const OriginalNextImage = NextImage.default;

Object.defineProperty(NextImage, 'default', {
  configurable: true,
  value: ({ src, ...props }) => (
    <OriginalNextImage
      src={`${basePath}${src}`}
      {...props}
      unoptimized
    />
  ),
});

Object.defineProperty(NextImage, '__esModule', {
  configurable: true,
  value: true,
});

pjaws avatar Jul 07 '22 18:07 pjaws

I was having issues with images in Storybook returning a 404 while using a custom loader such as Imgix. You can solve this by either passing in the full URL to the image in your stories or just adding the base path inside preview.js:

import * as NextImage from 'next/image';

const basePath = '<your base path here>';
const OriginalNextImage = NextImage.default;

Object.defineProperty(NextImage, 'default', {
  configurable: true,
  value: ({ src, ...props }) => (
    <OriginalNextImage
      src={`${basePath}${src}`}
      {...props}
      unoptimized
    />
  ),
});

Object.defineProperty(NextImage, '__esModule', {
  configurable: true,
  value: true,
});

Update

Now getting an error with this config on Next.js 12.2.4: Uncaught TypeError: Cannot redefine property: __esModule

Removing the Object.defineProperty(NextImage, '__esModule'... fixes it.

pjaws avatar Aug 05 '22 19:08 pjaws

Please verify that your issue can be recreated with next@canary.

Why was this issue marked with the please verify canary label?

We noticed the provided reproduction was using an older version of Next.js, instead of canary.

The canary version of Next.js ships daily and includes all features and fixes that have not been released to the stable version yet. You can think of canary as a public beta. Some issues may already be fixed in the canary version, so please verify that your issue reproduces by running npm install next@canary and test it in your project, using your reproduction steps.

If the issue does not reproduce with the canary version, then it has already been fixed and this issue can be closed.

How can I quickly verify if my issue has been fixed in canary?

The safest way is to install next@canary in your project and test it, but you can also search through closed Next.js issues for duplicates or check the Next.js releases. You can also use the GitHub template (preferred), or the CodeSandbox or StackBlitz templates to create a reproduction with canary from scratch.

My issue has been open for a long time, why do I need to verify canary now?

Next.js does not backport bug fixes to older versions of Next.js. Instead, we are trying to introduce only a minimal amount of breaking changes between major releases.

What happens if I don't verify against the canary version of Next.js?

An issue with the please verify canary that receives no meaningful activity (e.g. new comments that acknowledge verification against canary) will be automatically closed and locked after 30 days.

If your issue has not been resolved in that time and it has been closed/locked, please open a new issue, with the required reproduction, using next@canary.

I did not open this issue, but it is relevant to me, what can I do to help?

Anyone experiencing the same issue is welcome to provide a minimal reproduction following the above steps. Furthermore, you can upvote the issue using the :+1: reaction on the topmost comment (please do not comment "I have the same issue" without repro steps). Then, we can sort issues by votes to prioritize.

I think my reproduction is good enough, why aren't you looking into it quicker?

We look into every Next.js issue and constantly monitor open issues for new comments.

However, sometimes we might miss one or two due to the popularity/high traffic of the repository. We apologize, and kindly ask you to refrain from tagging core maintainers, as that will usually not result in increased priority.

Upvoting issues to show your interest will help us prioritize and address them as quickly as possible. That said, every issue is important to us, and if an issue gets closed by accident, we encourage you to open a new one linking to the old issue and we will look into it.

Useful Resources

github-actions[bot] avatar Jan 18 '23 17:01 github-actions[bot]

This issue has been automatically closed because it wasn't verified against next@canary. If you think it was closed by accident, please leave a comment. If you are running into a similar issue, please open a new issue with a reproduction. Thank you.

balazsorban44 avatar Feb 18 '23 23:02 balazsorban44

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

github-actions[bot] avatar Mar 21 '23 00:03 github-actions[bot]