From 3ebf5267dcd84fa85ecf5a8ae7ff695750816754 Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 12 Jul 2021 13:05:41 -0400 Subject: [PATCH] Workaround for Node.js 16+ on Apple Silicon M1 (#27031) This PR is a workaround for #24421 by adding an artificial delay when Apple M1 + buggy Node.js is detected. Node.js 14 is unaffected because it M1 still reports `arch=x64`. Starting in Node.js 16, M1 reports `arch=arm64`. V8 Bug: https://crbug.com/1224882 Node.js Issue: https://github.com/nodejs/node/issues/39327 --- packages/next/server/lib/squoosh/impl.ts | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/next/server/lib/squoosh/impl.ts b/packages/next/server/lib/squoosh/impl.ts index b9efc9859114f..1d924e226c55a 100644 --- a/packages/next/server/lib/squoosh/impl.ts +++ b/packages/next/server/lib/squoosh/impl.ts @@ -1,6 +1,32 @@ +import semver from 'next/dist/compiled/semver' import { codecs as supportedFormats, preprocessors } from './codecs' import ImageData from './image_data' +// Fixed in Node.js 16.5.0 and newer. +// See https://github.com/nodejs/node/pull/39337 +// Eventually, remove this delay when engines is updated. +// See https://git.io/JCTr0 +const FIXED_VERSION = '16.5.0' +const DELAY_MS = 1000 +let _promise: Promise | undefined + +function delayOnce(ms: number): Promise { + if (!_promise) { + _promise = new Promise((resolve) => { + setTimeout(resolve, ms) + }) + } + return _promise +} + +function maybeDelay(): Promise { + const isAppleM1 = process.arch === 'arm64' && process.platform === 'darwin' + if (isAppleM1 && semver.lt(process.version, FIXED_VERSION)) { + return delayOnce(DELAY_MS) + } + return Promise.resolve() +} + export async function decodeBuffer( _buffer: Buffer | Uint8Array ): Promise { @@ -39,6 +65,7 @@ export async function resize({ image, width, height }: ResizeOpts) { const p = preprocessors['resize'] const m = await p.instantiate() + await maybeDelay() return await m(image.data, image.width, image.height, { ...p.defaultOptions, width, @@ -54,6 +81,7 @@ export async function encodeJpeg( const e = supportedFormats['mozjpeg'] const m = await e.enc() + await maybeDelay() const r = await m.encode!(image.data, image.width, image.height, { ...e.defaultEncoderOptions, quality, @@ -69,6 +97,7 @@ export async function encodeWebp( const e = supportedFormats['webp'] const m = await e.enc() + await maybeDelay() const r = await m.encode!(image.data, image.width, image.height, { ...e.defaultEncoderOptions, quality, @@ -83,6 +112,7 @@ export async function encodePng( const e = supportedFormats['oxipng'] const m = await e.enc() + await maybeDelay() const r = await m.encode(image.data, image.width, image.height, { ...e.defaultEncoderOptions, })