Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NextJS: Fix Image Context reuse (ensure singleton by externalizing it) #23881

Merged
23 changes: 22 additions & 1 deletion code/frameworks/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./image-context": {
"types": "./dist/image-context.d.ts",
"require": "./dist/image-context.js",
"import": "./dist/image-context.mjs"
},
"./dist/image-context": {
"types": "./dist/image-context.d.ts",
"require": "./dist/image-context.js",
"import": "./dist/image-context.mjs"
},
"./preset": {
"types": "./dist/preset.d.ts",
"require": "./dist/preset.js"
Expand All @@ -46,6 +56,16 @@
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"typesVersions": {
"*": {
"*": [
"dist/index.d.ts"
],
"dist/image-context": [
"dist/image-context.d.ts"
]
}
},
"files": [
"dist/**/*",
"template/cli/**/*",
Expand Down Expand Up @@ -136,11 +156,12 @@
},
"bundler": {
"entries": [
"./src/image-context.ts",
"./src/index.ts",
"./src/preset.ts",
"./src/preview.tsx",
"./src/next-image-loader-stub.ts",
"./src/images/context.ts",
"./src/images/decorator.tsx",
"./src/images/next-future-image.tsx",
"./src/images/next-legacy-image.tsx",
"./src/images/next-image.tsx",
Expand Down
9 changes: 8 additions & 1 deletion code/frameworks/nextjs/src/images/decorator.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import * as React from 'react';
import type { Addon_StoryContext } from '@storybook/types';
import { ImageContext } from './context';

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-error (this only errors during compilation for production)
// eslint-disable-next-line import/no-extraneous-dependencies
import { ImageContext as ImageContextValue } from '@storybook/nextjs/dist/image-context';
import { type ImageContext as ImageContextType } from '../image-context';

const ImageContext = ImageContextValue as typeof ImageContextType;

export const ImageDecorator = (
Story: React.FC,
Expand Down
17 changes: 10 additions & 7 deletions code/frameworks/nextjs/src/images/next-future-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ import type * as _NextImage from 'next/image';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore import is aliased in webpack config
import OriginalNextFutureImage from 'sb-original/next/future/image';
import { ImageContext } from './context';

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-error (this only errors during compilation for production)
// eslint-disable-next-line import/no-extraneous-dependencies
import { ImageContext as ImageContextValue } from '@storybook/nextjs/dist/image-context';
import { type ImageContext as ImageContextType } from '../image-context';
import { defaultLoader } from './next-image-default-loader';

function NextFutureImage(props: _NextImage.ImageProps) {
const ImageContext = ImageContextValue as typeof ImageContextType;

function NextFutureImage({ loader, ...props }: _NextImage.ImageProps) {
const imageParameters = React.useContext(ImageContext);

return (
<OriginalNextFutureImage
{...imageParameters}
{...props}
loader={props.loader ?? defaultLoader}
/>
<OriginalNextFutureImage {...imageParameters} {...props} loader={loader ?? defaultLoader} />
);
}

Expand Down
15 changes: 10 additions & 5 deletions code/frameworks/nextjs/src/images/next-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@
import OriginalNextImage from 'sb-original/next/image';
import type * as _NextImage from 'next/image';
import React from 'react';
import { ImageContext } from './context';

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-error (this only errors during compilation for production)
// eslint-disable-next-line import/no-extraneous-dependencies
import { ImageContext as ImageContextValue } from '@storybook/nextjs/dist/image-context';
import { type ImageContext as ImageContextType } from '../image-context';
import { defaultLoader } from './next-image-default-loader';

const MockedNextImage = (props: _NextImage.ImageProps) => {
const ImageContext = ImageContextValue as typeof ImageContextType;

const MockedNextImage = ({ loader, ...props }: _NextImage.ImageProps) => {
const imageParameters = React.useContext(ImageContext);

return (
<OriginalNextImage {...imageParameters} {...props} loader={props.loader ?? defaultLoader} />
);
return <OriginalNextImage {...imageParameters} {...props} loader={loader ?? defaultLoader} />;
};

export default MockedNextImage;
17 changes: 10 additions & 7 deletions code/frameworks/nextjs/src/images/next-legacy-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
import OriginalNextLegacyImage from 'sb-original/next/legacy/image';
import type * as _NextLegacyImage from 'next/legacy/image';
import React from 'react';
import { ImageContext } from './context';

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-error (this only errors during compilation for production)
// eslint-disable-next-line import/no-extraneous-dependencies
import { ImageContext as ImageContextValue } from '@storybook/nextjs/dist/image-context';
import { type ImageContext as ImageContextType } from '../image-context';
import { defaultLoader } from './next-image-default-loader';

function NextLegacyImage(props: _NextLegacyImage.ImageProps) {
const ImageContext = ImageContextValue as typeof ImageContextType;

function NextLegacyImage({ loader, ...props }: _NextLegacyImage.ImageProps) {
const imageParameters = React.useContext(ImageContext);

return (
<OriginalNextLegacyImage
{...imageParameters}
{...props}
loader={props.loader ?? defaultLoader}
/>
<OriginalNextLegacyImage {...imageParameters} {...props} loader={loader ?? defaultLoader} />
);
}

Expand Down