rsnext/packages/next/server/lib/squoosh/main.ts
JJ Kasper 25d064f812
Pre-compile more dependencies (#32742)
This ncc's some remaining dependencies bringing us under 20 install time dependencies (including nested dependencies), this also reduces install size by another `2.75 MB`. A follow-up PR will investigate a custom install script for our swc packages to allow us to remove the `optionalDependencies` which is slowing down install time as well. 

x-ref: https://github.com/vercel/next.js/pull/32679
x-ref: https://github.com/vercel/next.js/pull/32627
x-ref: https://github.com/vercel/next.js/issues/31887
x-ref: https://github.com/vercel/styled-jsx/pull/770
2022-01-17 15:17:22 +00:00

85 lines
2.4 KiB
TypeScript

import { Worker } from 'next/dist/compiled/jest-worker'
import * as path from 'path'
import { execOnce } from '../../../shared/lib/utils'
import { cpus } from 'os'
type RotateOperation = {
type: 'rotate'
numRotations: number
}
type ResizeOperation = {
type: 'resize'
} & ({ width: number; height?: never } | { height: number; width?: never })
export type Operation = RotateOperation | ResizeOperation
export type Encoding = 'jpeg' | 'png' | 'webp' | 'avif'
const getWorker = execOnce(
() =>
new Worker(path.resolve(__dirname, 'impl'), {
enableWorkerThreads: true,
// There will be at most 6 workers needed since each worker will take
// at least 1 operation type.
numWorkers: Math.max(1, Math.min(cpus().length - 1, 6)),
computeWorkerKey: (method) => method,
})
)
export async function processBuffer(
buffer: Buffer,
operations: Operation[],
encoding: Encoding,
quality: number
): Promise<Buffer> {
const worker: typeof import('./impl') = getWorker() as any
let imageData = await worker.decodeBuffer(buffer)
for (const operation of operations) {
if (operation.type === 'rotate') {
imageData = await worker.rotate(imageData, operation.numRotations)
} else if (operation.type === 'resize') {
if (
operation.width &&
imageData.width &&
imageData.width > operation.width
) {
imageData = await worker.resize({
image: imageData,
width: operation.width,
})
} else if (
operation.height &&
imageData.height &&
imageData.height > operation.height
) {
imageData = await worker.resize({
image: imageData,
height: operation.height,
})
}
}
}
switch (encoding) {
case 'jpeg':
return Buffer.from(await worker.encodeJpeg(imageData, { quality }))
case 'webp':
return Buffer.from(await worker.encodeWebp(imageData, { quality }))
case 'avif':
const avifQuality = quality - 20
return Buffer.from(
await worker.encodeAvif(imageData, {
quality: Math.max(avifQuality, 0),
})
)
case 'png':
return Buffer.from(await worker.encodePng(imageData))
default:
throw Error(`Unsupported encoding format`)
}
}
export async function decodeBuffer(buffer: Buffer) {
const worker: typeof import('./impl') = getWorker() as any
const imageData = await worker.decodeBuffer(buffer)
return imageData
}