Skip to content

Commit

Permalink
Merge pull request #23296 from storybookjs/valentin/fix-next-images-i…
Browse files Browse the repository at this point in the history
…n-latest-release

Next.js: Fix next/image usage in latest Next.js release

(cherry picked from commit d4a3a23)
  • Loading branch information
valentinpalkovic authored and shilman committed Jul 4, 2023
1 parent f57d66e commit b4f47c5
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 139 deletions.
11 changes: 10 additions & 1 deletion code/frameworks/nextjs/package.json
Expand Up @@ -102,7 +102,7 @@
"@types/babel__core": "^7",
"@types/babel__plugin-transform-runtime": "^7",
"@types/babel__preset-env": "^7",
"next": "^13.2.4",
"next": "^13.4.8",
"typescript": "^4.9.3",
"webpack": "^5.65.0"
},
Expand Down Expand Up @@ -143,8 +143,17 @@
"./src/preset.ts",
"./src/preview.tsx",
"./src/next-image-loader-stub.ts",
"./src/images/context.ts",
"./src/images/next-future-image.tsx",
"./src/images/next-legacy-image.tsx",
"./src/images/next-image.tsx",
"./src/font/webpack/loader/storybook-nextjs-font-loader.ts"
],
"externals": [
"sb-original/next/image",
"sb-original/next/future/image",
"sb-original/next/legacy/image"
],
"platform": "node"
},
"gitHead": "9fb2573aa274f3f69d3358050e8df9c903e8245f"
Expand Down
21 changes: 21 additions & 0 deletions code/frameworks/nextjs/src/images/next-future-image.tsx
@@ -0,0 +1,21 @@
import React from 'react';
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';
import { defaultLoader } from './next-image-default-loader';

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

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

export default NextFutureImage;
28 changes: 28 additions & 0 deletions code/frameworks/nextjs/src/images/next-image-default-loader.tsx
@@ -0,0 +1,28 @@
import type * as _NextImage from 'next/image';

export const defaultLoader = ({ src, width, quality }: _NextImage.ImageLoaderProps) => {
const missingValues = [];
if (!src) {
missingValues.push('src');
}

if (!width) {
missingValues.push('width');
}

if (missingValues.length > 0) {
throw new Error(
`Next Image Optimization requires ${missingValues.join(
', '
)} to be provided. Make sure you pass them as props to the \`next/image\` component. Received: ${JSON.stringify(
{
src,
width,
quality,
}
)}`
);
}

return `${src}?w=${width}&q=${quality ?? 75}`;
};
88 changes: 0 additions & 88 deletions code/frameworks/nextjs/src/images/next-image-stub.tsx

This file was deleted.

17 changes: 17 additions & 0 deletions code/frameworks/nextjs/src/images/next-image.tsx
@@ -0,0 +1,17 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore import is aliased in webpack config
import OriginalNextImage from 'sb-original/next/image';
import type * as _NextImage from 'next/image';
import React from 'react';
import { ImageContext } from './context';
import { defaultLoader } from './next-image-default-loader';

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

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

export default MockedNextImage;
21 changes: 21 additions & 0 deletions code/frameworks/nextjs/src/images/next-legacy-image.tsx
@@ -0,0 +1,21 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore import is aliased in webpack config
import OriginalNextLegacyImage from 'sb-original/next/legacy/image';
import type * as _NextLegacyImage from 'next/legacy/image';
import React from 'react';
import { ImageContext } from './context';
import { defaultLoader } from './next-image-default-loader';

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

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

export default NextLegacyImage;
31 changes: 29 additions & 2 deletions code/frameworks/nextjs/src/images/webpack.ts
@@ -1,11 +1,38 @@
import semver from 'semver';
import type { Configuration as WebpackConfig, RuleSetRule } from 'webpack';
import type { NextConfig } from 'next';
import { addScopedAlias, getNextjsVersion } from '../utils';
import path from 'path';
import { getNextjsVersion } from '../utils';

export const configureImages = (baseConfig: WebpackConfig, nextConfig: NextConfig): void => {
configureStaticImageImport(baseConfig, nextConfig);
addScopedAlias(baseConfig, 'next/image');
configureImageDefaults(baseConfig);
};

const configureImageDefaults = (baseConfig: WebpackConfig): void => {
const version = getNextjsVersion();
const resolve = baseConfig.resolve ?? {};
resolve.alias = {
...resolve.alias,
'sb-original/next/image': require.resolve('next/image'),
'next/image': path.resolve(__dirname, './images/next-image'),
};

if (semver.satisfies(version, '^13.0.0')) {
resolve.alias = {
...resolve.alias,
'sb-original/next/legacy/image': require.resolve('next/legacy/image'),
'next/legacy/image': path.resolve(__dirname, './images/next-legacy-image'),
};
}

if (semver.satisfies(version, '^12.2.0')) {
resolve.alias = {
...resolve.alias,
'sb-original/next/future/image': require.resolve('next/future/image'),
'next/future/image': path.resolve(__dirname, './images/next-future-image'),
};
}
};

const configureStaticImageImport = (baseConfig: WebpackConfig, nextConfig: NextConfig): void => {
Expand Down
1 change: 0 additions & 1 deletion code/frameworks/nextjs/src/preview.tsx
Expand Up @@ -3,7 +3,6 @@ import './config/preview';
import { ImageDecorator } from './images/decorator';
import { RouterDecorator } from './routing/decorator';
import { StyledJsxDecorator } from './styledJsx/decorator';
import './images/next-image-stub';
import { HeadManagerDecorator } from './head-manager/decorator';

function addNextHeadCount() {
Expand Down
1 change: 1 addition & 0 deletions code/frameworks/nextjs/src/routing/app-router-provider.tsx
Expand Up @@ -68,6 +68,7 @@ const AppRouterProvider: React.FC<AppRouterProviderProps> = ({ children, action,
changeByServerResponse() {
// NOOP
},
buildId: 'storybook',
tree,
focusAndScrollRef: {
apply: false,
Expand Down

0 comments on commit b4f47c5

Please sign in to comment.