feat(next/image)!: remove squoosh in favor of sharp as optional dependency (#63321)

## History

Previously, we added support for `squoosh` because it was a wasm
implementation that "just worked" on all platforms when running `next
dev` for the first time. However, it was slow so we always recommended
manually installing `sharp` for production use cases running `next
build` and `next start`.

Now that [`sharp` supports
webassembly](https://sharp.pixelplumbing.com/install#webassembly), we no
longer need to maintain `squoosh`, so it can be removed. We also don't
need to make the user install sharp manually because it can be installed
under `optionalDependencies`. I left it optional in case there was some
platform that still needed to manually install the wasm variant with
`npm install --cpu=wasm32 sharp` such as codesandbox/stackblitz (I don't
believe sharp has any fallback built in yet).

Since we can guarantee `sharp`, we can also remove `get-orientation` dep
and upgrade `image-size` dep.

I also moved an [existing `sharp`
test](https://github.com/vercel/next.js/pull/56674) into its own fixture
since it was unrelated to image optimization.

## Related Issues
- Fixes https://github.com/vercel/next.js/issues/41417
- Related https://github.com/vercel/next.js/pull/54670
- Related https://github.com/vercel/next.js/issues/54708
- Related https://github.com/vercel/next.js/issues/44804
- Related https://github.com/vercel/next.js/issues/48820
- Related https://github.com/vercel/next.js/pull/61810
- Related https://github.com/vercel/next.js/pull/61696
- Related https://github.com/vercel/next.js/issues/44685
- Closes https://github.com/vercel/next.js/issues/64362

## Breaking Change

This is a breaking change because newer versions of `sharp` no longer
support `yarn@1`.

- https://github.com/lovell/sharp/issues/3750

The workaround is to install with `yarn --ignore-engines` flag.

Also note that Vercel no longer defaults to yarn when no lockfile is
found

- https://github.com/vercel/vercel/pull/11131
- https://github.com/vercel/vercel/pull/11242

Closes NEXT-2823
This commit is contained in:
Steven 2024-04-25 14:01:56 -04:00 committed by GitHub
parent 433faa8436
commit a6a6117197
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 1091 additions and 13417 deletions

1
.github/CODEOWNERS vendored
View file

@ -27,7 +27,6 @@
/**/*image*/** @timneutkens @ijjk @shuding @styfle @huozhi @ztanner @vercel/devex
/**/*img* @timneutkens @ijjk @shuding @styfle @huozhi @ztanner @vercel/devex
/packages/next/client/use-intersection.tsx @timneutkens @ijjk @shuding @styfle
/packages/next/server/lib/squoosh/ @timneutkens @ijjk @shuding @styfle
/packages/next/server/serve-static.ts @timneutkens @ijjk @shuding @styfle @huozhi @ztanner
/packages/next/server/config.ts @timneutkens @ijjk @shuding @styfle @huozhi @ztanner

View file

@ -443,8 +443,6 @@ If you need a different provider, you can use the [`loader`](#loader) prop with
> Images can not be optimized at build time using [`output: 'export'`](/docs/pages/building-your-application/deploying/static-exports), only on-demand. To use `next/legacy/image` with `output: 'export'`, you will need to use a different loader than the default. [Read more in the discussion.](https://github.com/vercel/next.js/discussions/19065)
> The `next/legacy/image` component's default loader uses [`squoosh`](https://www.npmjs.com/package/@squoosh/lib) because it is quick to install and suitable for a development environment. When using `next start` in your production environment, it is strongly recommended that you install [`sharp`](https://www.npmjs.com/package/sharp) by running `npm i sharp` in your project directory. This is not necessary for Vercel deployments, as `sharp` is installed automatically.
## Advanced
The following configuration is for advanced use cases and is usually not necessary. If you choose to configure the properties below, you will override any changes to the Next.js defaults in future updates.

View file

@ -110,7 +110,6 @@
"@types/react-dom": "18.2.23",
"@types/relay-runtime": "14.1.13",
"@types/selenium-webdriver": "4.0.15",
"@types/sharp": "0.29.3",
"@types/string-hash": "1.1.1",
"@types/trusted-types": "2.0.3",
"@typescript-eslint/eslint-plugin": "6.14.0",
@ -160,7 +159,7 @@
"html-validator": "5.1.18",
"http-proxy": "1.18.1",
"husky": "8.0.0",
"image-size": "0.9.3",
"image-size": "1.1.1",
"is-animated": "2.0.2",
"isomorphic-unfetch": "3.0.0",
"jest": "29.7.0",

View file

@ -119,6 +119,9 @@
"optional": true
}
},
"optionalDependencies": {
"sharp": "^0.33.3"
},
"devDependencies": {
"@ampproject/toolbox-optimizer": "2.8.3",
"@babel/code-frame": "7.22.5",
@ -234,7 +237,6 @@
"events": "3.3.0",
"find-up": "4.1.0",
"fresh": "0.5.2",
"get-orientation": "1.1.2",
"glob": "7.1.7",
"gzip-size": "5.1.1",
"http-proxy": "1.18.1",
@ -243,7 +245,7 @@
"https-proxy-agent": "5.0.1",
"icss-utils": "5.1.0",
"ignore-loader": "0.1.2",
"image-size": "1.0.0",
"image-size": "1.1.1",
"is-docker": "2.0.0",
"is-wsl": "2.2.0",
"jest-worker": "27.5.1",

View file

@ -305,7 +305,6 @@ export async function collectBuildTraces({
// only ignore image-optimizer code when
// this is being handled outside of next-server
'**/next/dist/server/image-optimizer.js',
'**/next/dist/server/lib/squoosh/**/*.wasm',
]
: []),

View file

@ -33,7 +33,7 @@ function nextImageLoader(this: any, content: Buffer) {
const imageSizeSpan = imageLoaderSpan.traceChild('image-size-calculation')
const imageSize = await imageSizeSpan.traceAsyncFn(() =>
getImageSize(content, extension).catch((err) => err)
getImageSize(content).catch((err) => err)
)
if (imageSize instanceof Error) {

View file

@ -127,8 +127,7 @@ async function nextMetadataImageLoader(
}
const imageSize: { width?: number; height?: number } = await getImageSize(
content,
extension as 'avif' | 'webp' | 'png' | 'jpeg'
content
).catch((err) => err)
if (imageSize instanceof Error) {

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright © 2019 MooYeol Prescott Lee, http://debug.so <mooyoul@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
{"name":"get-orientation","main":"index.js","author":"MooYeol Prescott Lee <mooyoul@gmail.com>","license":"MIT"}

View file

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright © 2017 Aditya Yadav, http://netroy.in
Copyright © 2013-Present Aditya Yadav, http://netroy.in
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

File diff suppressed because one or more lines are too long

View file

@ -4,7 +4,6 @@ import { cpus } from 'os'
import type { IncomingMessage, ServerResponse } from 'http'
import { mediaType } from 'next/dist/compiled/@hapi/accept'
import contentDisposition from 'next/dist/compiled/content-disposition'
import { getOrientation, Orientation } from 'next/dist/compiled/get-orientation'
import imageSizeOf from 'next/dist/compiled/image-size'
import isAnimated from 'next/dist/compiled/is-animated'
import { join } from 'path'
@ -15,11 +14,6 @@ import type { ImageConfigComplete } from '../shared/lib/image-config'
import { hasMatch } from '../shared/lib/match-remote-pattern'
import type { NextConfigComplete } from './config-shared'
import { createRequestResponseMocks } from './lib/mock-request'
// Do not import anything other than types from this module
// because it will throw an error when using `outputFileTracing`
// as `jest-worker` is ignored in file tracing. Use `await import`
// or `require` instead.
import type { Operation } from './lib/squoosh/main'
import type { NextUrlWithParsedQuery } from './request-meta'
import type {
IncrementalCacheEntry,
@ -28,6 +22,7 @@ import type {
import { sendEtagResponse } from './send-payload'
import { getContentType, getExtension } from './serve-static'
import * as Log from '../build/output/log'
import isError from '../lib/is-error'
type XCacheHeader = 'MISS' | 'HIT' | 'STALE'
@ -44,10 +39,10 @@ const VECTOR_TYPES = [SVG]
const BLUR_IMG_SIZE = 8 // should match `next-image-loader`
const BLUR_QUALITY = 70 // should match `next-image-loader`
let sharp: typeof import('sharp') | undefined
let sharp: typeof import('sharp')
try {
sharp = require(process.env.NEXT_SHARP_PATH || 'sharp')
sharp = require('sharp')
if (sharp && sharp.concurrency() > 1) {
// Reducing concurrency should reduce the memory usage too.
// We more aggressively reduce in dev but also reduce in prod.
@ -55,12 +50,15 @@ try {
const divisor = process.env.NODE_ENV === 'development' ? 4 : 2
sharp.concurrency(Math.floor(Math.max(cpus().length / divisor, 1)))
}
} catch (e) {
// Sharp not present on the server, Squoosh fallback will be used
} catch (e: unknown) {
if (isError(e) && e.code === 'MODULE_NOT_FOUND') {
throw new Error(
'Module `sharp` not found. Please run `npm install --cpu=wasm32 sharp` to install it.'
)
}
throw e
}
let showSharpMissingWarning = process.env.NODE_ENV === 'production'
export interface ImageParamsResult {
href: string
isAbsolute: boolean
@ -418,7 +416,6 @@ export async function optimizeImage({
quality,
width,
height,
nextConfigOutput,
}: {
buffer: Buffer
contentType: string
@ -428,99 +425,38 @@ export async function optimizeImage({
nextConfigOutput?: 'standalone' | 'export'
}): Promise<Buffer> {
let optimizedBuffer = buffer
if (sharp) {
// Begin sharp transformation logic
const transformer = sharp(buffer, {
sequentialRead: true,
})
transformer.rotate()
// Begin sharp transformation logic
const transformer = sharp(buffer, {
sequentialRead: true,
})
if (height) {
transformer.resize(width, height)
} else {
transformer.resize(width, undefined, {
withoutEnlargement: true,
})
}
transformer.rotate()
if (contentType === AVIF) {
if (transformer.avif) {
const avifQuality = quality - 15
transformer.avif({
quality: Math.max(avifQuality, 0),
chromaSubsampling: '4:2:0', // same as webp
})
} else {
Log.warnOnce(
`Your installed version of the 'sharp' package does not support AVIF images. Run 'npm i sharp@latest' to upgrade to the latest version.\n` +
'Read more: https://nextjs.org/docs/messages/sharp-version-avif'
)
transformer.webp({ quality })
}
} else if (contentType === WEBP) {
transformer.webp({ quality })
} else if (contentType === PNG) {
transformer.png({ quality })
} else if (contentType === JPEG) {
transformer.jpeg({ quality, progressive: true })
}
optimizedBuffer = await transformer.toBuffer()
// End sharp transformation logic
if (height) {
transformer.resize(width, height)
} else {
if (showSharpMissingWarning && nextConfigOutput === 'standalone') {
Log.error(
`Error: 'sharp' is required to be installed in standalone mode for the image optimization to function correctly. Read more at: https://nextjs.org/docs/messages/sharp-missing-in-production`
)
throw new ImageError(500, 'Internal Server Error')
}
// Show sharp warning in production once
if (showSharpMissingWarning) {
Log.warnOnce(
`For production Image Optimization with Next.js, the optional 'sharp' package is strongly recommended. Run 'npm i sharp', and Next.js will use it automatically for Image Optimization.\n` +
'Read more: https://nextjs.org/docs/messages/sharp-missing-in-production'
)
showSharpMissingWarning = false
}
// Begin Squoosh transformation logic
const orientation = await getOrientation(buffer)
const operations: Operation[] = []
if (orientation === Orientation.RIGHT_TOP) {
operations.push({ type: 'rotate', numRotations: 1 })
} else if (orientation === Orientation.BOTTOM_RIGHT) {
operations.push({ type: 'rotate', numRotations: 2 })
} else if (orientation === Orientation.LEFT_BOTTOM) {
operations.push({ type: 'rotate', numRotations: 3 })
} else {
// TODO: support more orientations
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// const _: never = orientation
}
if (height) {
operations.push({ type: 'resize', width, height })
} else {
operations.push({ type: 'resize', width })
}
const { processBuffer } =
require('./lib/squoosh/main') as typeof import('./lib/squoosh/main')
if (contentType === AVIF) {
optimizedBuffer = await processBuffer(buffer, operations, 'avif', quality)
} else if (contentType === WEBP) {
optimizedBuffer = await processBuffer(buffer, operations, 'webp', quality)
} else if (contentType === PNG) {
optimizedBuffer = await processBuffer(buffer, operations, 'png', quality)
} else if (contentType === JPEG) {
optimizedBuffer = await processBuffer(buffer, operations, 'jpeg', quality)
}
transformer.resize(width, undefined, {
withoutEnlargement: true,
})
}
if (contentType === AVIF) {
const avifQuality = quality - 15
transformer.avif({
quality: Math.max(avifQuality, 0),
chromaSubsampling: '4:2:0', // same as webp
})
} else if (contentType === WEBP) {
transformer.webp({ quality })
} else if (contentType === PNG) {
transformer.png({ quality })
} else if (contentType === JPEG) {
transformer.jpeg({ quality, progressive: true })
}
optimizedBuffer = await transformer.toBuffer()
return optimizedBuffer
}
@ -667,12 +603,10 @@ export async function imageOptimizer(
})
if (optimizedBuffer) {
if (isDev && width <= BLUR_IMG_SIZE && quality === BLUR_QUALITY) {
const { getMetadata } =
require('./lib/squoosh/main') as typeof import('./lib/squoosh/main')
// During `next dev`, we don't want to generate blur placeholders with webpack
// because it can delay starting the dev server. Instead, `next-image-loader.js`
// will inline a special url to lazily generate the blur placeholder at request time.
const meta = await getMetadata(optimizedBuffer)
const meta = await getImageSize(optimizedBuffer)
const opts = {
blurWidth: meta.width,
blurHeight: meta.height,
@ -794,29 +728,10 @@ export function sendResponse(
}
}
export async function getImageSize(
buffer: Buffer,
// Should match VALID_BLUR_EXT
extension: 'avif' | 'webp' | 'png' | 'jpeg'
): Promise<{
export async function getImageSize(buffer: Buffer): Promise<{
width?: number
height?: number
}> {
// TODO: upgrade "image-size" package to support AVIF
// See https://github.com/image-size/image-size/issues/348
if (extension === 'avif') {
if (sharp) {
const transformer = sharp(buffer)
const { width, height } = await transformer.metadata()
return { width, height }
} else {
const { decodeBuffer } =
require('./lib/squoosh/main') as typeof import('./lib/squoosh/main')
const { width, height } = await decodeBuffer(buffer)
return { width, height }
}
}
const { width, height } = imageSizeOf(buffer)
return { width, height }
}

View file

@ -1,3 +0,0 @@
@timneutkens:notify
@ijjk:notify
@shuding:notify

View file

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,32 +0,0 @@
// eslint-disable-next-line no-shadow
export const enum AVIFTune {
auto,
psnr,
ssim,
}
export interface EncodeOptions {
cqLevel: number
denoiseLevel: number
cqAlphaLevel: number
tileRowsLog2: number
tileColsLog2: number
speed: number
subsample: number
chromaDeltaQ: boolean
sharpness: number
tune: AVIFTune
}
export interface AVIFModule extends EmscriptenWasm.Module {
encode(
data: BufferSource,
width: number,
height: number,
options: EncodeOptions
): Uint8Array
}
declare var moduleFactory: EmscriptenWasm.ModuleFactory<AVIFModule>
export default moduleFactory

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,374 +0,0 @@
import { promises as fsp } from 'fs'
import * as path from 'path'
import { instantiateEmscriptenWasm, pathify } from './emscripten-utils.js'
interface DecodeModule extends EmscriptenWasm.Module {
decode: (data: Uint8Array) => ImageData
}
type DecodeModuleFactory = EmscriptenWasm.ModuleFactory<DecodeModule>
interface RotateModuleInstance {
exports: {
memory: WebAssembly.Memory
rotate(width: number, height: number, rotate: number): void
}
}
interface ResizeWithAspectParams {
input_width: number
input_height: number
target_width?: number
target_height?: number
}
export interface ResizeOptions {
width?: number
height?: number
method: 'triangle' | 'catrom' | 'mitchell' | 'lanczos3'
premultiply: boolean
linearRGB: boolean
}
export interface RotateOptions {
numRotations: number
}
// MozJPEG
import type { MozJPEGModule as MozJPEGEncodeModule } from './mozjpeg/mozjpeg_enc'
// @ts-ignore
import mozEnc from './mozjpeg/mozjpeg_node_enc.js'
const mozEncWasm = path.resolve(__dirname, './mozjpeg/mozjpeg_node_enc.wasm')
// @ts-ignore
import mozDec from './mozjpeg/mozjpeg_node_dec.js'
const mozDecWasm = path.resolve(__dirname, './mozjpeg/mozjpeg_node_dec.wasm')
// WebP
import type { WebPModule as WebPEncodeModule } from './webp/webp_enc'
// @ts-ignore
import webpEnc from './webp/webp_node_enc.js'
const webpEncWasm = path.resolve(__dirname, './webp/webp_node_enc.wasm')
// @ts-ignore
import webpDec from './webp/webp_node_dec.js'
const webpDecWasm = path.resolve(__dirname, './webp/webp_node_dec.wasm')
// AVIF
import type { AVIFModule as AVIFEncodeModule } from './avif/avif_enc'
// @ts-ignore
import avifEnc from './avif/avif_node_enc.js'
const avifEncWasm = path.resolve(__dirname, './avif/avif_node_enc.wasm')
// @ts-ignore
import avifDec from './avif/avif_node_dec.js'
const avifDecWasm = path.resolve(__dirname, './avif/avif_node_dec.wasm')
// PNG
// @ts-ignore
import * as pngEncDec from './png/squoosh_png.js'
const pngEncDecWasm = path.resolve(__dirname, './png/squoosh_png_bg.wasm')
const pngEncDecInit = () =>
pngEncDec.default(fsp.readFile(pathify(pngEncDecWasm)))
// OxiPNG
// @ts-ignore
import * as oxipng from './png/squoosh_oxipng.js'
const oxipngWasm = path.resolve(__dirname, './png/squoosh_oxipng_bg.wasm')
const oxipngInit = () => oxipng.default(fsp.readFile(pathify(oxipngWasm)))
// Resize
// @ts-ignore
import * as resize from './resize/squoosh_resize.js'
const resizeWasm = path.resolve(__dirname, './resize/squoosh_resize_bg.wasm')
const resizeInit = () => resize.default(fsp.readFile(pathify(resizeWasm)))
// rotate
const rotateWasm = path.resolve(__dirname, './rotate/rotate.wasm')
// Our decoders currently rely on a `ImageData` global.
import ImageData from './image_data'
;(globalThis as any).ImageData = ImageData
function resizeNameToIndex(
name: 'triangle' | 'catrom' | 'mitchell' | 'lanczos3'
) {
switch (name) {
case 'triangle':
return 0
case 'catrom':
return 1
case 'mitchell':
return 2
case 'lanczos3':
return 3
default:
throw Error(`Unknown resize algorithm "${name}"`)
}
}
function resizeWithAspect({
input_width,
input_height,
target_width,
target_height,
}: ResizeWithAspectParams): { width: number; height: number } {
if (!target_width && !target_height) {
throw Error('Need to specify at least width or height when resizing')
}
if (target_width && target_height) {
return { width: target_width, height: target_height }
}
if (!target_width) {
return {
width: Math.round((input_width / input_height) * target_height!),
height: target_height!,
}
}
return {
width: target_width,
height: Math.round((input_height / input_width) * target_width),
}
}
export const preprocessors = {
resize: {
name: 'Resize',
description: 'Resize the image before compressing',
instantiate: async () => {
await resizeInit()
return (
buffer: Uint8Array,
input_width: number,
input_height: number,
{ width, height, method, premultiply, linearRGB }: ResizeOptions
) => {
;({ width, height } = resizeWithAspect({
input_width,
input_height,
target_width: width,
target_height: height,
}))
const imageData = new ImageData(
resize.resize(
buffer,
input_width,
input_height,
width,
height,
resizeNameToIndex(method),
premultiply,
linearRGB
),
width,
height
)
resize.cleanup()
return imageData
}
},
defaultOptions: {
method: 'lanczos3',
fitMethod: 'stretch',
premultiply: true,
linearRGB: true,
},
},
rotate: {
name: 'Rotate',
description: 'Rotate image',
instantiate: async () => {
return async (
buffer: Uint8Array,
width: number,
height: number,
{ numRotations }: RotateOptions
) => {
const degrees = (numRotations * 90) % 360
const sameDimensions = degrees === 0 || degrees === 180
const size = width * height * 4
const instance = (
await WebAssembly.instantiate(await fsp.readFile(pathify(rotateWasm)))
).instance as RotateModuleInstance
const { memory } = instance.exports
const additionalPagesNeeded = Math.ceil(
(size * 2 - memory.buffer.byteLength + 8) / (64 * 1024)
)
if (additionalPagesNeeded > 0) {
memory.grow(additionalPagesNeeded)
}
const view = new Uint8ClampedArray(memory.buffer)
view.set(buffer, 8)
instance.exports.rotate(width, height, degrees)
return new ImageData(
view.slice(size + 8, size * 2 + 8),
sameDimensions ? width : height,
sameDimensions ? height : width
)
}
},
defaultOptions: {
numRotations: 0,
},
},
} as const
export const codecs = {
mozjpeg: {
name: 'MozJPEG',
extension: 'jpg',
detectors: [/^\xFF\xD8\xFF/],
dec: () =>
instantiateEmscriptenWasm(mozDec as DecodeModuleFactory, mozDecWasm),
enc: () =>
instantiateEmscriptenWasm(
mozEnc as EmscriptenWasm.ModuleFactory<MozJPEGEncodeModule>,
mozEncWasm
),
defaultEncoderOptions: {
quality: 75,
baseline: false,
arithmetic: false,
progressive: true,
optimize_coding: true,
smoothing: 0,
color_space: 3 /*YCbCr*/,
quant_table: 3,
trellis_multipass: false,
trellis_opt_zero: false,
trellis_opt_table: false,
trellis_loops: 1,
auto_subsample: true,
chroma_subsample: 2,
separate_chroma_quality: false,
chroma_quality: 75,
},
autoOptimize: {
option: 'quality',
min: 0,
max: 100,
},
},
webp: {
name: 'WebP',
extension: 'webp',
detectors: [/^RIFF....WEBPVP8[LX ]/s],
dec: () =>
instantiateEmscriptenWasm(webpDec as DecodeModuleFactory, webpDecWasm),
enc: () =>
instantiateEmscriptenWasm(
webpEnc as EmscriptenWasm.ModuleFactory<WebPEncodeModule>,
webpEncWasm
),
defaultEncoderOptions: {
quality: 75,
target_size: 0,
target_PSNR: 0,
method: 4,
sns_strength: 50,
filter_strength: 60,
filter_sharpness: 0,
filter_type: 1,
partitions: 0,
segments: 4,
pass: 1,
show_compressed: 0,
preprocessing: 0,
autofilter: 0,
partition_limit: 0,
alpha_compression: 1,
alpha_filtering: 1,
alpha_quality: 100,
lossless: 0,
exact: 0,
image_hint: 0,
emulate_jpeg_size: 0,
thread_level: 0,
low_memory: 0,
near_lossless: 100,
use_delta_palette: 0,
use_sharp_yuv: 0,
},
autoOptimize: {
option: 'quality',
min: 0,
max: 100,
},
},
avif: {
name: 'AVIF',
extension: 'avif',
// eslint-disable-next-line no-control-regex
detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
dec: () =>
instantiateEmscriptenWasm(avifDec as DecodeModuleFactory, avifDecWasm),
enc: async () => {
return instantiateEmscriptenWasm(
avifEnc as EmscriptenWasm.ModuleFactory<AVIFEncodeModule>,
avifEncWasm
)
},
defaultEncoderOptions: {
cqLevel: 33,
cqAlphaLevel: -1,
denoiseLevel: 0,
tileColsLog2: 0,
tileRowsLog2: 0,
speed: 6,
subsample: 1,
chromaDeltaQ: false,
sharpness: 0,
tune: 0 /* AVIFTune.auto */,
},
autoOptimize: {
option: 'cqLevel',
min: 62,
max: 0,
},
},
oxipng: {
name: 'OxiPNG',
extension: 'png',
// eslint-disable-next-line no-control-regex
detectors: [/^\x89PNG\x0D\x0A\x1A\x0A/],
dec: async () => {
await pngEncDecInit()
return {
decode: (buffer: Buffer | Uint8Array) => {
const imageData = pngEncDec.decode(buffer)
pngEncDec.cleanup()
return imageData
},
}
},
enc: async () => {
await pngEncDecInit()
await oxipngInit()
return {
encode: (
buffer: Uint8ClampedArray | ArrayBuffer,
width: number,
height: number,
opts: { level: number }
) => {
const simplePng = pngEncDec.encode(
new Uint8Array(buffer),
width,
height
)
const imageData = oxipng.optimise(simplePng, opts.level, false)
oxipng.cleanup()
return imageData
},
}
},
defaultEncoderOptions: {
level: 2,
},
autoOptimize: {
option: 'level',
min: 6,
max: 1,
},
},
} as const

View file

@ -1,121 +0,0 @@
// These types roughly model the object that the JS files generated by Emscripten define. Copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten/index.d.ts and turned into a type definition rather than a global to support our way of using Emscripten.
declare namespace EmscriptenWasm {
type ModuleFactory<T extends Module = Module> = (
moduleOverrides?: ModuleOpts
) => Promise<T>
type EnvironmentType = 'WEB' | 'NODE' | 'SHELL' | 'WORKER'
// Options object for modularized Emscripten files. Shoe-horned by @surma.
// FIXME: This an incomplete definition!
interface ModuleOpts {
mainScriptUrlOrBlob?: string
noInitialRun?: boolean
locateFile?: (url: string) => string
onRuntimeInitialized?: () => void
}
interface Module {
print(str: string): void
printErr(str: string): void
arguments: string[]
environment: EnvironmentType
preInit: { (): void }[]
preRun: { (): void }[]
postRun: { (): void }[]
preinitializedWebGLContext: WebGLRenderingContext
noInitialRun: boolean
noExitRuntime: boolean
logReadFiles: boolean
filePackagePrefixURL: string
wasmBinary: ArrayBuffer
destroy(object: object): void
getPreloadedPackage(
remotePackageName: string,
remotePackageSize: number
): ArrayBuffer
instantiateWasm(
imports: WebAssembly.Imports,
successCallback: (module: WebAssembly.Module) => void
): WebAssembly.Exports
locateFile(url: string): string
onCustomMessage(event: MessageEvent): void
Runtime: any
ccall(
ident: string,
returnType: string | null,
argTypes: string[],
args: any[]
): any
cwrap(ident: string, returnType: string | null, argTypes: string[]): any
setValue(ptr: number, value: any, type: string, noSafe?: boolean): void
getValue(ptr: number, type: string, noSafe?: boolean): number
ALLOC_NORMAL: number
ALLOC_STACK: number
ALLOC_STATIC: number
ALLOC_DYNAMIC: number
ALLOC_NONE: number
allocate(slab: any, types: string, allocator: number, ptr: number): number
allocate(slab: any, types: string[], allocator: number, ptr: number): number
Pointer_stringify(ptr: number, length?: number): string
UTF16ToString(ptr: number): string
stringToUTF16(str: string, outPtr: number): void
UTF32ToString(ptr: number): string
stringToUTF32(str: string, outPtr: number): void
// USE_TYPED_ARRAYS == 1
HEAP: Int32Array
IHEAP: Int32Array
FHEAP: Float64Array
// USE_TYPED_ARRAYS == 2
HEAP8: Int8Array
HEAP16: Int16Array
HEAP32: Int32Array
HEAPU8: Uint8Array
HEAPU16: Uint16Array
HEAPU32: Uint32Array
HEAPF32: Float32Array
HEAPF64: Float64Array
TOTAL_STACK: number
TOTAL_MEMORY: number
FAST_MEMORY: number
addOnPreRun(cb: () => any): void
addOnInit(cb: () => any): void
addOnPreMain(cb: () => any): void
addOnExit(cb: () => any): void
addOnPostRun(cb: () => any): void
// Tools
intArrayFromString(
stringy: string,
dontAddNull?: boolean,
length?: number
): number[]
intArrayToString(array: number[]): string
writeStringToMemory(str: string, buffer: number, dontAddNull: boolean): void
writeArrayToMemory(array: number[], buffer: number): void
writeAsciiToMemory(str: string, buffer: number, dontAddNull: boolean): void
addRunDependency(id: any): void
removeRunDependency(id: any): void
preloadedImages: any
preloadedAudios: any
_malloc(size: number): number
_free(ptr: number): void
// Augmentations below by @surma.
onRuntimeInitialized: () => void | null
}
}

View file

@ -1,26 +0,0 @@
import { fileURLToPath } from 'url'
export function pathify(path: string): string {
if (path.startsWith('file://')) {
path = fileURLToPath(path)
}
return path
}
export function instantiateEmscriptenWasm<T extends EmscriptenWasm.Module>(
factory: EmscriptenWasm.ModuleFactory<T>,
path: string,
workerJS: string = ''
): Promise<T> {
return factory({
locateFile(requestPath) {
// The glue code generated by emscripten uses the original
// file names of the worker file and the wasm binary.
// These will have changed in the bundling process and
// we need to inject them here.
if (requestPath.endsWith('.wasm')) return pathify(path)
if (requestPath.endsWith('.worker.js')) return pathify(workerJS)
return requestPath
},
})
}

View file

@ -1,33 +0,0 @@
export default class ImageData {
static from(input: ImageData): ImageData {
return new ImageData(input.data || input._data, input.width, input.height)
}
private _data: Buffer | Uint8Array | Uint8ClampedArray
width: number
height: number
get data(): Buffer {
if (Object.prototype.toString.call(this._data) === '[object Object]') {
return Buffer.from(Object.values(this._data))
}
if (
this._data instanceof Buffer ||
this._data instanceof Uint8Array ||
this._data instanceof Uint8ClampedArray
) {
return Buffer.from(this._data)
}
throw new Error('invariant')
}
constructor(
data: Buffer | Uint8Array | Uint8ClampedArray,
width: number,
height: number
) {
this._data = data
this.width = width
this.height = height
}
}

View file

@ -1,113 +0,0 @@
import { codecs as supportedFormats, preprocessors } from './codecs'
import ImageData from './image_data'
type EncoderKey = keyof typeof supportedFormats
export async function decodeBuffer(
_buffer: Buffer | Uint8Array
): Promise<ImageData> {
const buffer = Buffer.from(_buffer)
const firstChunk = buffer.slice(0, 16)
const firstChunkString = Array.from(firstChunk)
.map((v) => String.fromCodePoint(v))
.join('')
const key = Object.entries(supportedFormats).find(([, { detectors }]) =>
detectors.some((detector) => detector.exec(firstChunkString))
)?.[0] as EncoderKey | undefined
if (!key) {
throw Error(`Buffer has an unsupported format`)
}
const encoder = supportedFormats[key]
const mod = await encoder.dec()
const rgba = mod.decode(new Uint8Array(buffer))
return rgba
}
export async function rotate(
image: ImageData,
numRotations: number
): Promise<ImageData> {
image = ImageData.from(image)
const m = await preprocessors['rotate'].instantiate()
return await m(image.data, image.width, image.height, { numRotations })
}
type ResizeOpts = { image: ImageData } & (
| { width: number; height?: never }
| { height: number; width?: never }
| { height: number; width: number }
)
export async function resize({ image, width, height }: ResizeOpts) {
image = ImageData.from(image)
const p = preprocessors['resize']
const m = await p.instantiate()
return await m(image.data, image.width, image.height, {
...p.defaultOptions,
width,
height,
})
}
export async function encodeJpeg(
image: ImageData,
{ quality }: { quality: number }
): Promise<Buffer | Uint8Array> {
image = ImageData.from(image)
const e = supportedFormats['mozjpeg']
const m = await e.enc()
const r = await m.encode(image.data, image.width, image.height, {
...e.defaultEncoderOptions,
quality,
})
return Buffer.from(r)
}
export async function encodeWebp(
image: ImageData,
{ quality }: { quality: number }
): Promise<Buffer | Uint8Array> {
image = ImageData.from(image)
const e = supportedFormats['webp']
const m = await e.enc()
const r = await m.encode(image.data, image.width, image.height, {
...e.defaultEncoderOptions,
quality,
})
return Buffer.from(r)
}
export async function encodeAvif(
image: ImageData,
{ quality }: { quality: number }
): Promise<Buffer | Uint8Array> {
image = ImageData.from(image)
const e = supportedFormats['avif']
const m = await e.enc()
const val = e.autoOptimize.min || 62
const r = await m.encode(image.data, image.width, image.height, {
...e.defaultEncoderOptions,
// Think of cqLevel as the "amount" of quantization (0 to 62),
// so a lower value yields higher quality (0 to 100).
cqLevel: Math.round(val - (quality / 100) * val),
})
return Buffer.from(r)
}
export async function encodePng(
image: ImageData
): Promise<Buffer | Uint8Array> {
image = ImageData.from(image)
const e = supportedFormats['oxipng']
const m = await e.enc()
const r = await m.encode(image.data, image.width, image.height, {
...e.defaultEncoderOptions,
})
return Buffer.from(r)
}

View file

@ -1,97 +0,0 @@
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 }
| { width: number; height: number }
)
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 getMetadata(
buffer: Buffer
): Promise<{ width: number; height: number }> {
const worker: typeof import('./impl') = getWorker() as any
const { width, height } = await worker.decodeBuffer(buffer)
return { width, height }
}
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') {
const opt = { image: imageData, width: 0, height: 0 }
if (
operation.width &&
imageData.width &&
imageData.width > operation.width
) {
opt.width = operation.width
}
if (
operation.height &&
imageData.height &&
imageData.height > operation.height
) {
opt.height = operation.height
}
if (opt.width > 0 || opt.height > 0) {
imageData = await worker.resize(opt)
}
}
}
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
}

View file

@ -1,38 +0,0 @@
// eslint-disable-next-line no-shadow
export const enum MozJpegColorSpace {
GRAYSCALE = 1,
RGB,
YCbCr,
}
export interface EncodeOptions {
quality: number
baseline: boolean
arithmetic: boolean
progressive: boolean
optimize_coding: boolean
smoothing: number
color_space: MozJpegColorSpace
quant_table: number
trellis_multipass: boolean
trellis_opt_zero: boolean
trellis_opt_table: boolean
trellis_loops: number
auto_subsample: boolean
chroma_subsample: number
separate_chroma_quality: boolean
chroma_quality: number
}
export interface MozJPEGModule extends EmscriptenWasm.Module {
encode(
data: BufferSource,
width: number,
height: number,
options: EncodeOptions
): Uint8Array
}
declare var moduleFactory: EmscriptenWasm.ModuleFactory<MozJPEGModule>
export default moduleFactory

View file

@ -1,119 +0,0 @@
let wasm
let cachedTextDecoder = new TextDecoder('utf-8', {
ignoreBOM: true,
fatal: true,
})
cachedTextDecoder.decode()
let cachegetUint8Memory0 = null
function getUint8Memory0() {
if (
cachegetUint8Memory0 === null ||
cachegetUint8Memory0.buffer !== wasm.memory.buffer
) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer)
}
return cachegetUint8Memory0
}
function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len))
}
let WASM_VECTOR_LEN = 0
function passArray8ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 1)
getUint8Memory0().set(arg, ptr / 1)
WASM_VECTOR_LEN = arg.length
return ptr
}
let cachegetInt32Memory0 = null
function getInt32Memory0() {
if (
cachegetInt32Memory0 === null ||
cachegetInt32Memory0.buffer !== wasm.memory.buffer
) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer)
}
return cachegetInt32Memory0
}
function getArrayU8FromWasm0(ptr, len) {
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len)
}
/**
* @param {Uint8Array} data
* @param {number} level
* @param {boolean} interlace
* @returns {Uint8Array}
*/
export function optimise(data, level, interlace) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16)
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc)
var len0 = WASM_VECTOR_LEN
wasm.optimise(retptr, ptr0, len0, level, interlace)
var r0 = getInt32Memory0()[retptr / 4 + 0]
var r1 = getInt32Memory0()[retptr / 4 + 1]
var v1 = getArrayU8FromWasm0(r0, r1).slice()
wasm.__wbindgen_free(r0, r1 * 1)
return v1
} finally {
wasm.__wbindgen_add_to_stack_pointer(16)
}
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
return await WebAssembly.instantiateStreaming(module, imports)
}
const bytes = await module.arrayBuffer()
return await WebAssembly.instantiate(bytes, imports)
} else {
const instance = await WebAssembly.instantiate(module, imports)
if (instance instanceof WebAssembly.Instance) {
return { instance, module }
} else {
return instance
}
}
}
async function init(input) {
const imports = {}
imports.wbg = {}
imports.wbg.__wbindgen_throw = function (arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1))
}
if (
typeof input === 'string' ||
(typeof Request === 'function' && input instanceof Request) ||
(typeof URL === 'function' && input instanceof URL)
) {
input = fetch(input)
}
const { instance, module } = await load(await input, imports)
wasm = instance.exports
init.__wbindgen_wasm_module = module
return wasm
}
export default init
// Manually remove the wasm and memory references to trigger GC
export function cleanup() {
wasm = null
cachegetUint8Memory0 = null
cachegetInt32Memory0 = null
}

