Skip to content

Commit

Permalink
Next.js: Add avif support
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinpalkovic committed Oct 30, 2023
1 parent 010fc13 commit 38e6ecc
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 14 deletions.
4 changes: 3 additions & 1 deletion code/frameworks/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,15 @@
"find-up": "^5.0.0",
"fs-extra": "^11.1.0",
"image-size": "^1.0.0",
"loader-utils": "^3.2.0",
"loader-utils": "^3.2.1",
"node-polyfill-webpack-plugin": "^2.0.1",
"pnp-webpack-plugin": "^1.7.0",
"postcss": "^8.4.21",
"postcss-loader": "^7.0.2",
"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 All @@ -119,6 +120,7 @@
"@types/babel__core": "^7",
"@types/babel__plugin-transform-runtime": "^7",
"@types/babel__preset-env": "^7",
"@types/loader-utils": "^2.0.5",
"next": "^14.0.0",
"typescript": "^4.9.3",
"webpack": "^5.65.0"
Expand Down
35 changes: 29 additions & 6 deletions code/frameworks/nextjs/src/next-image-loader-stub.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,52 @@
// @ts-expect-error (loader-utils has no webpack5 compatible types)
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';

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

const nextImageLoaderStub: RawLoaderDefinition<LoaderOptions> = function (content) {
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)));
}

const nextImageLoaderStub: RawLoaderDefinition<LoaderOptions> = async function NextImageLoader(
content
) {
const { filename, nextConfig } = this.getOptions();
const outputPath = interpolateName(this, filename.replace('[ext]', '.[ext]'), {
const opts = {
context: this.rootContext,
content,
});
};
const outputPath = interpolateName(this, filename.replace('[ext]', '.[ext]'), opts);
const extension = interpolateName(this, '[ext]', opts);

this.emitFile(outputPath, content);

const { width, height } = imageSizeOf(this.resourcePath);

if (nextConfig.images?.disableStaticImages) {
return `const src = '${outputPath}'; export default src;`;
}

let width;
let height;

if (extension === 'avif') {
const transformer = sharp(content);
const result = await transformer.metadata();
width = result.width;
height = result.height;
} else {
const result = imageSizeOf(this.resourcePath);
width = result.width;
height = result.height;
}

return `export default ${JSON.stringify({
src: outputPath,
height,
Expand Down
8 changes: 8 additions & 0 deletions code/frameworks/nextjs/template/stories/Image.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Image from 'next/image';
import { waitFor } from '@storybook/testing-library';

import Accessibility from '../../assets/accessibility.svg';
import AvifImage from '../../assets/avif-test-image.avif';

export default {
component: Image,
Expand All @@ -14,6 +15,13 @@ export default {

export const Default = {};

export const Avif = {
args: {
src: AvifImage,
alt: 'Avif Test Image',
},
};

export const BlurredPlaceholder = {
args: {
placeholder: 'blur',
Expand Down
Binary file not shown.
Loading

0 comments on commit 38e6ecc

Please sign in to comment.