WIP: testing config to switch between Squoosh and Sharp
This commit is contained in:
parent
ca0c7e8b83
commit
f174b2523e
12 changed files with 290 additions and 105 deletions
|
@ -22,6 +22,7 @@
|
|||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./sharp": "./dist/loaders/sharp.js",
|
||||
"./squoosh": "./dist/loaders/squoosh.js",
|
||||
"./endpoints/dev": "./dist/endpoints/dev.js",
|
||||
"./endpoints/prod": "./dist/endpoints/prod.js",
|
||||
"./components": "./components/index.js",
|
||||
|
@ -41,10 +42,10 @@
|
|||
"test": "mocha --exit --timeout 20000 test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@squoosh/lib": "^0.4.0",
|
||||
"etag": "^1.8.1",
|
||||
"image-size": "^1.0.1",
|
||||
"mrmime": "^1.0.0",
|
||||
"sharp": "^0.30.6",
|
||||
"slash": "^4.0.0",
|
||||
"tiny-glob": "^0.2.9"
|
||||
},
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import type { APIRoute } from 'astro';
|
||||
import { lookup } from 'mrmime';
|
||||
import loader from '../loaders/sharp.js';
|
||||
import { loadImage } from '../utils/images.js';
|
||||
|
||||
export const get: APIRoute = async ({ request }) => {
|
||||
// @ts-ignore
|
||||
const { default: loader } = await import('virtual:image-loader');
|
||||
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const transform = loader.parseTransform(url.searchParams);
|
||||
|
|
|
@ -33,7 +33,7 @@ export interface IntegrationOptions {
|
|||
|
||||
export default function integration(options: IntegrationOptions = {}): AstroIntegration {
|
||||
const resolvedOptions = {
|
||||
serviceEntryPoint: '@astrojs/image/sharp',
|
||||
serviceEntryPoint: '@astrojs/image/squoosh',
|
||||
logLevel: 'info' as LoggerLevel,
|
||||
...options,
|
||||
};
|
||||
|
@ -48,11 +48,15 @@ export default function integration(options: IntegrationOptions = {}): AstroInte
|
|||
return {
|
||||
plugins: [createPlugin(_config, resolvedOptions)],
|
||||
optimizeDeps: {
|
||||
include: ['image-size', 'sharp'],
|
||||
include: [
|
||||
'image-size',
|
||||
resolvedOptions.serviceEntryPoint === '@astrojs/image/sharp' && 'sharp',
|
||||
resolvedOptions.serviceEntryPoint === '@astrojs/image/squoosh' && '@squoosh/lib',
|
||||
].filter(Boolean),
|
||||
},
|
||||
ssr: {
|
||||
noExternal: ['@astrojs/image', resolvedOptions.serviceEntryPoint],
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import slash from 'slash';
|
||||
import { ROUTE_PATTERN } from '../constants.js';
|
||||
import { ImageService, isSSRService, OutputFormat, TransformOptions } from '../loaders/index.js';
|
||||
import sharp from '../loaders/sharp.js';
|
||||
import { isRemoteImage, parseAspectRatio } from '../utils/images.js';
|
||||
import { ImageMetadata } from '../vite-plugin-astro-image.js';
|
||||
|
||||
|
@ -126,15 +125,9 @@ export async function getImage(
|
|||
const isDev = import.meta.env?.DEV;
|
||||
const isLocalImage = !isRemoteImage(resolved.src);
|
||||
|
||||
const _loader = isDev && isLocalImage ? sharp : loader;
|
||||
|
||||
if (!_loader) {
|
||||
throw new Error('@astrojs/image: loader not found!');
|
||||
}
|
||||
|
||||
// For SSR services, build URLs for the injected route
|
||||
if (isSSRService(_loader)) {
|
||||
const { searchParams } = _loader.serializeTransform(resolved);
|
||||
if (isSSRService(loader)) {
|
||||
const { searchParams } = loader.serializeTransform(resolved);
|
||||
|
||||
// cache all images rendered to HTML
|
||||
if (globalThis.astroImage?.addStaticImage) {
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
/// <reference types="astro/astro-jsx" />
|
||||
|
||||
import { isAspectRatioString, isOutputFormat } from "../utils/images.js";
|
||||
|
||||
|
||||
export type InputFormat =
|
||||
| 'heic'
|
||||
| 'heif'
|
||||
|
@ -10,7 +14,7 @@ export type InputFormat =
|
|||
| 'webp'
|
||||
| 'gif';
|
||||
|
||||
export type OutputFormat = 'avif' | 'jpeg' | 'png' | 'webp';
|
||||
export type OutputFormat = 'avif' | 'jpeg' | 'jpg' | 'png' | 'webp';
|
||||
|
||||
/**
|
||||
* Defines the original image and transforms that need to be applied to it.
|
||||
|
@ -103,3 +107,85 @@ export function isHostedService(service: ImageService): service is ImageService
|
|||
export function isSSRService(service: ImageService): service is SSRImageService {
|
||||
return 'transform' in service;
|
||||
}
|
||||
|
||||
export abstract class BaseSSRService implements SSRImageService {
|
||||
async getImageAttributes(transform: TransformOptions) {
|
||||
// strip off the known attributes
|
||||
const { width, height, src, format, quality, aspectRatio, ...rest } = transform;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
width: width,
|
||||
height: height,
|
||||
};
|
||||
}
|
||||
|
||||
serializeTransform(transform: TransformOptions) {
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
if (transform.quality) {
|
||||
searchParams.append('q', transform.quality.toString());
|
||||
}
|
||||
|
||||
if (transform.format) {
|
||||
searchParams.append('f', transform.format);
|
||||
}
|
||||
|
||||
if (transform.width) {
|
||||
searchParams.append('w', transform.width.toString());
|
||||
}
|
||||
|
||||
if (transform.height) {
|
||||
searchParams.append('h', transform.height.toString());
|
||||
}
|
||||
|
||||
if (transform.aspectRatio) {
|
||||
searchParams.append('ar', transform.aspectRatio.toString());
|
||||
}
|
||||
|
||||
searchParams.append('href', transform.src);
|
||||
|
||||
return { searchParams };
|
||||
}
|
||||
|
||||
parseTransform(searchParams: URLSearchParams) {
|
||||
if (!searchParams.has('href')) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let transform: TransformOptions = { src: searchParams.get('href')! };
|
||||
|
||||
if (searchParams.has('q')) {
|
||||
transform.quality = parseInt(searchParams.get('q')!);
|
||||
}
|
||||
|
||||
if (searchParams.has('f')) {
|
||||
const format = searchParams.get('f')!;
|
||||
if (isOutputFormat(format)) {
|
||||
transform.format = format;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchParams.has('w')) {
|
||||
transform.width = parseInt(searchParams.get('w')!);
|
||||
}
|
||||
|
||||
if (searchParams.has('h')) {
|
||||
transform.height = parseInt(searchParams.get('h')!);
|
||||
}
|
||||
|
||||
if (searchParams.has('ar')) {
|
||||
const ratio = searchParams.get('ar')!;
|
||||
|
||||
if (isAspectRatioString(ratio)) {
|
||||
transform.aspectRatio = ratio;
|
||||
} else {
|
||||
transform.aspectRatio = parseFloat(ratio);
|
||||
}
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
abstract transform(inputBuffer: Buffer, transform: TransformOptions): Promise<{ data: Buffer, format: OutputFormat }>;
|
||||
}
|
||||
|
|
|
@ -1,86 +1,9 @@
|
|||
import sharp from 'sharp';
|
||||
import { isAspectRatioString, isOutputFormat } from '../utils/images.js';
|
||||
import { BaseSSRService } from './index.js';
|
||||
import type { OutputFormat, SSRImageService, TransformOptions } from './index.js';
|
||||
|
||||
class SharpService implements SSRImageService {
|
||||
async getImageAttributes(transform: TransformOptions) {
|
||||
// strip off the known attributes
|
||||
const { width, height, src, format, quality, aspectRatio, ...rest } = transform;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
width: width,
|
||||
height: height,
|
||||
};
|
||||
}
|
||||
|
||||
serializeTransform(transform: TransformOptions) {
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
if (transform.quality) {
|
||||
searchParams.append('q', transform.quality.toString());
|
||||
}
|
||||
|
||||
if (transform.format) {
|
||||
searchParams.append('f', transform.format);
|
||||
}
|
||||
|
||||
if (transform.width) {
|
||||
searchParams.append('w', transform.width.toString());
|
||||
}
|
||||
|
||||
if (transform.height) {
|
||||
searchParams.append('h', transform.height.toString());
|
||||
}
|
||||
|
||||
if (transform.aspectRatio) {
|
||||
searchParams.append('ar', transform.aspectRatio.toString());
|
||||
}
|
||||
|
||||
searchParams.append('href', transform.src);
|
||||
|
||||
return { searchParams };
|
||||
}
|
||||
|
||||
parseTransform(searchParams: URLSearchParams) {
|
||||
if (!searchParams.has('href')) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let transform: TransformOptions = { src: searchParams.get('href')! };
|
||||
|
||||
if (searchParams.has('q')) {
|
||||
transform.quality = parseInt(searchParams.get('q')!);
|
||||
}
|
||||
|
||||
if (searchParams.has('f')) {
|
||||
const format = searchParams.get('f')!;
|
||||
if (isOutputFormat(format)) {
|
||||
transform.format = format;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchParams.has('w')) {
|
||||
transform.width = parseInt(searchParams.get('w')!);
|
||||
}
|
||||
|
||||
if (searchParams.has('h')) {
|
||||
transform.height = parseInt(searchParams.get('h')!);
|
||||
}
|
||||
|
||||
if (searchParams.has('ar')) {
|
||||
const ratio = searchParams.get('ar')!;
|
||||
|
||||
if (isAspectRatioString(ratio)) {
|
||||
transform.aspectRatio = ratio;
|
||||
} else {
|
||||
transform.aspectRatio = parseFloat(ratio);
|
||||
}
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
class SharpService extends BaseSSRService {
|
||||
async transform(inputBuffer: Buffer, transform: TransformOptions) {
|
||||
const sharpImage = sharp(inputBuffer, { failOnError: false, pages: -1 });
|
||||
|
||||
|
|
130
packages/integrations/image/src/loaders/squoosh.ts
Normal file
130
packages/integrations/image/src/loaders/squoosh.ts
Normal file
|
@ -0,0 +1,130 @@
|
|||
// @ts-ignore
|
||||
import { ImagePool } from '@squoosh/lib';
|
||||
import { red } from 'kleur/colors';
|
||||
import { BaseSSRService } from './index.js';
|
||||
import { isAspectRatioString, isOutputFormat } from '../utils/images.js';
|
||||
import { error } from '../utils/logger.js';
|
||||
import { metadata } from '../utils/metadata.js';
|
||||
import type { OutputFormat, SSRImageService, TransformOptions } from './index.js';
|
||||
|
||||
class SquooshService extends BaseSSRService {
|
||||
/**
|
||||
* Squoosh doesn't support multithreading when transforming to AVIF files.
|
||||
*
|
||||
* https://github.com/GoogleChromeLabs/squoosh/issues/1111
|
||||
*/
|
||||
#imagePool = new ImagePool(1);
|
||||
|
||||
async processAvif(image: any, transform: TransformOptions) {
|
||||
const encodeOptions = transform.quality
|
||||
? { avif: { quality: transform.quality } }
|
||||
: { avif: {} };
|
||||
await image.encode(encodeOptions);
|
||||
const data = await image.encodedWith.avif;
|
||||
|
||||
return {
|
||||
data: data.binary,
|
||||
format: 'avif' as OutputFormat,
|
||||
};
|
||||
}
|
||||
|
||||
async processJpeg(image: any, transform: TransformOptions) {
|
||||
const encodeOptions = transform.quality
|
||||
? { mozjpeg: { quality: transform.quality } }
|
||||
: { mozjpeg: {} };
|
||||
await image.encode(encodeOptions);
|
||||
const data = await image.encodedWith.mozjpeg;
|
||||
|
||||
return {
|
||||
data: data.binary,
|
||||
format: 'jpeg' as OutputFormat,
|
||||
};
|
||||
}
|
||||
|
||||
async processPng(image: any, transform: TransformOptions) {
|
||||
await image.encode({ oxipng: {} });
|
||||
const data = await image.encodedWith.oxipng;
|
||||
|
||||
return {
|
||||
data: data.binary,
|
||||
format: 'png' as OutputFormat,
|
||||
};
|
||||
}
|
||||
|
||||
async processWebp(image: any, transform: TransformOptions) {
|
||||
const encodeOptions = transform.quality
|
||||
? { webp: { quality: transform.quality } }
|
||||
: { webp: {} };
|
||||
await image.encode(encodeOptions);
|
||||
const data = await image.encodedWith.webp;
|
||||
|
||||
return {
|
||||
data: data.binary,
|
||||
format: 'png' as OutputFormat,
|
||||
};
|
||||
}
|
||||
|
||||
async autorotate(image: any, transform: TransformOptions, inputBuffer: Buffer) {
|
||||
// check EXIF orientation data and rotate the image if needed
|
||||
const meta = await metadata(transform.src, inputBuffer);
|
||||
|
||||
switch (meta?.orientation) {
|
||||
case 3:
|
||||
case 4:
|
||||
await image.preprocess({ rotate: { numRotations: 2 } });
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
await image.preprocess({ rotate: { numRotations: 1 } });
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
await image.preprocess({ rotate: { numRotations: 3 } });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async transform(inputBuffer: Buffer, transform: TransformOptions) {
|
||||
const image = this.#imagePool.ingestImage(inputBuffer);
|
||||
|
||||
let preprocessOptions: any = {};
|
||||
|
||||
// Image files lie! Rotate the image based on EXIF data
|
||||
await this.autorotate(image, transform, inputBuffer);
|
||||
|
||||
if (transform.width || transform.height) {
|
||||
const width = transform.width && Math.round(transform.width);
|
||||
const height = transform.height && Math.round(transform.height);
|
||||
|
||||
preprocessOptions.resize = {
|
||||
width,
|
||||
height,
|
||||
};
|
||||
|
||||
await image.preprocess({ resize: { width, height } });
|
||||
}
|
||||
|
||||
switch (transform.format) {
|
||||
case 'avif':
|
||||
return await this.processAvif(image, transform);
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
return await this.processJpeg(image, transform);
|
||||
case 'png':
|
||||
return await this.processPng(image, transform);
|
||||
case 'webp':
|
||||
return await this.processWebp(image, transform);
|
||||
default:
|
||||
error({
|
||||
level: 'info',
|
||||
prefix: false,
|
||||
message: red(`Unknown image output: "${transform.format}" used for ${transform.src}`),
|
||||
});
|
||||
throw new Error(`Unknown image output: "${transform.format}" used for ${transform.src}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const service = new SquooshService();
|
||||
|
||||
export default service;
|
|
@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
|
|||
import type { OutputFormat, TransformOptions } from '../loaders/index.js';
|
||||
|
||||
export function isOutputFormat(value: string): value is OutputFormat {
|
||||
return ['avif', 'jpeg', 'png', 'webp'].includes(value);
|
||||
return ['avif', 'jpeg', 'jpg', 'png', 'webp'].includes(value);
|
||||
}
|
||||
|
||||
export function isAspectRatioString(value: string): value is `${number}:${number}` {
|
||||
|
|
|
@ -3,8 +3,12 @@ import fs from 'node:fs/promises';
|
|||
import { InputFormat } from '../loaders/index.js';
|
||||
import { ImageMetadata } from '../vite-plugin-astro-image.js';
|
||||
|
||||
export async function metadata(src: string): Promise<ImageMetadata | undefined> {
|
||||
const file = await fs.readFile(src);
|
||||
export interface Metadata extends ImageMetadata {
|
||||
orientation?: number;
|
||||
}
|
||||
|
||||
export async function metadata(src: string, data?: Buffer): Promise<Metadata | undefined> {
|
||||
const file = data || await fs.readFile(src);
|
||||
|
||||
const { width, height, type, orientation } = await sizeOf(file);
|
||||
const isPortrait = (orientation || 0) >= 5;
|
||||
|
@ -18,5 +22,6 @@ export async function metadata(src: string): Promise<ImageMetadata | undefined>
|
|||
width: isPortrait ? height : width,
|
||||
height: isPortrait ? width : height,
|
||||
format: type as InputFormat,
|
||||
orientation,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ describe('Image rotation', function () {
|
|||
const url = new URL('./fixtures/rotation/dist/' + pathname, import.meta.url);
|
||||
const dist = fileURLToPath(url);
|
||||
const result = sizeOf(dist);
|
||||
expect(result).to.deep.equal(expected);
|
||||
expect(result, pathname).to.deep.equal(expected);
|
||||
}
|
||||
|
||||
describe('build', () => {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { expect } from 'chai';
|
||||
import sharp from '../dist/loaders/sharp.js';
|
||||
import { BaseSSRService } from '../dist/loaders/index.js';
|
||||
|
||||
describe('abstract SSR service', () => {
|
||||
const service = new BaseSSRService();
|
||||
|
||||
describe('Sharp service', () => {
|
||||
describe('serializeTransform', () => {
|
||||
const src = '/assets/image.png';
|
||||
|
||||
|
@ -16,7 +18,7 @@ describe('Sharp service', () => {
|
|||
['aspect ratio float', { src, aspectRatio: 1.7 }],
|
||||
].forEach(([description, props]) => {
|
||||
it(description, async () => {
|
||||
const { searchParams } = await sharp.serializeTransform(props);
|
||||
const { searchParams } = await service.serializeTransform(props);
|
||||
|
||||
function verifyProp(expected, search) {
|
||||
if (expected) {
|
||||
|
@ -52,7 +54,7 @@ describe('Sharp service', () => {
|
|||
].forEach(([description, params, expected]) => {
|
||||
it(description, async () => {
|
||||
const searchParams = new URLSearchParams(params);
|
||||
const props = sharp.parseTransform(searchParams);
|
||||
const props = service.parseTransform(searchParams);
|
||||
|
||||
expect(props).to.deep.equal(expected);
|
||||
});
|
||||
|
|
|
@ -2192,6 +2192,7 @@ importers:
|
|||
|
||||
packages/integrations/image:
|
||||
specifiers:
|
||||
'@squoosh/lib': ^0.4.0
|
||||
'@types/etag': ^1.8.1
|
||||
'@types/sharp': ^0.30.4
|
||||
astro: workspace:*
|
||||
|
@ -2200,14 +2201,13 @@ importers:
|
|||
image-size: ^1.0.1
|
||||
kleur: ^4.1.4
|
||||
mrmime: ^1.0.0
|
||||
sharp: ^0.30.6
|
||||
slash: ^4.0.0
|
||||
tiny-glob: ^0.2.9
|
||||
dependencies:
|
||||
'@squoosh/lib': 0.4.0
|
||||
etag: 1.8.1
|
||||
image-size: 1.0.2
|
||||
mrmime: 1.0.1
|
||||
sharp: 0.30.7
|
||||
slash: 4.0.0
|
||||
tiny-glob: 0.2.9
|
||||
devDependencies:
|
||||
|
@ -2242,10 +2242,13 @@ importers:
|
|||
'@astrojs/image': workspace:*
|
||||
'@astrojs/node': workspace:*
|
||||
astro: workspace:*
|
||||
sharp: ^0.30.7
|
||||
dependencies:
|
||||
'@astrojs/image': link:../../..
|
||||
'@astrojs/node': link:../../../../node
|
||||
astro: link:../../../../../astro
|
||||
devDependencies:
|
||||
sharp: 0.30.7
|
||||
|
||||
packages/integrations/lit:
|
||||
specifiers:
|
||||
|
@ -8440,6 +8443,14 @@ packages:
|
|||
- react-dom
|
||||
dev: false
|
||||
|
||||
/@squoosh/lib/0.4.0:
|
||||
resolution: {integrity: sha512-O1LyugWLZjMI4JZeZMA5vzfhfPjfMZXH5/HmVkRagP8B70wH3uoR7tjxfGNdSavey357MwL8YJDxbGwBBdHp7Q==}
|
||||
engines: {node: ' ^12.5.0 || ^14.0.0 || ^16.0.0 '}
|
||||
dependencies:
|
||||
wasm-feature-detect: 1.2.11
|
||||
web-streams-polyfill: 3.2.1
|
||||
dev: false
|
||||
|
||||
/@surma/rollup-plugin-off-main-thread/2.2.3:
|
||||
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
|
||||
dependencies:
|
||||
|
@ -9627,6 +9638,7 @@ packages:
|
|||
buffer: 5.7.1
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.0
|
||||
dev: true
|
||||
|
||||
/bl/5.0.0:
|
||||
resolution: {integrity: sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==}
|
||||
|
@ -9708,6 +9720,7 @@ packages:
|
|||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
ieee754: 1.2.1
|
||||
dev: true
|
||||
|
||||
/buffer/6.0.3:
|
||||
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
|
||||
|
@ -9976,6 +9989,7 @@ packages:
|
|||
dependencies:
|
||||
color-name: 1.1.4
|
||||
simple-swizzle: 0.2.2
|
||||
dev: true
|
||||
|
||||
/color-support/1.1.3:
|
||||
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
||||
|
@ -9988,6 +10002,7 @@ packages:
|
|||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
color-string: 1.9.1
|
||||
dev: true
|
||||
|
||||
/colorette/2.0.19:
|
||||
resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
|
||||
|
@ -10262,6 +10277,7 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
mimic-response: 3.1.0
|
||||
dev: true
|
||||
|
||||
/dedent-js/1.0.1:
|
||||
resolution: {integrity: sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==}
|
||||
|
@ -10513,6 +10529,7 @@ packages:
|
|||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
dev: true
|
||||
|
||||
/enquirer/2.3.6:
|
||||
resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
|
||||
|
@ -11259,6 +11276,7 @@ packages:
|
|||
/expand-template/2.0.3:
|
||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/extend-shallow/2.0.1:
|
||||
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
|
||||
|
@ -11440,6 +11458,7 @@ packages:
|
|||
|
||||
/fs-constants/1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
dev: true
|
||||
|
||||
/fs-extra/7.0.1:
|
||||
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
|
||||
|
@ -11601,7 +11620,8 @@ packages:
|
|||
dev: true
|
||||
|
||||
/github-from-package/0.0.0:
|
||||
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
|
||||
resolution: {integrity: sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=}
|
||||
dev: true
|
||||
|
||||
/github-slugger/1.4.0:
|
||||
resolution: {integrity: sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==}
|
||||
|
@ -12132,6 +12152,7 @@ packages:
|
|||
|
||||
/is-arrayish/0.3.2:
|
||||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||
dev: true
|
||||
|
||||
/is-bigint/1.0.4:
|
||||
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
|
||||
|
@ -13355,6 +13376,7 @@ packages:
|
|||
/mimic-response/3.1.0:
|
||||
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/min-indent/1.0.1:
|
||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||
|
@ -13466,6 +13488,7 @@ packages:
|
|||
|
||||
/mkdirp-classic/0.5.3:
|
||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||
dev: true
|
||||
|
||||
/mkdirp/0.5.6:
|
||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||
|
@ -13547,6 +13570,7 @@ packages:
|
|||
|
||||
/napi-build-utils/1.0.2:
|
||||
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
||||
dev: true
|
||||
|
||||
/natural-compare/1.4.0:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
|
@ -13596,9 +13620,11 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
semver: 7.3.7
|
||||
dev: true
|
||||
|
||||
/node-addon-api/5.0.0:
|
||||
resolution: {integrity: sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==}
|
||||
dev: true
|
||||
|
||||
/node-domexception/1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
|
@ -14564,6 +14590,7 @@ packages:
|
|||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.1
|
||||
tunnel-agent: 0.6.0
|
||||
dev: true
|
||||
|
||||
/preferred-pm/3.0.3:
|
||||
resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==}
|
||||
|
@ -14684,6 +14711,7 @@ packages:
|
|||
dependencies:
|
||||
end-of-stream: 1.4.4
|
||||
once: 1.4.0
|
||||
dev: true
|
||||
|
||||
/punycode/2.1.1:
|
||||
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
|
||||
|
@ -15357,6 +15385,7 @@ packages:
|
|||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.1
|
||||
tunnel-agent: 0.6.0
|
||||
dev: true
|
||||
|
||||
/shebang-command/1.2.0:
|
||||
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
|
||||
|
@ -15419,6 +15448,7 @@ packages:
|
|||
|
||||
/simple-concat/1.0.1:
|
||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
||||
dev: true
|
||||
|
||||
/simple-get/4.0.1:
|
||||
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
|
||||
|
@ -15426,11 +15456,13 @@ packages:
|
|||
decompress-response: 6.0.0
|
||||
once: 1.4.0
|
||||
simple-concat: 1.0.1
|
||||
dev: true
|
||||
|
||||
/simple-swizzle/0.2.2:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
dev: true
|
||||
|
||||
/sirv/1.0.19:
|
||||
resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==}
|
||||
|
@ -15934,6 +15966,7 @@ packages:
|
|||
mkdirp-classic: 0.5.3
|
||||
pump: 3.0.0
|
||||
tar-stream: 2.2.0
|
||||
dev: true
|
||||
|
||||
/tar-stream/2.2.0:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
|
@ -15944,6 +15977,7 @@ packages:
|
|||
fs-constants: 1.0.0
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.0
|
||||
dev: true
|
||||
|
||||
/tar/4.4.19:
|
||||
resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==}
|
||||
|
@ -16158,6 +16192,7 @@ packages:
|
|||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: true
|
||||
|
||||
/turbo-darwin-64/1.2.5:
|
||||
resolution: {integrity: sha512-AjMEF8hlA9vy1gXLHBruqgO42s0M0rKKZLQPM239wli5lKEprmxd8WMSjd9YmxRflS+/fwrXfjVl0QRhHjDIww==}
|
||||
|
@ -16846,6 +16881,10 @@ packages:
|
|||
'@vue/server-renderer': 3.2.37_vue@3.2.37
|
||||
'@vue/shared': 3.2.37
|
||||
|
||||
/wasm-feature-detect/1.2.11:
|
||||
resolution: {integrity: sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w==}
|
||||
dev: false
|
||||
|
||||
/wcwidth/1.0.1:
|
||||
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
||||
dependencies:
|
||||
|
|
Loading…
Reference in a new issue