View file

@ -1,183 +0,0 @@
let wasm
let cachedTextDecoder = new TextDecoder('utf-8', {
ignoreBOM: true,
fatal: true,
})
cachedTextDecoder.decode()
let cachegetUint8Memory0 = null
function getUint8Memory0() {
if (
cachegetUint8Memory0 === null ||
cachegetUint8Memory0.buffer !== wasm.memory.buffer
) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer)
}
return cachegetUint8Memory0
}
function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len))
}
let cachegetUint8ClampedMemory0 = null
function getUint8ClampedMemory0() {
if (
cachegetUint8ClampedMemory0 === null ||
cachegetUint8ClampedMemory0.buffer !== wasm.memory.buffer
) {
cachegetUint8ClampedMemory0 = new Uint8ClampedArray(wasm.memory.buffer)
}
return cachegetUint8ClampedMemory0
}
function getClampedArrayU8FromWasm0(ptr, len) {
return getUint8ClampedMemory0().subarray(ptr / 1, ptr / 1 + len)
}
const heap = new Array(32).fill(undefined)
heap.push(undefined, null, true, false)
let heap_next = heap.length
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1)
const idx = heap_next
heap_next = heap[idx]
heap[idx] = obj
return idx
}
let WASM_VECTOR_LEN = 0
function passArray8ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 1)
getUint8Memory0().set(arg, ptr / 1)
WASM_VECTOR_LEN = arg.length
return ptr
}
let cachegetInt32Memory0 = null
function getInt32Memory0() {
if (
cachegetInt32Memory0 === null ||
cachegetInt32Memory0.buffer !== wasm.memory.buffer
) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer)
}
return cachegetInt32Memory0
}
function getArrayU8FromWasm0(ptr, len) {
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len)
}
/**
* @param {Uint8Array} data
* @param {number} width
* @param {number} height
* @returns {Uint8Array}
*/
export function encode(data, width, height) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16)
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc)
var len0 = WASM_VECTOR_LEN
wasm.encode(retptr, ptr0, len0, width, height)
var r0 = getInt32Memory0()[retptr / 4 + 0]
var r1 = getInt32Memory0()[retptr / 4 + 1]
var v1 = getArrayU8FromWasm0(r0, r1).slice()
wasm.__wbindgen_free(r0, r1 * 1)
return v1
} finally {
wasm.__wbindgen_add_to_stack_pointer(16)
}
}
function getObject(idx) {
return heap[idx]
}
function dropObject(idx) {
if (idx < 36) return
heap[idx] = heap_next
heap_next = idx
}
function takeObject(idx) {
const ret = getObject(idx)
dropObject(idx)
return ret
}
/**
* @param {Uint8Array} data
* @returns {ImageData}
*/
export function decode(data) {
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc)
var len0 = WASM_VECTOR_LEN
var ret = wasm.decode(ptr0, len0)
return takeObject(ret)
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
return await WebAssembly.instantiateStreaming(module, imports)
}
const bytes = await module.arrayBuffer()
return await WebAssembly.instantiate(bytes, imports)
} else {
const instance = await WebAssembly.instantiate(module, imports)
if (instance instanceof WebAssembly.Instance) {
return { instance, module }
} else {
return instance
}
}
}
async function init(input) {
const imports = {}
imports.wbg = {}
imports.wbg.__wbg_newwithownedu8clampedarrayandsh_787b2db8ea6bfd62 =
function (arg0, arg1, arg2, arg3) {
var v0 = getClampedArrayU8FromWasm0(arg0, arg1).slice()
wasm.__wbindgen_free(arg0, arg1 * 1)
var ret = new ImageData(v0, arg2 >>> 0, arg3 >>> 0)
return addHeapObject(ret)
}
imports.wbg.__wbindgen_throw = function (arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1))
}
if (
typeof input === 'string' ||
(typeof Request === 'function' && input instanceof Request) ||
(typeof URL === 'function' && input instanceof URL)
) {
input = fetch(input)
}
const { instance, module } = await load(await input, imports)
wasm = instance.exports
init.__wbindgen_wasm_module = module
return wasm
}
export default init
// Manually remove the wasm and memory references to trigger GC
export function cleanup() {
wasm = null
cachegetUint8ClampedMemory0 = null
cachegetUint8Memory0 = null
cachegetInt32Memory0 = null
}

