Skip to content

Commit

Permalink
Merge pull request #26787 from shuta13/fix-deps-on-sharp-errors
Browse files Browse the repository at this point in the history
Next.js: Move sharp into optional deps

(cherry picked from commit 9fd8c0a)
  • Loading branch information
valentinpalkovic authored and shilman committed Apr 16, 2024
1 parent 0ff71b4 commit 5a4de0d
Show file tree
Hide file tree
Showing 5 changed files with 638 additions and 254 deletions.
4 changes: 3 additions & 1 deletion code/frameworks/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@
"resolve-url-loader": "^5.0.0",
"sass-loader": "^12.4.0",
"semver": "^7.3.5",
"sharp": "^0.32.6",
"style-loader": "^3.3.1",
"styled-jsx": "5.1.1",
"ts-dedent": "^2.0.0",
Expand Down Expand Up @@ -146,6 +145,9 @@
"optional": true
}
},
"optionalDependencies": {
"sharp": "^0.33.3"
},
"engines": {
"node": ">=18.0.0"
},
Expand Down
31 changes: 22 additions & 9 deletions code/frameworks/nextjs/src/next-image-loader-stub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,27 @@ import { interpolateName } from 'loader-utils';
import imageSizeOf from 'image-size';
import type { RawLoaderDefinition } from 'webpack';
import type { NextConfig } from 'next';
import sharp from 'sharp';
import { cpus } from 'os';
import { NextJsSharpError } from '@storybook/core-events/preview-errors';

interface LoaderOptions {
filename: string;
nextConfig: NextConfig;
}

if (sharp.concurrency() > 1) {
// Reducing concurrency reduces the memory usage too.
const divisor = process.env.NODE_ENV === 'development' ? 4 : 2;
sharp.concurrency(Math.floor(Math.max(cpus().length / divisor, 1)));
let sharp: typeof import('sharp') | undefined;

try {
sharp = require('sharp');
if (sharp && sharp.concurrency() > 1) {
// Reducing concurrency reduces the memory usage too.
const divisor = process.env.NODE_ENV === 'development' ? 4 : 2;
sharp.concurrency(Math.floor(Math.max(cpus().length / divisor, 1)));
}
} catch (e) {
console.warn(
'You have to install sharp in order to use image optimization features in Next.js. AVIF support is also disabled.'
);
}

const nextImageLoaderStub: RawLoaderDefinition<LoaderOptions> = async function NextImageLoader(
Expand All @@ -37,10 +46,14 @@ const nextImageLoaderStub: RawLoaderDefinition<LoaderOptions> = async function N
let height;

if (extension === 'avif') {
const transformer = sharp(content);
const result = await transformer.metadata();
width = result.width;
height = result.height;
if (sharp) {
const transformer = sharp(content);
const result = await transformer.metadata();
width = result.width;
height = result.height;
} else {
throw new NextJsSharpError();
}
} else {
const result = imageSizeOf(this.resourcePath);
width = result.width;
Expand Down
17 changes: 17 additions & 0 deletions code/lib/core-events/src/errors/preview-errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export enum Category {
RENDERER_VUE = 'RENDERER_VUE',
RENDERER_VUE3 = 'RENDERER_VUE3',
RENDERER_WEB_COMPONENTS = 'RENDERER_WEB-COMPONENTS',
FRAMEWORK_NEXTJS = 'FRAMEWORK_NEXTJS',
}

export class MissingStoryAfterHmrError extends StorybookError {
Expand Down Expand Up @@ -235,3 +236,19 @@ export class StoryStoreAccessedBeforeInitializationError extends StorybookError
remove access to the store entirely`;
}
}

export class NextJsSharpError extends StorybookError {
readonly category = Category.FRAMEWORK_NEXTJS;

readonly code = 1;

readonly documentation = 'https://storybook.js.org/docs/get-started/nextjs#faq';

template() {
return dedent`
You are importing avif images, but you don't have sharp installed.
You have to install sharp in order to use image optimization features in Next.js.
`;
}
}
Loading

0 comments on commit 5a4de0d

Please sign in to comment.