View file

@ -1,140 +0,0 @@
let wasm
let cachegetUint8Memory0 = null
function getUint8Memory0() {
if (
cachegetUint8Memory0 === null ||
cachegetUint8Memory0.buffer !== wasm.memory.buffer
) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer)
}
return cachegetUint8Memory0
}
let WASM_VECTOR_LEN = 0
function passArray8ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 1)
getUint8Memory0().set(arg, ptr / 1)
WASM_VECTOR_LEN = arg.length
return ptr
}
let cachegetInt32Memory0 = null
function getInt32Memory0() {
if (
cachegetInt32Memory0 === null ||
cachegetInt32Memory0.buffer !== wasm.memory.buffer
) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer)
}
return cachegetInt32Memory0
}
let cachegetUint8ClampedMemory0 = null
function getUint8ClampedMemory0() {
if (
cachegetUint8ClampedMemory0 === null ||
cachegetUint8ClampedMemory0.buffer !== wasm.memory.buffer
) {
cachegetUint8ClampedMemory0 = new Uint8ClampedArray(wasm.memory.buffer)
}
return cachegetUint8ClampedMemory0
}
function getClampedArrayU8FromWasm0(ptr, len) {
return getUint8ClampedMemory0().subarray(ptr / 1, ptr / 1 + len)
}
/**
* @param {Uint8Array} input_image
* @param {number} input_width
* @param {number} input_height
* @param {number} output_width
* @param {number} output_height
* @param {number} typ_idx
* @param {boolean} premultiply
* @param {boolean} color_space_conversion
* @returns {Uint8ClampedArray}
*/
export function resize(
input_image,
input_width,
input_height,
output_width,
output_height,
typ_idx,
premultiply,
color_space_conversion
) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16)
var ptr0 = passArray8ToWasm0(input_image, wasm.__wbindgen_malloc)
var len0 = WASM_VECTOR_LEN
wasm.resize(
retptr,
ptr0,
len0,
input_width,
input_height,
output_width,
output_height,
typ_idx,
premultiply,
color_space_conversion
)
var r0 = getInt32Memory0()[retptr / 4 + 0]
var r1 = getInt32Memory0()[retptr / 4 + 1]
var v1 = getClampedArrayU8FromWasm0(r0, r1).slice()
wasm.__wbindgen_free(r0, r1 * 1)
return v1
} finally {
wasm.__wbindgen_add_to_stack_pointer(16)
}
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
return await WebAssembly.instantiateStreaming(module, imports)
}
const bytes = await module.arrayBuffer()
return await WebAssembly.instantiate(bytes, imports)
} else {
const instance = await WebAssembly.instantiate(module, imports)
if (instance instanceof WebAssembly.Instance) {
return { instance, module }
} else {
return instance
}
}
}
async function init(input) {
const imports = {}
if (
typeof input === 'string' ||
(typeof Request === 'function' && input instanceof Request) ||
(typeof URL === 'function' && input instanceof URL)
) {
input = fetch(input)
}
const { instance, module } = await load(await input, imports)
wasm = instance.exports
init.__wbindgen_wasm_module = module
return wasm
}
export default init
// Manually remove the wasm and memory references to trigger GC
export function cleanup() {
wasm = null
cachegetUint8Memory0 = null
cachegetInt32Memory0 = null
}

View file

@ -1,42 +0,0 @@
export interface EncodeOptions {
quality: number
target_size: number
target_PSNR: number
method: number
sns_strength: number
filter_strength: number
filter_sharpness: number
filter_type: number
partitions: number
segments: number
pass: number
show_compressed: number
preprocessing: number
autofilter: number
partition_limit: number
alpha_compression: number
alpha_filtering: number
alpha_quality: number
lossless: number
exact: number
image_hint: number
emulate_jpeg_size: number
thread_level: number
low_memory: number
near_lossless: number
use_delta_palette: number
use_sharp_yuv: number
}
export interface WebPModule extends EmscriptenWasm.Module {
encode(
data: BufferSource,
width: number,
height: number,
options: EncodeOptions
): Uint8Array
}
declare var moduleFactory: EmscriptenWasm.ModuleFactory<WebPModule>
export default moduleFactory

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -663,15 +663,6 @@ export async function ncc_image_size(task, opts) {
.target('src/compiled/image-size')
}
// eslint-disable-next-line camelcase
externals['get-orientation'] = 'next/dist/compiled/get-orientation'
export async function ncc_get_orientation(task, opts) {
await task
.source(relative(__dirname, require.resolve('get-orientation')))
.ncc({ packageName: 'get-orientation', externals })
.target('src/compiled/get-orientation')
}
// eslint-disable-next-line camelcase
externals['@hapi/accept'] = 'next/dist/compiled/@hapi/accept'
export async function ncc_hapi_accept(task, opts) {
@ -2180,7 +2171,6 @@ export async function ncc(task, opts) {
'ncc_p_limit',
'ncc_raw_body',
'ncc_image_size',
'ncc_get_orientation',
'ncc_hapi_accept',
'ncc_commander',
'ncc_node_fetch',

View file

@ -94,11 +94,6 @@ declare module 'next/dist/compiled/@hapi/accept' {
export = m
}
declare module 'next/dist/compiled/get-orientation' {
import m from 'get-orientation'
export = m
}
declare module 'next/dist/compiled/acorn' {
import m from 'acorn'
export = m

View file

@ -170,9 +170,6 @@ importers:
'@types/selenium-webdriver':
specifier: 4.0.15
version: 4.0.15
'@types/sharp':
specifier: 0.29.3
version: 0.29.3
'@types/string-hash':
specifier: 1.1.1
version: 1.1.1
@ -321,8 +318,8 @@ importers:
specifier: 8.0.0
version: 8.0.0
image-size:
specifier: 0.9.3
version: 0.9.3
specifier: 1.1.1
version: 1.1.1
is-animated:
specifier: 2.0.2
version: 2.0.2
@ -838,6 +835,10 @@ importers:
styled-jsx:
specifier: 5.1.1
version: 5.1.1(@babel/core@7.22.5)(react@18.2.0)
optionalDependencies:
sharp:
specifier: ^0.33.3
version: 0.33.3
devDependencies:
'@ampproject/toolbox-optimizer':
specifier: 2.8.3
@ -1181,9 +1182,6 @@ importers:
fresh:
specifier: 0.5.2
version: 0.5.2
get-orientation:
specifier: 1.1.2
version: 1.1.2
glob:
specifier: 7.1.7
version: 7.1.7
@ -1209,8 +1207,8 @@ importers:
specifier: 0.1.2
version: 0.1.2
image-size:
specifier: 1.0.0
version: 1.0.0
specifier: 1.1.1
version: 1.1.1
is-docker:
specifier: 2.0.0
version: 2.0.0
@ -3579,6 +3577,14 @@ packages:
'@edge-runtime/primitives': 4.1.0
dev: true
/@emnapi/runtime@1.1.1:
resolution: {integrity: sha512-3bfqkzuR1KLx57nZfjr2NLnFOobvyS0aTszaEGCGqmYMVDRaGvgIZbjGSV/MHSSmLgQ/b9JFHQ5xm5WRZYd+XQ==}
requiresBuild: true
dependencies:
tslib: 2.6.2
dev: false
optional: true
/@emotion/babel-plugin@11.11.0:
resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
dependencies:
@ -4109,6 +4115,194 @@ packages:
resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
dev: true
/@img/sharp-darwin-arm64@0.33.3:
resolution: {integrity: sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.0.2
dev: false
optional: true
/@img/sharp-darwin-x64@0.33.3:
resolution: {integrity: sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [darwin]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-darwin-x64': 1.0.2
dev: false
optional: true
/@img/sharp-libvips-darwin-arm64@1.0.2:
resolution: {integrity: sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==}
engines: {macos: '>=11', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-darwin-x64@1.0.2:
resolution: {integrity: sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==}
engines: {macos: '>=10.13', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-arm64@1.0.2:
resolution: {integrity: sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==}
engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-arm@1.0.2:
resolution: {integrity: sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==}
engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-s390x@1.0.2:
resolution: {integrity: sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==}
engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-x64@1.0.2:
resolution: {integrity: sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==}
engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linuxmusl-arm64@1.0.2:
resolution: {integrity: sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==}
engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linuxmusl-x64@1.0.2:
resolution: {integrity: sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==}
engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-linux-arm64@0.33.3:
resolution: {integrity: sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-arm64': 1.0.2
dev: false
optional: true
/@img/sharp-linux-arm@0.33.3:
resolution: {integrity: sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==}
engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.0.2
dev: false
optional: true
/@img/sharp-linux-s390x@0.33.3:
resolution: {integrity: sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==}
engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [s390x]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-s390x': 1.0.2
dev: false
optional: true
/@img/sharp-linux-x64@0.33.3:
resolution: {integrity: sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.0.2
dev: false
optional: true
/@img/sharp-linuxmusl-arm64@0.33.3:
resolution: {integrity: sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==}
engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linuxmusl-arm64': 1.0.2
dev: false
optional: true
/@img/sharp-linuxmusl-x64@0.33.3:
resolution: {integrity: sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==}
engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linuxmusl-x64': 1.0.2
dev: false
optional: true
/@img/sharp-wasm32@0.33.3:
resolution: {integrity: sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [wasm32]
requiresBuild: true
dependencies:
'@emnapi/runtime': 1.1.1
dev: false
optional: true
/@img/sharp-win32-ia32@0.33.3:
resolution: {integrity: sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@img/sharp-win32-x64@0.33.3:
resolution: {integrity: sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@isaacs/cliui@8.0.2:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@ -7218,12 +7412,6 @@ packages:
'@types/node': 20.12.3
dev: true
/@types/sharp@0.29.3:
resolution: {integrity: sha512-83Xp05eK2hvfNnmKLr2Fz0C2A0jrr2TnSLqKRbkLTYuAu+Erj6mKQLoEMGafE73Om8p3q3ryZxtHFM/7hy4Adg==}
dependencies:
'@types/node': 20.12.3
dev: true
/@types/shell-quote@1.7.1:
resolution: {integrity: sha512-SWZ2Nom1pkyXCDohRSrkSKvDh8QOG9RfAsrt5/NsPQC4UQJ55eG0qClA40I+Gkez4KTQ0uDUT8ELRXThf3J5jw==}
dev: true
@ -7525,7 +7713,7 @@ packages:
'@typescript-eslint/types': 6.14.0
'@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3)
eslint: 8.56.0
semver: 7.5.4
semver: 7.6.0
transitivePeerDependencies:
- supports-color
- typescript
@ -9596,20 +9784,30 @@ packages:
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
/color-string@1.5.4:
resolution: {integrity: sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==}
/color-string@1.9.1:
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
requiresBuild: true
dependencies:
color-name: 1.1.4
simple-swizzle: 0.2.2
dev: true
/color@3.1.3:
resolution: {integrity: sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==}
dependencies:
color-convert: 1.9.3
color-string: 1.5.4
color-string: 1.9.1
dev: true
/color@4.2.3:
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
engines: {node: '>=12.5.0'}
requiresBuild: true
dependencies:
color-convert: 2.0.1
color-string: 1.9.1
dev: false
optional: true
/colord@2.9.3:
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
dev: true
@ -10935,6 +11133,13 @@ packages:
hasBin: true
dev: true
/detect-libc@2.0.3:
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
engines: {node: '>=8'}
requiresBuild: true
dev: false
optional: true
/detect-newline@3.1.0:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
engines: {node: '>=8'}
@ -13073,14 +13278,6 @@ packages:
has-proto: 1.0.1
has-symbols: 1.0.3
/get-orientation@1.1.2:
resolution: {integrity: sha512-/pViTfifW+gBbh/RnlFYHINvELT9Znt+SYyDKAUL6uV6By019AK/s+i9XP4jSwq7lwP38Fd8HVeTxym3+hkwmQ==}
dependencies:
stream-parser: 0.3.1
transitivePeerDependencies:
- supports-color
dev: true
/get-own-enumerable-property-symbols@3.0.2:
resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==}
dev: true
@ -14128,17 +14325,9 @@ packages:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
/image-size@0.9.3:
resolution: {integrity: sha512-5SakFa79uhUVSjKeQE30GVzzLJ0QNzB53+I+/VD1vIesD6GP6uatWIlgU0uisFNLt1u0d6kBydp7yfk+lLJhLQ==}
engines: {node: '>=10.18.0'}
hasBin: true
dependencies:
queue: 6.0.1
dev: true
/image-size@1.0.0:
resolution: {integrity: sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==}
engines: {node: '>=12.0.0'}
/image-size@1.1.1:
resolution: {integrity: sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==}
engines: {node: '>=16.x'}
hasBin: true
dependencies:
queue: 6.0.2
@ -14461,7 +14650,7 @@ packages:
/is-arrayish@0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
dev: true
requiresBuild: true
/is-async-function@2.0.0:
resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==}
@ -15089,7 +15278,7 @@ packages:
'@babel/parser': 7.22.5
'@istanbuljs/schema': 0.1.2
istanbul-lib-coverage: 3.2.0
semver: 7.5.4
semver: 7.6.0
transitivePeerDependencies:
- supports-color
dev: true
@ -15798,7 +15987,7 @@ packages:
jest-util: 29.7.0
natural-compare: 1.4.0
pretty-format: 29.7.0
semver: 7.5.4
semver: 7.6.0
transitivePeerDependencies:
- supports-color
dev: true
@ -21018,12 +21207,6 @@ packages:
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
/queue@6.0.1:
resolution: {integrity: sha512-AJBQabRCCNr9ANq8v77RJEv73DPbn55cdTb+Giq4X0AVnNVZvMHlYp7XlQiN+1npCZj1DuSmaA2hYVUUDgxFDg==}
dependencies:
inherits: 2.0.4
dev: true
/queue@6.0.2:
resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
dependencies:
@ -22372,6 +22555,14 @@ packages:
dependencies:
lru-cache: 6.0.0
/semver@7.6.0:
resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
engines: {node: '>=10'}
hasBin: true
requiresBuild: true
dependencies:
lru-cache: 6.0.0
/send@0.17.1:
resolution: {integrity: sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==}
engines: {node: '>= 0.8.0'}
@ -22478,6 +22669,37 @@ packages:
resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
dev: true
/sharp@0.33.3:
resolution: {integrity: sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==}
engines: {libvips: '>=8.15.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0}
requiresBuild: true
dependencies:
color: 4.2.3
detect-libc: 2.0.3
semver: 7.6.0
optionalDependencies:
'@img/sharp-darwin-arm64': 0.33.3
'@img/sharp-darwin-x64': 0.33.3
'@img/sharp-libvips-darwin-arm64': 1.0.2
'@img/sharp-libvips-darwin-x64': 1.0.2
'@img/sharp-libvips-linux-arm': 1.0.2
'@img/sharp-libvips-linux-arm64': 1.0.2
'@img/sharp-libvips-linux-s390x': 1.0.2
'@img/sharp-libvips-linux-x64': 1.0.2
'@img/sharp-libvips-linuxmusl-arm64': 1.0.2
'@img/sharp-libvips-linuxmusl-x64': 1.0.2
'@img/sharp-linux-arm': 0.33.3
'@img/sharp-linux-arm64': 0.33.3
'@img/sharp-linux-s390x': 0.33.3
'@img/sharp-linux-x64': 0.33.3
'@img/sharp-linuxmusl-arm64': 0.33.3
'@img/sharp-linuxmusl-x64': 0.33.3
'@img/sharp-wasm32': 0.33.3
'@img/sharp-win32-ia32': 0.33.3
'@img/sharp-win32-x64': 0.33.3
dev: false
optional: true
/shebang-command@1.2.0:
resolution: {integrity: sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=}
engines: {node: '>=0.10.0'}
@ -22534,9 +22756,9 @@ packages:
/simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
requiresBuild: true
dependencies:
is-arrayish: 0.3.2
dev: true
/sirv@1.0.10:
resolution: {integrity: sha512-H5EZCoZaggEUQy8ocKsF7WAToGuZhjJlLvM3XOef46CbdIgbNeQ1p32N1PCuCjkVYwrAVOSMacN6CXXgIzuspg==}
@ -22962,14 +23184,6 @@ packages:
xtend: 4.0.2
dev: true
/stream-parser@0.3.1:
resolution: {integrity: sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=}
dependencies:
debug: 2.6.9
transitivePeerDependencies:
- supports-color
dev: true
/streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}

View file

@ -82,7 +82,6 @@ async function main() {
'node_modules/next/dist/pages/**/*',
'node_modules/next/dist/server/image-optimizer.js',
'node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*',
'node_modules/next/dist/server/lib/squoosh/**/*.wasm',
'node_modules/next/dist/compiled/webpack/(bundle4|bundle5).js',
'node_modules/react/**/*.development.js',
'node_modules/react-dom/**/*.development.js',

View file

@ -1,29 +0,0 @@
import execa from 'execa'
import fs from 'fs-extra'
import { join } from 'path'
import { setupTests } from './util'
const appDir = join(__dirname, '../app')
const imagesDir = join(appDir, '.next', 'cache', 'images')
describe('with outdated sharp', () => {
beforeAll(async () => {
await fs.writeFile(
join(appDir, 'package.json'),
JSON.stringify({
packageManager: 'npm@10.2.5',
})
)
await execa('npm', ['add', 'sharp@0.26.3'], {
cwd: appDir,
stdio: 'inherit',
})
})
afterAll(async () => {
await fs.remove(join(appDir, 'node_modules'))
await fs.remove(join(appDir, 'package-lock.json'))
await fs.remove(join(appDir, 'package.json'))
})
setupTests({ isSharp: true, isOutdatedSharp: true, appDir, imagesDir })
})

View file

@ -1,5 +1,3 @@
import execa from 'execa'
import fs from 'fs-extra'
import { join } from 'path'
import { setupTests } from './util'
@ -7,23 +5,5 @@ const appDir = join(__dirname, '../app')
const imagesDir = join(appDir, '.next', 'cache', 'images')
describe('with latest sharp', () => {
beforeAll(async () => {
await fs.writeFile(
join(appDir, 'package.json'),
JSON.stringify({
packageManager: 'npm@10.2.5',
})
)
await execa('npm', ['add', 'sharp@latest'], {
cwd: appDir,
stdio: 'inherit',
})
})
afterAll(async () => {
await fs.remove(join(appDir, 'node_modules'))
await fs.remove(join(appDir, 'package-lock.json'))
await fs.remove(join(appDir, 'package.json'))
})
setupTests({ isSharp: true, isOutdatedSharp: false, appDir, imagesDir })
setupTests({ appDir, imagesDir })
})

View file

@ -1,9 +0,0 @@
import { join } from 'path'
import { setupTests } from './util'
const appDir = join(__dirname, '../app')
const imagesDir = join(appDir, '.next', 'cache', 'images')
describe('with squoosh', () => {
setupTests({ isSharp: false, isOutdatedSharp: false, appDir, imagesDir })
})

View file

@ -18,8 +18,6 @@ import isAnimated from 'next/dist/compiled/is-animated'
import type { RequestInit } from 'node-fetch'
const largeSize = 1080 // defaults defined in server/config.ts
const sharpMissingText = `For production Image Optimization with Next.js, the optional 'sharp' package is strongly recommended`
const sharpOutdatedText = `Your installed version of the 'sharp' package does not support AVIF images. Run 'npm i sharp@latest' to upgrade to the latest version`
const animatedWarnText =
'is an animated image so it will not be optimized. Consider adding the "unoptimized" property to the <Image>.'
@ -149,26 +147,6 @@ export function runTests(ctx) {
slowImageServer.stop()
})
if (!isDev && ctx.isSharp && ctx.nextConfigImages) {
it('should handle custom sharp usage', async () => {
const res = await fetchViaHTTP(ctx.appPort, '/api/custom-sharp')
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ success: true })
const traceFile = await fs.readJson(
join(
ctx.appDir,
'.next',
'server',
'pages',
'api',
'custom-sharp.js.nft.json'
)
)
expect(traceFile.files.some((file) => file.includes('sharp/'))).toBe(true)
})
}
if (domains.length > 0) {
it('should normalize invalid status codes', async () => {
const url = `http://localhost:${
@ -407,26 +385,24 @@ export function runTests(ctx) {
await expectWidth(res, ctx.w)
})
if (!ctx.isOutdatedSharp) {
it('should downlevel avif format to jpeg for old Safari', async () => {
const accept =
'image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5'
const query = { w: ctx.w, q: 74, url: '/test.avif' }
const opts = { headers: { accept } }
const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts)
expect(res.status).toBe(200)
expect(res.headers.get('Content-Type')).toContain('image/jpeg')
expect(res.headers.get('Cache-Control')).toBe(
`public, max-age=${isDev ? 0 : minimumCacheTTL}, must-revalidate`
)
expect(res.headers.get('Vary')).toBe('Accept')
expect(res.headers.get('etag')).toBeTruthy()
expect(res.headers.get('Content-Disposition')).toBe(
`${contentDispositionType}; filename="test.jpeg"`
)
await expectWidth(res, ctx.w)
})
}
it('should downlevel avif format to jpeg for old Safari', async () => {
const accept =
'image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5'
const query = { w: ctx.w, q: 74, url: '/test.avif' }
const opts = { headers: { accept } }
const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts)
expect(res.status).toBe(200)
expect(res.headers.get('Content-Type')).toContain('image/jpeg')
expect(res.headers.get('Cache-Control')).toBe(
`public, max-age=${isDev ? 0 : minimumCacheTTL}, must-revalidate`
)
expect(res.headers.get('Vary')).toBe('Accept')
expect(res.headers.get('etag')).toBeTruthy()
expect(res.headers.get('Content-Disposition')).toBe(
`${contentDispositionType}; filename="test.jpeg"`
)
await expectWidth(res, ctx.w)
})
it('should fail when url is missing', async () => {
const query = { w: ctx.w, q: 100 }
@ -677,9 +653,7 @@ export function runTests(ctx) {
expect(res.headers.get('Content-Disposition')).toBe(
`${contentDispositionType}; filename="test.avif"`
)
// TODO: upgrade "image-size" package to support AVIF
// See https://github.com/image-size/image-size/issues/348
//await expectWidth(res, ctx.w)
await expectWidth(res, ctx.w)
})
it('should compress avif smaller than webp at q=100', async () => {
@ -1152,34 +1126,6 @@ export function runTests(ctx) {
await expectWidth(res, 400)
})
if (!ctx.isSharp) {
// this checks for specific color type output by squoosh
// which differs in sharp
it('should not change the color type of a png', async () => {
// https://github.com/vercel/next.js/issues/22929
// A grayscaled PNG with transparent pixels.
const query = { url: '/grayscale.png', w: largeSize, q: 80 }
const opts = { headers: { accept: 'image/png' } }
const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts)
expect(res.status).toBe(200)
expect(res.headers.get('Content-Type')).toBe('image/png')
expect(res.headers.get('Cache-Control')).toBe(
`public, max-age=${isDev ? 0 : minimumCacheTTL}, must-revalidate`
)
expect(res.headers.get('Vary')).toBe('Accept')
expect(res.headers.get('Content-Disposition')).toBe(
`${contentDispositionType}; filename="grayscale.png"`
)
const png = await res.buffer()
// Read the color type byte (offset 9 + magic number 16).
// http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html
const colorType = png.readUIntBE(25, 1)
expect(colorType).toBe(4)
})
}
it('should set cache-control to immutable for static images', async () => {
if (!ctx.isDev) {
const filename = 'test'
@ -1287,34 +1233,96 @@ export function runTests(ctx) {
expect(xCache).toEqual(['MISS', 'MISS', 'MISS'])
})
}
if (ctx.isDev || ctx.isSharp) {
it('should not have sharp missing warning', () => {
expect(ctx.nextOutput).not.toContain(sharpMissingText)
})
} else {
it('should have sharp missing warning', () => {
expect(ctx.nextOutput).toContain(sharpMissingText)
})
}
if (ctx.isSharp && ctx.isOutdatedSharp && avifEnabled) {
it('should have sharp outdated warning', () => {
expect(ctx.nextOutput).toContain(sharpOutdatedText)
})
} else {
it('should not have sharp outdated warning', () => {
expect(ctx.nextOutput).not.toContain(sharpOutdatedText)
})
}
}
export const setupTests = (ctx) => {
const nextConfig = new File(join(ctx.appDir, 'next.config.js'))
// only run one server config with outdated sharp
if (!ctx.isOutdatedSharp) {
describe('dev support w/o next.config.js', () => {
describe('dev support w/o next.config.js', () => {
if (ctx.nextConfigImages) {
// skip this test because it requires next.config.js
return
}
const size = 384 // defaults defined in server/config.ts
const curCtx = {
...ctx,
w: size,
isDev: true,
}
beforeAll(async () => {
const json = JSON.stringify({
experimental: {
outputFileTracingRoot: join(__dirname, '../../../..'),
},
})
nextConfig.replace('{ /* replaceme */ }', json)
curCtx.nextOutput = ''
curCtx.appPort = await findPort()
curCtx.app = await launchApp(curCtx.appDir, curCtx.appPort, {
onStderr(msg) {
curCtx.nextOutput += msg
},
cwd: curCtx.appDir,
})
await cleanImagesDir(ctx)
})
afterAll(async () => {
nextConfig.restore()
if (curCtx.app) await killApp(curCtx.app)
})
runTests(curCtx)
})
describe('dev support with next.config.js', () => {
const size = 400
const curCtx = {
...ctx,
w: size,
isDev: true,
nextConfigImages: {
domains: [
'localhost',
'127.0.0.1',
'example.com',
'assets.vercel.com',
'image-optimization-test.vercel.app',
],
formats: ['image/avif', 'image/webp'],
deviceSizes: [largeSize],
imageSizes: [size],
...ctx.nextConfigImages,
},
}
beforeAll(async () => {
const json = JSON.stringify({
images: curCtx.nextConfigImages,
experimental: {
outputFileTracingRoot: join(__dirname, '../../../..'),
},
})
curCtx.nextOutput = ''
nextConfig.replace('{ /* replaceme */ }', json)
await cleanImagesDir(ctx)
curCtx.appPort = await findPort()
curCtx.app = await launchApp(curCtx.appDir, curCtx.appPort, {
onStderr(msg) {
curCtx.nextOutput += msg
},
cwd: curCtx.appDir,
})
})
afterAll(async () => {
nextConfig.restore()
if (curCtx.app) await killApp(curCtx.app)
})
runTests(curCtx)
})
;(process.env.TURBOPACK_DEV ? describe.skip : describe)(
'Production Mode Server support w/o next.config.js',
() => {
if (ctx.nextConfigImages) {
// skip this test because it requires next.config.js
return
@ -1323,9 +1331,8 @@ export const setupTests = (ctx) => {
const curCtx = {
...ctx,
w: size,
isDev: true,
isDev: false,
}
beforeAll(async () => {
const json = JSON.stringify({
experimental: {
@ -1334,68 +1341,13 @@ export const setupTests = (ctx) => {
})
nextConfig.replace('{ /* replaceme */ }', json)
curCtx.nextOutput = ''
curCtx.appPort = await findPort()
curCtx.app = await launchApp(curCtx.appDir, curCtx.appPort, {
onStderr(msg) {
curCtx.nextOutput += msg
},
env: {
NEXT_SHARP_PATH: curCtx.isSharp
? join(curCtx.appDir, 'node_modules', 'sharp')
: '',
},
cwd: curCtx.appDir,
})
await cleanImagesDir(ctx)
})
afterAll(async () => {
nextConfig.restore()
if (curCtx.app) await killApp(curCtx.app)
})
runTests(curCtx)
})
describe('dev support with next.config.js', () => {
const size = 400
const curCtx = {
...ctx,
w: size,
isDev: true,
nextConfigImages: {
domains: [
'localhost',
'127.0.0.1',
'example.com',
'assets.vercel.com',
'image-optimization-test.vercel.app',
],
formats: ['image/avif', 'image/webp'],
deviceSizes: [largeSize],
imageSizes: [size],
...ctx.nextConfigImages,
},
}
beforeAll(async () => {
const json = JSON.stringify({
images: curCtx.nextConfigImages,
experimental: {
outputFileTracingRoot: join(__dirname, '../../../..'),
},
})
curCtx.nextOutput = ''
nextConfig.replace('{ /* replaceme */ }', json)
await nextBuild(curCtx.appDir)
await cleanImagesDir(ctx)
curCtx.appPort = await findPort()
curCtx.app = await launchApp(curCtx.appDir, curCtx.appPort, {
curCtx.app = await nextStart(curCtx.appDir, curCtx.appPort, {
onStderr(msg) {
curCtx.nextOutput += msg
},
env: {
NEXT_SHARP_PATH: curCtx.isSharp
? join(curCtx.appDir, 'node_modules', 'sharp')
: '',
},
cwd: curCtx.appDir,
})
})
@ -1405,53 +1357,8 @@ export const setupTests = (ctx) => {
})
runTests(curCtx)
})
;(process.env.TURBOPACK_DEV ? describe.skip : describe)(
'Production Mode Server support w/o next.config.js',
() => {
if (ctx.nextConfigImages) {
// skip this test because it requires next.config.js
return
}
const size = 384 // defaults defined in server/config.ts
const curCtx = {
...ctx,
w: size,
isDev: false,
}
beforeAll(async () => {
const json = JSON.stringify({
experimental: {
outputFileTracingRoot: join(__dirname, '../../../..'),
},
})
nextConfig.replace('{ /* replaceme */ }', json)
curCtx.nextOutput = ''
await nextBuild(curCtx.appDir)
await cleanImagesDir(ctx)
curCtx.appPort = await findPort()
curCtx.app = await nextStart(curCtx.appDir, curCtx.appPort, {
onStderr(msg) {
curCtx.nextOutput += msg
},
env: {
NEXT_SHARP_PATH: curCtx.isSharp
? join(curCtx.appDir, 'node_modules', 'sharp')
: '',
},
cwd: curCtx.appDir,
})
})
afterAll(async () => {
nextConfig.restore()
if (curCtx.app) await killApp(curCtx.app)
})
runTests(curCtx)
}
)
}
}
)
;(process.env.TURBOPACK_DEV ? describe.skip : describe)(
'Production Mode Server support with next.config.js',
() => {
@ -1482,20 +1389,6 @@ export const setupTests = (ctx) => {
})
curCtx.nextOutput = ''
nextConfig.replace('{ /* replaceme */ }', json)
if (curCtx.isSharp) {
await fs.writeFile(
join(curCtx.appDir, 'pages', 'api', 'custom-sharp.js'),
`
import sharp from 'sharp'
export default function handler(req, res) {
console.log(sharp)
res.json({ success: true })
}
`
)
}
await nextBuild(curCtx.appDir)
await cleanImagesDir(ctx)
curCtx.appPort = await findPort()
@ -1503,21 +1396,11 @@ export const setupTests = (ctx) => {
onStderr(msg) {
curCtx.nextOutput += msg
},
env: {
NEXT_SHARP_PATH: curCtx.isSharp
? join(curCtx.appDir, 'node_modules', 'sharp')
: '',
},
cwd: curCtx.appDir,
})
})
afterAll(async () => {
nextConfig.restore()
if (curCtx.isSharp) {
await fs.remove(
join(curCtx.appDir, 'pages', 'api', 'custom-sharp.js')
)
}
if (curCtx.app) await killApp(curCtx.app)
})

View file

@ -78,7 +78,7 @@ const runTests = (isDev = false) => {
`style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%;background-size:cover;background-position:0% 0%;filter:blur(20px);background-image:url(${
isDev
? '&quot;/docs/_next/image?url=%2Fdocs%2F_next%2Fstatic%2Fmedia%2Ftest.fab2915d.jpg&amp;w=8&amp;q=70&quot;'
: '&quot;data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z&quot;'
: '&quot;data:image/jpeg;base64,/9j/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wgARCAAGAAgDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGUB//EABYQAAMAAAAAAAAAAAAAAAAAAAMSE//aAAgBAQABBQJhQ//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Bf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Bf//EABoQAAEFAQAAAAAAAAAAAAAAABIAARETMkH/2gAIAQEABj8CEHsLU8X/xAAYEAACAwAAAAAAAAAAAAAAAAAAEUFhcf/aAAgBAQABPyHSKKiP/9oADAMBAAIAAwAAABAD/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPxB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPxB//8QAGRAAAQUAAAAAAAAAAAAAAAAAEQAhMVHR/9oACAEBAAE/EMvICK3JX//Z&quot;'
})`
)
}
@ -93,7 +93,7 @@ const runTests = (isDev = false) => {
`style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%;background-size:cover;background-position:0% 0%;filter:blur(20px);background-image:url(${
isDev
? '&quot;/docs/_next/image?url=%2Fdocs%2F_next%2Fstatic%2Fmedia%2Ftest.3f1a293b.png&amp;w=8&amp;q=70&quot;'
: '&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAICAAAAAAZhBqgAAAAJklEQVR42mNgkmBkYGXgZGBoY2Co/lPAcOf/dYaCzHwGEBAVEwUAZZIG0TbWicQAAAAASUVORK5CYII=&quot;'
: '&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAICAMAAAALMbVOAAAAFVBMVEUBAQEtLS1CQkIHBwf9/f21tbWurq5/IXexAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAHElEQVR4nGNggAJmJmYGJhYmBlYWNgZGRkaYMAACTwAjtdG5RQAAAABJRU5ErkJggg==&quot;'
})`
)
}

View file

@ -66,12 +66,12 @@ const runTests = () => {
})
it('Should add a blur placeholder to statically imported jpg', async () => {
expect(html).toContain(
`style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%;background-size:cover;background-position:0% 0%;filter:blur(20px);background-image:url(&quot;data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z&quot;)"`
`style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%;background-size:cover;background-position:0% 0%;filter:blur(20px);background-image:url(&quot;data:image/jpeg;base64,/9j/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wgARCAAGAAgDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGUB//EABYQAAMAAAAAAAAAAAAAAAAAAAMSE//aAAgBAQABBQJhQ//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Bf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Bf//EABoQAAEFAQAAAAAAAAAAAAAAABIAARETMkH/2gAIAQEABj8CEHsLU8X/xAAYEAACAwAAAAAAAAAAAAAAAAAAEUFhcf/aAAgBAQABPyHSKKiP/9oADAMBAAIAAwAAABAD/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPxB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPxB//8QAGRAAAQUAAAAAAAAAAAAAAAAAEQAhMVHR/9oACAEBAAE/EMvICK3JX//Z&quot;)"`
)
})
it('Should add a blur placeholder to statically imported png', async () => {
expect(html).toContain(
`style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%;background-size:cover;background-position:0% 0%;filter:blur(20px);background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAOklEQVR42iWGsQkAIBDE0iuIdiLOJjiGIzjiL/Meb4okiNYIlLjK3hJMzCQG1/0qmXXOUkjAV+m9wAMe3QiV6Ne8VgAAAABJRU5ErkJggg==&quot;)`
`style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%;background-size:cover;background-position:0% 0%;filter:blur(20px);background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAICAMAAAALMbVOAAAAFVBMVEUBAQEtLS1CQkIHBwf9/f21tbWurq5/IXexAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAHElEQVR4nGNggAJmJmYGJhYmBlYWNgZGRkaYMAACTwAjtdG5RQAAAABJRU5ErkJggg==&quot;)`
)
})

View file

@ -140,7 +140,7 @@ const runTests = (isDev) => {
)
} else {
expect(style).toBe(
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 240'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z'/%3E%3C/svg%3E")`
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 240'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/jpeg;base64,/9j/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wgARCAAGAAgDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGUB//EABYQAAMAAAAAAAAAAAAAAAAAAAMSE//aAAgBAQABBQJhQ//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Bf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Bf//EABoQAAEFAQAAAAAAAAAAAAAAABIAARETMkH/2gAIAQEABj8CEHsLU8X/xAAYEAACAwAAAAAAAAAAAAAAAAAAEUFhcf/aAAgBAQABPyHSKKiP/9oADAMBAAIAAwAAABAD/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPxB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPxB//8QAGRAAAQUAAAAAAAAAAAAAAAAAEQAhMVHR/9oACAEBAAE/EMvICK3JX//Z'/%3E%3C/svg%3E")`
)
}
}
@ -165,7 +165,7 @@ const runTests = (isDev) => {
)
} else {
expect(style).toBe(
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAOklEQVR42iWGsQkAIBDE0iuIdiLOJjiGIzjiL/Meb4okiNYIlLjK3hJMzCQG1/0qmXXOUkjAV+m9wAMe3QiV6Ne8VgAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAMAAADz0U65AAAAElBMVEUAAAA6OjolJSWwsLAfHx/9/f2oxsg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAH0lEQVR4nGNgwAaYmKAMZmYIzcjKyghmsDAysmDTAgAEXAAhXbseDQAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
)
}
}
@ -190,7 +190,7 @@ const runTests = (isDev) => {
)
} else {
expect(style).toBe(
`position:absolute;height:100%;width:100%;left:0;top:0;right:0;bottom:0;color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAOklEQVR42iWGsQkAIBDE0iuIdiLOJjiGIzjiL/Meb4okiNYIlLjK3hJMzCQG1/0qmXXOUkjAV+m9wAMe3QiV6Ne8VgAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
`position:absolute;height:100%;width:100%;left:0;top:0;right:0;bottom:0;color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAMAAADz0U65AAAAElBMVEUAAAA6OjolJSWwsLAfHx/9/f2oxsg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAH0lEQVR4nGNgwAaYmKAMZmYIzcjKyghmsDAysmDTAgAEXAAhXbseDQAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
)
}
}

View file

@ -135,7 +135,7 @@ const runTests = (isDev) => {
)
} else {
expect(style).toBe(
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 240'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z'/%3E%3C/svg%3E")`
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 240'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/jpeg;base64,/9j/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wgARCAAGAAgDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGUB//EABYQAAMAAAAAAAAAAAAAAAAAAAMSE//aAAgBAQABBQJhQ//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Bf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Bf//EABoQAAEFAQAAAAAAAAAAAAAAABIAARETMkH/2gAIAQEABj8CEHsLU8X/xAAYEAACAwAAAAAAAAAAAAAAAAAAEUFhcf/aAAgBAQABPyHSKKiP/9oADAMBAAIAAwAAABAD/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPxB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPxB//8QAGRAAAQUAAAAAAAAAAAAAAAAAEQAhMVHR/9oACAEBAAE/EMvICK3JX//Z'/%3E%3C/svg%3E")`
)
}
}
@ -160,7 +160,7 @@ const runTests = (isDev) => {
)
} else {
expect(style).toBe(
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAOklEQVR42iWGsQkAIBDE0iuIdiLOJjiGIzjiL/Meb4okiNYIlLjK3hJMzCQG1/0qmXXOUkjAV+m9wAMe3QiV6Ne8VgAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAMAAADz0U65AAAAElBMVEUAAAA6OjolJSWwsLAfHx/9/f2oxsg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAH0lEQVR4nGNgwAaYmKAMZmYIzcjKyghmsDAysmDTAgAEXAAhXbseDQAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
)
}
}

View file

@ -140,7 +140,7 @@ const runTests = (isDev) => {
)
} else {
expect(style).toBe(
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 240'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z'/%3E%3C/svg%3E")`
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 240'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/jpeg;base64,/9j/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wgARCAAGAAgDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGUB//EABYQAAMAAAAAAAAAAAAAAAAAAAMSE//aAAgBAQABBQJhQ//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Bf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Bf//EABoQAAEFAQAAAAAAAAAAAAAAABIAARETMkH/2gAIAQEABj8CEHsLU8X/xAAYEAACAwAAAAAAAAAAAAAAAAAAEUFhcf/aAAgBAQABPyHSKKiP/9oADAMBAAIAAwAAABAD/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPxB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPxB//8QAGRAAAQUAAAAAAAAAAAAAAAAAEQAhMVHR/9oACAEBAAE/EMvICK3JX//Z'/%3E%3C/svg%3E")`
)
}
}
@ -165,7 +165,7 @@ const runTests = (isDev) => {
)
} else {
expect(style).toBe(
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAOklEQVR42iWGsQkAIBDE0iuIdiLOJjiGIzjiL/Meb4okiNYIlLjK3hJMzCQG1/0qmXXOUkjAV+m9wAMe3QiV6Ne8VgAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
`color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAMAAADz0U65AAAAElBMVEUAAAA6OjolJSWwsLAfHx/9/f2oxsg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAH0lEQVR4nGNgwAaYmKAMZmYIzcjKyghmsDAysmDTAgAEXAAhXbseDQAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
)
}
}
@ -190,7 +190,7 @@ const runTests = (isDev) => {
)
} else {
expect(style).toBe(
`position:absolute;height:100%;width:100%;left:0;top:0;right:0;bottom:0;color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAOklEQVR42iWGsQkAIBDE0iuIdiLOJjiGIzjiL/Meb4okiNYIlLjK3hJMzCQG1/0qmXXOUkjAV+m9wAMe3QiV6Ne8VgAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
`position:absolute;height:100%;width:100%;left:0;top:0;right:0;bottom:0;color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 320'%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='20'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='none' style='filter: url(%23b);' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAMAAADz0U65AAAAElBMVEUAAAA6OjolJSWwsLAfHx/9/f2oxsg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAH0lEQVR4nGNgwAaYmKAMZmYIzcjKyghmsDAysmDTAgAEXAAhXbseDQAAAABJRU5ErkJggg=='/%3E%3C/svg%3E")`
)
}
}

View file

@ -0,0 +1,2 @@
node_modules
!package-lock.json

View file

@ -0,0 +1,585 @@
{
"name": "app",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"sharp": "latest"
}
},
"node_modules/@emnapi/runtime": {
"version": "0.45.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.45.0.tgz",
"integrity": "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.2.tgz",
"integrity": "sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"glibc": ">=2.26",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.0.1"
}
},
"node_modules/@img/sharp-darwin-x64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.2.tgz",
"integrity": "sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"glibc": ">=2.26",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.0.1"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.1.tgz",
"integrity": "sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"macos": ">=11",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.1.tgz",
"integrity": "sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"macos": ">=10.13",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.1.tgz",
"integrity": "sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.28",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.1.tgz",
"integrity": "sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.26",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-s390x": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.1.tgz",
"integrity": "sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==",
"cpu": [
"s390x"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.28",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.1.tgz",
"integrity": "sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.26",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.1.tgz",
"integrity": "sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"musl": ">=1.2.2",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.1.tgz",
"integrity": "sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"musl": ">=1.2.2",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-linux-arm": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.2.tgz",
"integrity": "sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.28",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.0.1"
}
},
"node_modules/@img/sharp-linux-arm64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.2.tgz",
"integrity": "sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.26",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.0.1"
}
},
"node_modules/@img/sharp-linux-s390x": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.2.tgz",
"integrity": "sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==",
"cpu": [
"s390x"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.28",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-s390x": "1.0.1"
}
},
"node_modules/@img/sharp-linux-x64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.2.tgz",
"integrity": "sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.26",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.0.1"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.2.tgz",
"integrity": "sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"musl": ">=1.2.2",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.0.1"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.2.tgz",
"integrity": "sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"musl": ">=1.2.2",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.0.1"
}
},
"node_modules/@img/sharp-wasm32": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.2.tgz",
"integrity": "sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==",
"cpu": [
"wasm32"
],
"optional": true,
"dependencies": {
"@emnapi/runtime": "^0.45.0"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-ia32": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.2.tgz",
"integrity": "sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-x64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.2.tgz",
"integrity": "sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"dependencies": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
},
"engines": {
"node": ">=12.5.0"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/color-string": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"dependencies": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"node_modules/detect-libc": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz",
"integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==",
"engines": {
"node": ">=8"
}
},
"node_modules/is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/semver": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/sharp": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.2.tgz",
"integrity": "sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==",
"hasInstallScript": true,
"dependencies": {
"color": "^4.2.3",
"detect-libc": "^2.0.2",
"semver": "^7.5.4"
},
"engines": {
"libvips": ">=8.15.1",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "0.33.2",
"@img/sharp-darwin-x64": "0.33.2",
"@img/sharp-libvips-darwin-arm64": "1.0.1",
"@img/sharp-libvips-darwin-x64": "1.0.1",
"@img/sharp-libvips-linux-arm": "1.0.1",
"@img/sharp-libvips-linux-arm64": "1.0.1",
"@img/sharp-libvips-linux-s390x": "1.0.1",
"@img/sharp-libvips-linux-x64": "1.0.1",
"@img/sharp-libvips-linuxmusl-arm64": "1.0.1",
"@img/sharp-libvips-linuxmusl-x64": "1.0.1",
"@img/sharp-linux-arm": "0.33.2",
"@img/sharp-linux-arm64": "0.33.2",
"@img/sharp-linux-s390x": "0.33.2",
"@img/sharp-linux-x64": "0.33.2",
"@img/sharp-linuxmusl-arm64": "0.33.2",
"@img/sharp-linuxmusl-x64": "0.33.2",
"@img/sharp-wasm32": "0.33.2",
"@img/sharp-win32-ia32": "0.33.2",
"@img/sharp-win32-x64": "0.33.2"
}
},
"node_modules/simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"dependencies": {
"is-arrayish": "^0.3.1"
}
},
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
"optional": true
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}

View file

@ -0,0 +1,7 @@
{
"private": true,
"packageManager": "npm@10.4.0",
"dependencies": {
"sharp": "latest"
}
}

View file

@ -0,0 +1,5 @@
import sharp from 'sharp'
export default function handler(req, res) {
res.json({ success: Boolean(sharp) })
}

View file

@ -0,0 +1,50 @@
/* eslint-env jest */
import {
fetchViaHTTP,
findPort,
killApp,
nextBuild,
nextStart,
} from 'next-test-utils'
import execa from 'execa'
import fs from 'fs-extra'
import { join } from 'path'
const appDir = join(__dirname, '../app')
let app,
appPort
// Skip as Turbopack doesn't support `next build` yet
;(process.env.TURBOPACK ? describe.skip : describe)('sharp api', () => {
beforeAll(async () => {
await execa('npm', ['install'], { cwd: appDir, stdio: 'inherit' })
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(async () => {
if (app) {
await killApp(app)
}
await fs.remove(join(appDir, '.next'))
await fs.remove(join(appDir, 'node_modules'))
})
it('should handle custom sharp usage', async () => {
const res = await fetchViaHTTP(appPort, '/api/custom-sharp')
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ success: true })
const traceFile = await fs.readJson(
join(
appDir,
'.next',
'server',
'pages',
'api',
'custom-sharp.js.nft.json'
)
)
expect(traceFile.files.some((file) => file.includes('sharp/'))).toBe(true)
})
})

View file

@ -178,7 +178,7 @@ createNextDescribe(
).toBe(false)
expect(
serverTrace.files.some((file) => file.includes('node_modules/sharp'))
).toBe(false)
).toBe(true)
}
const checks = [

View file

@ -10904,71 +10904,6 @@
"flakey": [],
"runtimeError": false
},
"test/integration/image-optimizer/test/old-sharp.test.ts": {
"passed": [],
"failed": [
"with outdated sharp Production Mode Server support with next.config.js should automatically detect image type when content-type is octet-stream",
"with outdated sharp Production Mode Server support with next.config.js should compress avif smaller than webp at q=100",
"with outdated sharp Production Mode Server support with next.config.js should compress avif smaller than webp at q=50",
"with outdated sharp Production Mode Server support with next.config.js should compress avif smaller than webp at q=75",
"with outdated sharp Production Mode Server support with next.config.js should downlevel webp format to jpeg for old Safari",
"with outdated sharp Production Mode Server support with next.config.js should emit blur svg when width is 8 in dev but not prod",
"with outdated sharp Production Mode Server support with next.config.js should emit blur svg when width is less than 8 in dev but not prod",
"with outdated sharp Production Mode Server support with next.config.js should error if the image file does not exist",
"with outdated sharp Production Mode Server support with next.config.js should error if the resource isn't a valid image",
"with outdated sharp Production Mode Server support with next.config.js should fail when domain is not defined in next.config.js",
"with outdated sharp Production Mode Server support with next.config.js should fail when internal url is not an image",
"with outdated sharp Production Mode Server support with next.config.js should fail when q is greater than 100",
"with outdated sharp Production Mode Server support with next.config.js should fail when q is less than 1",
"with outdated sharp Production Mode Server support with next.config.js should fail when q is missing",
"with outdated sharp Production Mode Server support with next.config.js should fail when q is not a number",
"with outdated sharp Production Mode Server support with next.config.js should fail when url fails to load an image",
"with outdated sharp Production Mode Server support with next.config.js should fail when url has file protocol",
"with outdated sharp Production Mode Server support with next.config.js should fail when url has ftp protocol",
"with outdated sharp Production Mode Server support with next.config.js should fail when url is missing",
"with outdated sharp Production Mode Server support with next.config.js should fail when w is 0",
"with outdated sharp Production Mode Server support with next.config.js should fail when w is less than 0",
"with outdated sharp Production Mode Server support with next.config.js should fail when w is missing",
"with outdated sharp Production Mode Server support with next.config.js should fail when w is not a number",
"with outdated sharp Production Mode Server support with next.config.js should fail when width is not in next.config.js",
"with outdated sharp Production Mode Server support with next.config.js should handle concurrent requests",
"with outdated sharp Production Mode Server support with next.config.js should handle custom sharp usage",
"with outdated sharp Production Mode Server support with next.config.js should handle non-ascii characters in image url",
"with outdated sharp Production Mode Server support with next.config.js should have sharp outdated warning",
"with outdated sharp Production Mode Server support with next.config.js should maintain animated gif",
"with outdated sharp Production Mode Server support with next.config.js should maintain animated png",
"with outdated sharp Production Mode Server support with next.config.js should maintain animated png 2",
"with outdated sharp Production Mode Server support with next.config.js should maintain animated webp",
"with outdated sharp Production Mode Server support with next.config.js should maintain bmp",
"with outdated sharp Production Mode Server support with next.config.js should maintain ico format",
"with outdated sharp Production Mode Server support with next.config.js should maintain jpg format for old Safari",
"with outdated sharp Production Mode Server support with next.config.js should maintain png format for old Safari",
"with outdated sharp Production Mode Server support with next.config.js should normalize invalid status codes",
"with outdated sharp Production Mode Server support with next.config.js should not allow svg with application header",
"with outdated sharp Production Mode Server support with next.config.js should not allow svg with comma header",
"with outdated sharp Production Mode Server support with next.config.js should not allow svg with uppercase header",
"with outdated sharp Production Mode Server support with next.config.js should not allow vector svg",
"with outdated sharp Production Mode Server support with next.config.js should not have sharp missing warning",
"with outdated sharp Production Mode Server support with next.config.js should not resize if requested width is larger than original source image",
"with outdated sharp Production Mode Server support with next.config.js should resize absolute url from localhost",
"with outdated sharp Production Mode Server support with next.config.js should resize relative url and new Chrome accept header as avif",
"with outdated sharp Production Mode Server support with next.config.js should resize relative url and old Chrome accept header as webp",
"with outdated sharp Production Mode Server support with next.config.js should resize relative url and png accept header",
"with outdated sharp Production Mode Server support with next.config.js should resize relative url and webp Firefox accept header",
"with outdated sharp Production Mode Server support with next.config.js should resize relative url with invalid accept header as gif",
"with outdated sharp Production Mode Server support with next.config.js should resize relative url with invalid accept header as png",
"with outdated sharp Production Mode Server support with next.config.js should resize relative url with invalid accept header as tiff",
"with outdated sharp Production Mode Server support with next.config.js should return home page",
"with outdated sharp Production Mode Server support with next.config.js should set 304 status without body when etag matches if-none-match",
"with outdated sharp Production Mode Server support with next.config.js should set cache-control to immutable for static images",
"with outdated sharp Production Mode Server support with next.config.js should use cache and stale-while-revalidate when query is the same for external image",
"with outdated sharp Production Mode Server support with next.config.js should use cache and stale-while-revalidate when query is the same for internal image",
"with outdated sharp Production Mode Server support with next.config.js should use cached image file when parameters are the same for animated gif"
],
"pending": [],
"flakey": [],
"runtimeError": false
},
"test/integration/image-optimizer/test/sharp.test.ts": {
"passed": [
"with latest sharp dev support w/o next.config.js should downlevel avif format to jpeg for old Safari",
@ -11187,227 +11122,6 @@
"flakey": [],
"runtimeError": false
},
"test/integration/image-optimizer/test/squoosh.test.ts": {
"passed": [
"with squoosh dev support w/o next.config.js should downlevel avif format to jpeg for old Safari",
"with squoosh dev support w/o next.config.js should downlevel webp format to jpeg for old Safari",
"with squoosh dev support w/o next.config.js should emit blur svg when width is 8 in dev but not prod",
"with squoosh dev support w/o next.config.js should emit blur svg when width is less than 8 in dev but not prod",
"with squoosh dev support w/o next.config.js should error if the image file does not exist",
"with squoosh dev support w/o next.config.js should error if the resource isn't a valid image",
"with squoosh dev support w/o next.config.js should fail when domain is not defined in next.config.js",
"with squoosh dev support w/o next.config.js should fail when internal url is not an image",
"with squoosh dev support w/o next.config.js should fail when q is greater than 100",
"with squoosh dev support w/o next.config.js should fail when q is less than 1",
"with squoosh dev support w/o next.config.js should fail when q is missing",
"with squoosh dev support w/o next.config.js should fail when q is not a number",
"with squoosh dev support w/o next.config.js should fail when url has file protocol",
"with squoosh dev support w/o next.config.js should fail when url has ftp protocol",
"with squoosh dev support w/o next.config.js should fail when url is missing",
"with squoosh dev support w/o next.config.js should fail when w is 0",
"with squoosh dev support w/o next.config.js should fail when w is less than 0",
"with squoosh dev support w/o next.config.js should fail when w is missing",
"with squoosh dev support w/o next.config.js should fail when w is not a number",
"with squoosh dev support w/o next.config.js should fail when width is not in next.config.js",
"with squoosh dev support w/o next.config.js should handle non-ascii characters in image url",
"with squoosh dev support w/o next.config.js should maintain animated gif",
"with squoosh dev support w/o next.config.js should maintain animated png",
"with squoosh dev support w/o next.config.js should maintain animated png 2",
"with squoosh dev support w/o next.config.js should maintain animated webp",
"with squoosh dev support w/o next.config.js should maintain bmp",
"with squoosh dev support w/o next.config.js should maintain ico format",
"with squoosh dev support w/o next.config.js should maintain jpg format for old Safari",
"with squoosh dev support w/o next.config.js should maintain png format for old Safari",
"with squoosh dev support w/o next.config.js should not allow svg with application header",
"with squoosh dev support w/o next.config.js should not allow svg with comma header",
"with squoosh dev support w/o next.config.js should not allow svg with uppercase header",
"with squoosh dev support w/o next.config.js should not allow vector svg",
"with squoosh dev support w/o next.config.js should not change the color type of a png",
"with squoosh dev support w/o next.config.js should not have sharp missing warning",
"with squoosh dev support w/o next.config.js should not have sharp outdated warning",
"with squoosh dev support w/o next.config.js should not resize if requested width is larger than original source image",
"with squoosh dev support w/o next.config.js should resize relative url and old Chrome accept header as webp",
"with squoosh dev support w/o next.config.js should resize relative url and png accept header",
"with squoosh dev support w/o next.config.js should resize relative url and webp Firefox accept header",
"with squoosh dev support w/o next.config.js should resize relative url with invalid accept header as gif",
"with squoosh dev support w/o next.config.js should resize relative url with invalid accept header as png",
"with squoosh dev support w/o next.config.js should resize relative url with invalid accept header as tiff",
"with squoosh dev support w/o next.config.js should return home page",
"with squoosh dev support w/o next.config.js should set 304 status without body when etag matches if-none-match",
"with squoosh dev support w/o next.config.js should set cache-control to immutable for static images",
"with squoosh dev support w/o next.config.js should use cache and stale-while-revalidate when query is the same for internal image",
"with squoosh dev support w/o next.config.js should use cached image file when parameters are the same for animated gif",
"with squoosh dev support with next.config.js should automatically detect image type when content-type is octet-stream",
"with squoosh dev support with next.config.js should compress avif smaller than webp at q=100",
"with squoosh dev support with next.config.js should compress avif smaller than webp at q=50",
"with squoosh dev support with next.config.js should compress avif smaller than webp at q=75",
"with squoosh dev support with next.config.js should downlevel avif format to jpeg for old Safari",
"with squoosh dev support with next.config.js should downlevel webp format to jpeg for old Safari",
"with squoosh dev support with next.config.js should emit blur svg when width is 8 in dev but not prod",
"with squoosh dev support with next.config.js should emit blur svg when width is less than 8 in dev but not prod",
"with squoosh dev support with next.config.js should error if the image file does not exist",
"with squoosh dev support with next.config.js should error if the resource isn't a valid image",
"with squoosh dev support with next.config.js should fail when domain is not defined in next.config.js",
"with squoosh dev support with next.config.js should fail when internal url is not an image",
"with squoosh dev support with next.config.js should fail when q is greater than 100",
"with squoosh dev support with next.config.js should fail when q is less than 1",
"with squoosh dev support with next.config.js should fail when q is missing",
"with squoosh dev support with next.config.js should fail when q is not a number",
"with squoosh dev support with next.config.js should fail when url fails to load an image",
"with squoosh dev support with next.config.js should fail when url has file protocol",
"with squoosh dev support with next.config.js should fail when url has ftp protocol",
"with squoosh dev support with next.config.js should fail when url is missing",
"with squoosh dev support with next.config.js should fail when w is 0",
"with squoosh dev support with next.config.js should fail when w is less than 0",
"with squoosh dev support with next.config.js should fail when w is missing",
"with squoosh dev support with next.config.js should fail when w is not a number",
"with squoosh dev support with next.config.js should fail when width is not in next.config.js",
"with squoosh dev support with next.config.js should handle concurrent requests",
"with squoosh dev support with next.config.js should handle non-ascii characters in image url",
"with squoosh dev support with next.config.js should maintain animated gif",
"with squoosh dev support with next.config.js should maintain animated png",
"with squoosh dev support with next.config.js should maintain animated png 2",
"with squoosh dev support with next.config.js should maintain animated webp",
"with squoosh dev support with next.config.js should maintain bmp",
"with squoosh dev support with next.config.js should maintain ico format",
"with squoosh dev support with next.config.js should maintain jpg format for old Safari",
"with squoosh dev support with next.config.js should maintain png format for old Safari",
"with squoosh dev support with next.config.js should normalize invalid status codes",
"with squoosh dev support with next.config.js should not allow svg with application header",
"with squoosh dev support with next.config.js should not allow svg with comma header",
"with squoosh dev support with next.config.js should not allow svg with uppercase header",
"with squoosh dev support with next.config.js should not allow vector svg",
"with squoosh dev support with next.config.js should not change the color type of a png",
"with squoosh dev support with next.config.js should not have sharp missing warning",
"with squoosh dev support with next.config.js should not have sharp outdated warning",
"with squoosh dev support with next.config.js should not resize if requested width is larger than original source image",
"with squoosh dev support with next.config.js should resize absolute url from localhost",
"with squoosh dev support with next.config.js should resize relative url and new Chrome accept header as avif",
"with squoosh dev support with next.config.js should resize relative url and old Chrome accept header as webp",
"with squoosh dev support with next.config.js should resize relative url and png accept header",
"with squoosh dev support with next.config.js should resize relative url and webp Firefox accept header",
"with squoosh dev support with next.config.js should resize relative url with invalid accept header as gif",
"with squoosh dev support with next.config.js should resize relative url with invalid accept header as png",
"with squoosh dev support with next.config.js should resize relative url with invalid accept header as tiff",
"with squoosh dev support with next.config.js should return home page",
"with squoosh dev support with next.config.js should set 304 status without body when etag matches if-none-match",
"with squoosh dev support with next.config.js should set cache-control to immutable for static images",
"with squoosh dev support with next.config.js should use cache and stale-while-revalidate when query is the same for external image",
"with squoosh dev support with next.config.js should use cache and stale-while-revalidate when query is the same for internal image",
"with squoosh dev support with next.config.js should use cached image file when parameters are the same for animated gif"
],
"failed": [
"with squoosh Production Mode Server support w/o next.config.js should downlevel avif format to jpeg for old Safari",
"with squoosh Production Mode Server support w/o next.config.js should downlevel webp format to jpeg for old Safari",
"with squoosh Production Mode Server support w/o next.config.js should emit blur svg when width is 8 in dev but not prod",
"with squoosh Production Mode Server support w/o next.config.js should emit blur svg when width is less than 8 in dev but not prod",
"with squoosh Production Mode Server support w/o next.config.js should error if the image file does not exist",
"with squoosh Production Mode Server support w/o next.config.js should error if the resource isn't a valid image",
"with squoosh Production Mode Server support w/o next.config.js should fail when domain is not defined in next.config.js",
"with squoosh Production Mode Server support w/o next.config.js should fail when internal url is not an image",
"with squoosh Production Mode Server support w/o next.config.js should fail when q is greater than 100",
"with squoosh Production Mode Server support w/o next.config.js should fail when q is less than 1",
"with squoosh Production Mode Server support w/o next.config.js should fail when q is missing",
"with squoosh Production Mode Server support w/o next.config.js should fail when q is not a number",
"with squoosh Production Mode Server support w/o next.config.js should fail when url has file protocol",
"with squoosh Production Mode Server support w/o next.config.js should fail when url has ftp protocol",
"with squoosh Production Mode Server support w/o next.config.js should fail when url is missing",
"with squoosh Production Mode Server support w/o next.config.js should fail when w is 0",
"with squoosh Production Mode Server support w/o next.config.js should fail when w is less than 0",
"with squoosh Production Mode Server support w/o next.config.js should fail when w is missing",
"with squoosh Production Mode Server support w/o next.config.js should fail when w is not a number",
"with squoosh Production Mode Server support w/o next.config.js should fail when width is not in next.config.js",
"with squoosh Production Mode Server support w/o next.config.js should handle non-ascii characters in image url",
"with squoosh Production Mode Server support w/o next.config.js should have sharp missing warning",
"with squoosh Production Mode Server support w/o next.config.js should maintain animated gif",
"with squoosh Production Mode Server support w/o next.config.js should maintain animated png",
"with squoosh Production Mode Server support w/o next.config.js should maintain animated png 2",
"with squoosh Production Mode Server support w/o next.config.js should maintain animated webp",
"with squoosh Production Mode Server support w/o next.config.js should maintain bmp",
"with squoosh Production Mode Server support w/o next.config.js should maintain ico format",
"with squoosh Production Mode Server support w/o next.config.js should maintain jpg format for old Safari",
"with squoosh Production Mode Server support w/o next.config.js should maintain png format for old Safari",
"with squoosh Production Mode Server support w/o next.config.js should not allow svg with application header",
"with squoosh Production Mode Server support w/o next.config.js should not allow svg with comma header",
"with squoosh Production Mode Server support w/o next.config.js should not allow svg with uppercase header",
"with squoosh Production Mode Server support w/o next.config.js should not allow vector svg",
"with squoosh Production Mode Server support w/o next.config.js should not change the color type of a png",
"with squoosh Production Mode Server support w/o next.config.js should not have sharp outdated warning",
"with squoosh Production Mode Server support w/o next.config.js should not resize if requested width is larger than original source image",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url and old Chrome accept header as webp",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url and png accept header",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url and webp Firefox accept header",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url with invalid accept header as gif",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url with invalid accept header as png",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url with invalid accept header as tiff",
"with squoosh Production Mode Server support w/o next.config.js should return home page",
"with squoosh Production Mode Server support w/o next.config.js should set 304 status without body when etag matches if-none-match",
"with squoosh Production Mode Server support w/o next.config.js should set cache-control to immutable for static images",
"with squoosh Production Mode Server support w/o next.config.js should use cache and stale-while-revalidate when query is the same for internal image",
"with squoosh Production Mode Server support w/o next.config.js should use cached image file when parameters are the same for animated gif",
"with squoosh Production Mode Server support with next.config.js should automatically detect image type when content-type is octet-stream",
"with squoosh Production Mode Server support with next.config.js should compress avif smaller than webp at q=100",
"with squoosh Production Mode Server support with next.config.js should compress avif smaller than webp at q=50",
"with squoosh Production Mode Server support with next.config.js should compress avif smaller than webp at q=75",
"with squoosh Production Mode Server support with next.config.js should downlevel avif format to jpeg for old Safari",
"with squoosh Production Mode Server support with next.config.js should downlevel webp format to jpeg for old Safari",
"with squoosh Production Mode Server support with next.config.js should emit blur svg when width is 8 in dev but not prod",
"with squoosh Production Mode Server support with next.config.js should emit blur svg when width is less than 8 in dev but not prod",
"with squoosh Production Mode Server support with next.config.js should error if the image file does not exist",
"with squoosh Production Mode Server support with next.config.js should error if the resource isn't a valid image",
"with squoosh Production Mode Server support with next.config.js should fail when domain is not defined in next.config.js",
"with squoosh Production Mode Server support with next.config.js should fail when internal url is not an image",
"with squoosh Production Mode Server support with next.config.js should fail when q is greater than 100",
"with squoosh Production Mode Server support with next.config.js should fail when q is less than 1",
"with squoosh Production Mode Server support with next.config.js should fail when q is missing",
"with squoosh Production Mode Server support with next.config.js should fail when q is not a number",
"with squoosh Production Mode Server support with next.config.js should fail when url fails to load an image",
"with squoosh Production Mode Server support with next.config.js should fail when url has file protocol",
"with squoosh Production Mode Server support with next.config.js should fail when url has ftp protocol",
"with squoosh Production Mode Server support with next.config.js should fail when url is missing",
"with squoosh Production Mode Server support with next.config.js should fail when w is 0",
"with squoosh Production Mode Server support with next.config.js should fail when w is less than 0",
"with squoosh Production Mode Server support with next.config.js should fail when w is missing",
"with squoosh Production Mode Server support with next.config.js should fail when w is not a number",
"with squoosh Production Mode Server support with next.config.js should fail when width is not in next.config.js",
"with squoosh Production Mode Server support with next.config.js should handle concurrent requests",
"with squoosh Production Mode Server support with next.config.js should handle non-ascii characters in image url",
"with squoosh Production Mode Server support with next.config.js should have sharp missing warning",
"with squoosh Production Mode Server support with next.config.js should maintain animated gif",
"with squoosh Production Mode Server support with next.config.js should maintain animated png",
"with squoosh Production Mode Server support with next.config.js should maintain animated png 2",
"with squoosh Production Mode Server support with next.config.js should maintain animated webp",
"with squoosh Production Mode Server support with next.config.js should maintain bmp",
"with squoosh Production Mode Server support with next.config.js should maintain ico format",
"with squoosh Production Mode Server support with next.config.js should maintain jpg format for old Safari",
"with squoosh Production Mode Server support with next.config.js should maintain png format for old Safari",
"with squoosh Production Mode Server support with next.config.js should normalize invalid status codes",
"with squoosh Production Mode Server support with next.config.js should not allow svg with application header",
"with squoosh Production Mode Server support with next.config.js should not allow svg with comma header",
"with squoosh Production Mode Server support with next.config.js should not allow svg with uppercase header",
"with squoosh Production Mode Server support with next.config.js should not allow vector svg",
"with squoosh Production Mode Server support with next.config.js should not change the color type of a png",
"with squoosh Production Mode Server support with next.config.js should not have sharp outdated warning",
"with squoosh Production Mode Server support with next.config.js should not resize if requested width is larger than original source image",
"with squoosh Production Mode Server support with next.config.js should resize absolute url from localhost",
"with squoosh Production Mode Server support with next.config.js should resize relative url and new Chrome accept header as avif",
"with squoosh Production Mode Server support with next.config.js should resize relative url and old Chrome accept header as webp",
"with squoosh Production Mode Server support with next.config.js should resize relative url and png accept header",
"with squoosh Production Mode Server support with next.config.js should resize relative url and webp Firefox accept header",
"with squoosh Production Mode Server support with next.config.js should resize relative url with invalid accept header as gif",
"with squoosh Production Mode Server support with next.config.js should resize relative url with invalid accept header as png",
"with squoosh Production Mode Server support with next.config.js should resize relative url with invalid accept header as tiff",
"with squoosh Production Mode Server support with next.config.js should return home page",
"with squoosh Production Mode Server support with next.config.js should set 304 status without body when etag matches if-none-match",
"with squoosh Production Mode Server support with next.config.js should set cache-control to immutable for static images",
"with squoosh Production Mode Server support with next.config.js should use cache and stale-while-revalidate when query is the same for external image",
"with squoosh Production Mode Server support with next.config.js should use cache and stale-while-revalidate when query is the same for internal image",
"with squoosh Production Mode Server support with next.config.js should use cached image file when parameters are the same for animated gif"
],
"pending": [],
"flakey": [],
"runtimeError": false
},
"test/integration/import-assertion/test/index.test.js": {
"passed": ["import-assertion dev should handle json assertions"],
"failed": [

View file

@ -13144,227 +13144,6 @@
"flakey": [],
"runtimeError": false
},
"test/integration/image-optimizer/test/squoosh.test.ts": {
"passed": [
"with squoosh dev support w/o next.config.js should downlevel avif format to jpeg for old Safari",
"with squoosh dev support w/o next.config.js should downlevel webp format to jpeg for old Safari",
"with squoosh dev support w/o next.config.js should emit blur svg when width is 8 in dev but not prod",
"with squoosh dev support w/o next.config.js should emit blur svg when width is less than 8 in dev but not prod",
"with squoosh dev support w/o next.config.js should error if the image file does not exist",
"with squoosh dev support w/o next.config.js should error if the resource isn't a valid image",
"with squoosh dev support w/o next.config.js should fail when domain is not defined in next.config.js",
"with squoosh dev support w/o next.config.js should fail when internal url is not an image",
"with squoosh dev support w/o next.config.js should fail when q is greater than 100",
"with squoosh dev support w/o next.config.js should fail when q is less than 1",
"with squoosh dev support w/o next.config.js should fail when q is missing",
"with squoosh dev support w/o next.config.js should fail when q is not a number",
"with squoosh dev support w/o next.config.js should fail when url has file protocol",
"with squoosh dev support w/o next.config.js should fail when url has ftp protocol",
"with squoosh dev support w/o next.config.js should fail when url is missing",
"with squoosh dev support w/o next.config.js should fail when w is 0",
"with squoosh dev support w/o next.config.js should fail when w is less than 0",
"with squoosh dev support w/o next.config.js should fail when w is missing",
"with squoosh dev support w/o next.config.js should fail when w is not a number",
"with squoosh dev support w/o next.config.js should fail when width is not in next.config.js",
"with squoosh dev support w/o next.config.js should handle non-ascii characters in image url",
"with squoosh dev support w/o next.config.js should maintain animated gif",
"with squoosh dev support w/o next.config.js should maintain animated png",
"with squoosh dev support w/o next.config.js should maintain animated png 2",
"with squoosh dev support w/o next.config.js should maintain animated webp",
"with squoosh dev support w/o next.config.js should maintain bmp",
"with squoosh dev support w/o next.config.js should maintain ico format",
"with squoosh dev support w/o next.config.js should maintain jpg format for old Safari",
"with squoosh dev support w/o next.config.js should maintain png format for old Safari",
"with squoosh dev support w/o next.config.js should not allow svg with application header",
"with squoosh dev support w/o next.config.js should not allow svg with comma header",
"with squoosh dev support w/o next.config.js should not allow svg with uppercase header",
"with squoosh dev support w/o next.config.js should not allow vector svg",
"with squoosh dev support w/o next.config.js should not change the color type of a png",
"with squoosh dev support w/o next.config.js should not have sharp missing warning",
"with squoosh dev support w/o next.config.js should not have sharp outdated warning",
"with squoosh dev support w/o next.config.js should not resize if requested width is larger than original source image",
"with squoosh dev support w/o next.config.js should resize relative url and old Chrome accept header as webp",
"with squoosh dev support w/o next.config.js should resize relative url and png accept header",
"with squoosh dev support w/o next.config.js should resize relative url and webp Firefox accept header",
"with squoosh dev support w/o next.config.js should resize relative url with invalid accept header as gif",
"with squoosh dev support w/o next.config.js should resize relative url with invalid accept header as png",
"with squoosh dev support w/o next.config.js should resize relative url with invalid accept header as tiff",
"with squoosh dev support w/o next.config.js should return home page",
"with squoosh dev support w/o next.config.js should set 304 status without body when etag matches if-none-match",
"with squoosh dev support w/o next.config.js should set cache-control to immutable for static images",
"with squoosh dev support w/o next.config.js should use cache and stale-while-revalidate when query is the same for internal image",
"with squoosh dev support w/o next.config.js should use cached image file when parameters are the same for animated gif",
"with squoosh dev support with next.config.js should automatically detect image type when content-type is octet-stream",
"with squoosh dev support with next.config.js should compress avif smaller than webp at q=100",
"with squoosh dev support with next.config.js should compress avif smaller than webp at q=50",
"with squoosh dev support with next.config.js should compress avif smaller than webp at q=75",
"with squoosh dev support with next.config.js should downlevel avif format to jpeg for old Safari",
"with squoosh dev support with next.config.js should downlevel webp format to jpeg for old Safari",
"with squoosh dev support with next.config.js should emit blur svg when width is 8 in dev but not prod",
"with squoosh dev support with next.config.js should emit blur svg when width is less than 8 in dev but not prod",
"with squoosh dev support with next.config.js should error if the image file does not exist",
"with squoosh dev support with next.config.js should error if the resource isn't a valid image",
"with squoosh dev support with next.config.js should fail when domain is not defined in next.config.js",
"with squoosh dev support with next.config.js should fail when internal url is not an image",
"with squoosh dev support with next.config.js should fail when q is greater than 100",
"with squoosh dev support with next.config.js should fail when q is less than 1",
"with squoosh dev support with next.config.js should fail when q is missing",
"with squoosh dev support with next.config.js should fail when q is not a number",
"with squoosh dev support with next.config.js should fail when url fails to load an image",
"with squoosh dev support with next.config.js should fail when url has file protocol",
"with squoosh dev support with next.config.js should fail when url has ftp protocol",
"with squoosh dev support with next.config.js should fail when url is missing",
"with squoosh dev support with next.config.js should fail when w is 0",
"with squoosh dev support with next.config.js should fail when w is less than 0",
"with squoosh dev support with next.config.js should fail when w is missing",
"with squoosh dev support with next.config.js should fail when w is not a number",
"with squoosh dev support with next.config.js should fail when width is not in next.config.js",
"with squoosh dev support with next.config.js should handle concurrent requests",
"with squoosh dev support with next.config.js should handle non-ascii characters in image url",
"with squoosh dev support with next.config.js should maintain animated gif",
"with squoosh dev support with next.config.js should maintain animated png",
"with squoosh dev support with next.config.js should maintain animated png 2",
"with squoosh dev support with next.config.js should maintain animated webp",
"with squoosh dev support with next.config.js should maintain bmp",
"with squoosh dev support with next.config.js should maintain ico format",
"with squoosh dev support with next.config.js should maintain jpg format for old Safari",
"with squoosh dev support with next.config.js should maintain png format for old Safari",
"with squoosh dev support with next.config.js should normalize invalid status codes",
"with squoosh dev support with next.config.js should not allow svg with application header",
"with squoosh dev support with next.config.js should not allow svg with comma header",
"with squoosh dev support with next.config.js should not allow svg with uppercase header",
"with squoosh dev support with next.config.js should not allow vector svg",
"with squoosh dev support with next.config.js should not change the color type of a png",
"with squoosh dev support with next.config.js should not have sharp missing warning",
"with squoosh dev support with next.config.js should not have sharp outdated warning",
"with squoosh dev support with next.config.js should not resize if requested width is larger than original source image",
"with squoosh dev support with next.config.js should resize absolute url from localhost",
"with squoosh dev support with next.config.js should resize relative url and new Chrome accept header as avif",
"with squoosh dev support with next.config.js should resize relative url and old Chrome accept header as webp",
"with squoosh dev support with next.config.js should resize relative url and png accept header",
"with squoosh dev support with next.config.js should resize relative url and webp Firefox accept header",
"with squoosh dev support with next.config.js should resize relative url with invalid accept header as gif",
"with squoosh dev support with next.config.js should resize relative url with invalid accept header as png",
"with squoosh dev support with next.config.js should resize relative url with invalid accept header as tiff",
"with squoosh dev support with next.config.js should return home page",
"with squoosh dev support with next.config.js should set 304 status without body when etag matches if-none-match",
"with squoosh dev support with next.config.js should set cache-control to immutable for static images",
"with squoosh dev support with next.config.js should use cache and stale-while-revalidate when query is the same for external image",
"with squoosh dev support with next.config.js should use cache and stale-while-revalidate when query is the same for internal image",
"with squoosh dev support with next.config.js should use cached image file when parameters are the same for animated gif"
],
"failed": [],
"pending": [
"with squoosh Production Mode Server support w/o next.config.js should downlevel avif format to jpeg for old Safari",
"with squoosh Production Mode Server support w/o next.config.js should downlevel webp format to jpeg for old Safari",
"with squoosh Production Mode Server support w/o next.config.js should emit blur svg when width is 8 in dev but not prod",
"with squoosh Production Mode Server support w/o next.config.js should emit blur svg when width is less than 8 in dev but not prod",
"with squoosh Production Mode Server support w/o next.config.js should error if the image file does not exist",
"with squoosh Production Mode Server support w/o next.config.js should error if the resource isn't a valid image",
"with squoosh Production Mode Server support w/o next.config.js should fail when domain is not defined in next.config.js",
"with squoosh Production Mode Server support w/o next.config.js should fail when internal url is not an image",
"with squoosh Production Mode Server support w/o next.config.js should fail when q is greater than 100",
"with squoosh Production Mode Server support w/o next.config.js should fail when q is less than 1",
"with squoosh Production Mode Server support w/o next.config.js should fail when q is missing",
"with squoosh Production Mode Server support w/o next.config.js should fail when q is not a number",
"with squoosh Production Mode Server support w/o next.config.js should fail when url has file protocol",
"with squoosh Production Mode Server support w/o next.config.js should fail when url has ftp protocol",
"with squoosh Production Mode Server support w/o next.config.js should fail when url is missing",
"with squoosh Production Mode Server support w/o next.config.js should fail when w is 0",
"with squoosh Production Mode Server support w/o next.config.js should fail when w is less than 0",
"with squoosh Production Mode Server support w/o next.config.js should fail when w is missing",
"with squoosh Production Mode Server support w/o next.config.js should fail when w is not a number",
"with squoosh Production Mode Server support w/o next.config.js should fail when width is not in next.config.js",
"with squoosh Production Mode Server support w/o next.config.js should handle non-ascii characters in image url",
"with squoosh Production Mode Server support w/o next.config.js should have sharp missing warning",
"with squoosh Production Mode Server support w/o next.config.js should maintain animated gif",
"with squoosh Production Mode Server support w/o next.config.js should maintain animated png",
"with squoosh Production Mode Server support w/o next.config.js should maintain animated png 2",
"with squoosh Production Mode Server support w/o next.config.js should maintain animated webp",
"with squoosh Production Mode Server support w/o next.config.js should maintain bmp",
"with squoosh Production Mode Server support w/o next.config.js should maintain ico format",
"with squoosh Production Mode Server support w/o next.config.js should maintain jpg format for old Safari",
"with squoosh Production Mode Server support w/o next.config.js should maintain png format for old Safari",
"with squoosh Production Mode Server support w/o next.config.js should not allow svg with application header",
"with squoosh Production Mode Server support w/o next.config.js should not allow svg with comma header",
"with squoosh Production Mode Server support w/o next.config.js should not allow svg with uppercase header",
"with squoosh Production Mode Server support w/o next.config.js should not allow vector svg",
"with squoosh Production Mode Server support w/o next.config.js should not change the color type of a png",
"with squoosh Production Mode Server support w/o next.config.js should not have sharp outdated warning",
"with squoosh Production Mode Server support w/o next.config.js should not resize if requested width is larger than original source image",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url and old Chrome accept header as webp",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url and png accept header",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url and webp Firefox accept header",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url with invalid accept header as gif",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url with invalid accept header as png",
"with squoosh Production Mode Server support w/o next.config.js should resize relative url with invalid accept header as tiff",
"with squoosh Production Mode Server support w/o next.config.js should return home page",
"with squoosh Production Mode Server support w/o next.config.js should set 304 status without body when etag matches if-none-match",
"with squoosh Production Mode Server support w/o next.config.js should set cache-control to immutable for static images",
"with squoosh Production Mode Server support w/o next.config.js should use cache and stale-while-revalidate when query is the same for internal image",
"with squoosh Production Mode Server support w/o next.config.js should use cached image file when parameters are the same for animated gif",
"with squoosh Production Mode Server support with next.config.js should automatically detect image type when content-type is octet-stream",
"with squoosh Production Mode Server support with next.config.js should compress avif smaller than webp at q=100",
"with squoosh Production Mode Server support with next.config.js should compress avif smaller than webp at q=50",
"with squoosh Production Mode Server support with next.config.js should compress avif smaller than webp at q=75",
"with squoosh Production Mode Server support with next.config.js should downlevel avif format to jpeg for old Safari",
"with squoosh Production Mode Server support with next.config.js should downlevel webp format to jpeg for old Safari",
"with squoosh Production Mode Server support with next.config.js should emit blur svg when width is 8 in dev but not prod",
"with squoosh Production Mode Server support with next.config.js should emit blur svg when width is less than 8 in dev but not prod",
"with squoosh Production Mode Server support with next.config.js should error if the image file does not exist",
"with squoosh Production Mode Server support with next.config.js should error if the resource isn't a valid image",
"with squoosh Production Mode Server support with next.config.js should fail when domain is not defined in next.config.js",
"with squoosh Production Mode Server support with next.config.js should fail when internal url is not an image",
"with squoosh Production Mode Server support with next.config.js should fail when q is greater than 100",
"with squoosh Production Mode Server support with next.config.js should fail when q is less than 1",
"with squoosh Production Mode Server support with next.config.js should fail when q is missing",
"with squoosh Production Mode Server support with next.config.js should fail when q is not a number",
"with squoosh Production Mode Server support with next.config.js should fail when url fails to load an image",
"with squoosh Production Mode Server support with next.config.js should fail when url has file protocol",
"with squoosh Production Mode Server support with next.config.js should fail when url has ftp protocol",
"with squoosh Production Mode Server support with next.config.js should fail when url is missing",
"with squoosh Production Mode Server support with next.config.js should fail when w is 0",
"with squoosh Production Mode Server support with next.config.js should fail when w is less than 0",
"with squoosh Production Mode Server support with next.config.js should fail when w is missing",
"with squoosh Production Mode Server support with next.config.js should fail when w is not a number",
"with squoosh Production Mode Server support with next.config.js should fail when width is not in next.config.js",
"with squoosh Production Mode Server support with next.config.js should handle concurrent requests",
"with squoosh Production Mode Server support with next.config.js should handle non-ascii characters in image url",
"with squoosh Production Mode Server support with next.config.js should have sharp missing warning",
"with squoosh Production Mode Server support with next.config.js should maintain animated gif",
"with squoosh Production Mode Server support with next.config.js should maintain animated png",
"with squoosh Production Mode Server support with next.config.js should maintain animated png 2",
"with squoosh Production Mode Server support with next.config.js should maintain animated webp",
"with squoosh Production Mode Server support with next.config.js should maintain bmp",
"with squoosh Production Mode Server support with next.config.js should maintain ico format",
"with squoosh Production Mode Server support with next.config.js should maintain jpg format for old Safari",
"with squoosh Production Mode Server support with next.config.js should maintain png format for old Safari",
"with squoosh Production Mode Server support with next.config.js should normalize invalid status codes",
"with squoosh Production Mode Server support with next.config.js should not allow svg with application header",
"with squoosh Production Mode Server support with next.config.js should not allow svg with comma header",
"with squoosh Production Mode Server support with next.config.js should not allow svg with uppercase header",
"with squoosh Production Mode Server support with next.config.js should not allow vector svg",
"with squoosh Production Mode Server support with next.config.js should not change the color type of a png",
"with squoosh Production Mode Server support with next.config.js should not have sharp outdated warning",
"with squoosh Production Mode Server support with next.config.js should not resize if requested width is larger than original source image",
"with squoosh Production Mode Server support with next.config.js should resize absolute url from localhost",
"with squoosh Production Mode Server support with next.config.js should resize relative url and new Chrome accept header as avif",
"with squoosh Production Mode Server support with next.config.js should resize relative url and old Chrome accept header as webp",
"with squoosh Production Mode Server support with next.config.js should resize relative url and png accept header",
"with squoosh Production Mode Server support with next.config.js should resize relative url and webp Firefox accept header",
"with squoosh Production Mode Server support with next.config.js should resize relative url with invalid accept header as gif",
"with squoosh Production Mode Server support with next.config.js should resize relative url with invalid accept header as png",
"with squoosh Production Mode Server support with next.config.js should resize relative url with invalid accept header as tiff",
"with squoosh Production Mode Server support with next.config.js should return home page",
"with squoosh Production Mode Server support with next.config.js should set 304 status without body when etag matches if-none-match",
"with squoosh Production Mode Server support with next.config.js should set cache-control to immutable for static images",
"with squoosh Production Mode Server support with next.config.js should use cache and stale-while-revalidate when query is the same for external image",
"with squoosh Production Mode Server support with next.config.js should use cache and stale-while-revalidate when query is the same for internal image",
"with squoosh Production Mode Server support with next.config.js should use cached image file when parameters are the same for animated gif"
],
"flakey": [],
"runtimeError": false
},
"test/integration/import-assertion/test/index.test.js": {
"passed": ["import-assertion dev should handle json assertions"],
"failed": [],