[ci] format
This commit is contained in:
parent
fad3867adb
commit
426f3bb40f
19 changed files with 166 additions and 159 deletions
|
@ -3,8 +3,8 @@ import { ssgBuild } from './build/ssg.js';
|
|||
import type { ImageService, SSRImageService, TransformOptions } from './loaders/index.js';
|
||||
import type { LoggerLevel } from './utils/logger.js';
|
||||
import { joinPaths, prependForwardSlash, propsToFilename } from './utils/paths.js';
|
||||
import { createPlugin } from './vite-plugin-astro-image.js';
|
||||
import { copyWasmFiles } from './vendor/squoosh/copy-wasm.js';
|
||||
import { createPlugin } from './vite-plugin-astro-image.js';
|
||||
|
||||
export { getImage } from './lib/get-image.js';
|
||||
export { getPicture } from './lib/get-picture.js';
|
||||
|
@ -48,19 +48,17 @@ export default function integration(options: IntegrationOptions = {}): AstroInte
|
|||
return {
|
||||
plugins: [createPlugin(_config, resolvedOptions)],
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
'image-size',
|
||||
].filter(Boolean),
|
||||
include: ['image-size'].filter(Boolean),
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: ["sharp"]
|
||||
}
|
||||
},
|
||||
rollupOptions: {
|
||||
external: ['sharp'],
|
||||
},
|
||||
},
|
||||
ssr: {
|
||||
noExternal: ['@astrojs/image', resolvedOptions.serviceEntryPoint],
|
||||
},
|
||||
assetsInclude: ['**/*.wasm']
|
||||
assetsInclude: ['**/*.wasm'],
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -78,18 +76,19 @@ export default function integration(options: IntegrationOptions = {}): AstroInte
|
|||
entryPoint: '@astrojs/image/endpoint',
|
||||
});
|
||||
}
|
||||
|
||||
const { default: defaultLoader } = await import(resolvedOptions.serviceEntryPoint === '@astrojs/image/sharp'
|
||||
? './loaders/sharp.js'
|
||||
: './loaders/squoosh.js'
|
||||
|
||||
const { default: defaultLoader } = await import(
|
||||
resolvedOptions.serviceEntryPoint === '@astrojs/image/sharp'
|
||||
? './loaders/sharp.js'
|
||||
: './loaders/squoosh.js'
|
||||
);
|
||||
|
||||
|
||||
globalThis.astroImage = {
|
||||
defaultLoader
|
||||
}
|
||||
defaultLoader,
|
||||
};
|
||||
},
|
||||
'astro:build:start': async ({ buildConfig }) => {
|
||||
_buildConfig = buildConfig
|
||||
_buildConfig = buildConfig;
|
||||
},
|
||||
'astro:build:setup': async () => {
|
||||
// Used to cache all images rendered to HTML
|
||||
|
@ -141,7 +140,7 @@ export default function integration(options: IntegrationOptions = {}): AstroInte
|
|||
if (resolvedOptions.serviceEntryPoint === '@astrojs/image/squoosh') {
|
||||
await copyWasmFiles(_buildConfig.server);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/// <reference types="astro/astro-jsx" />
|
||||
import mime from 'mime';
|
||||
import { OutputFormat, parseAspectRatio, TransformOptions } from '../loaders/index.js';
|
||||
import { extname } from '../utils/paths.js';
|
||||
import { ImageMetadata } from '../vite-plugin-astro-image.js';
|
||||
import { getImage } from './get-image.js';
|
||||
import { extname } from '../utils/paths.js';
|
||||
|
||||
export interface GetPictureParams {
|
||||
src: string | ImageMetadata | Promise<{ default: ImageMetadata }>;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { AstroConfig } from 'astro';
|
||||
import { htmlColorNames, type NamedColor } from '../utils/colornames.js';
|
||||
|
||||
/// <reference types="astro/astro-jsx" />
|
||||
|
@ -299,5 +298,8 @@ export abstract class BaseSSRService implements SSRImageService {
|
|||
return transform;
|
||||
}
|
||||
|
||||
abstract transform(inputBuffer: Buffer, transform: TransformOptions): Promise<{ data: Buffer, format: OutputFormat }>;
|
||||
abstract transform(
|
||||
inputBuffer: Buffer,
|
||||
transform: TransformOptions
|
||||
): Promise<{ data: Buffer; format: OutputFormat }>;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import sharp from 'sharp';
|
||||
import { BaseSSRService, isOutputFormatSupportsAlpha } from '../loaders/index.js';
|
||||
import type { SSRImageService } from '../loaders/index.js';
|
||||
import { BaseSSRService, isOutputFormatSupportsAlpha } from '../loaders/index.js';
|
||||
import type { OutputFormat, TransformOptions } from './index.js';
|
||||
|
||||
class SharpService extends BaseSSRService {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// @ts-ignore
|
||||
import { red } from 'kleur/colors';
|
||||
import { BaseSSRService } from './index.js';
|
||||
import { error } from '../utils/logger.js';
|
||||
import { metadata } from '../utils/metadata.js';
|
||||
import { isRemoteImage } from '../utils/paths.js';
|
||||
import type { OutputFormat, TransformOptions } from './index.js';
|
||||
import { processBuffer } from '../vendor/squoosh/image-pool.js';
|
||||
import type { Operation } from '../vendor/squoosh/image.js';
|
||||
import type { OutputFormat, TransformOptions } from './index.js';
|
||||
import { BaseSSRService } from './index.js';
|
||||
|
||||
class SquooshService extends BaseSSRService {
|
||||
async processAvif(image: any, transform: TransformOptions) {
|
||||
|
@ -58,7 +58,10 @@ class SquooshService extends BaseSSRService {
|
|||
};
|
||||
}
|
||||
|
||||
async autorotate(transform: TransformOptions, inputBuffer: Buffer): Promise<Operation | undefined> {
|
||||
async autorotate(
|
||||
transform: TransformOptions,
|
||||
inputBuffer: Buffer
|
||||
): Promise<Operation | undefined> {
|
||||
// check EXIF orientation data and rotate the image if needed
|
||||
try {
|
||||
const meta = await metadata(transform.src, inputBuffer);
|
||||
|
@ -74,15 +77,15 @@ class SquooshService extends BaseSSRService {
|
|||
case 8:
|
||||
return { type: 'rotate', numRotations: 3 };
|
||||
}
|
||||
} catch { }
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async transform(inputBuffer: Buffer, transform: TransformOptions) {
|
||||
const operations: Operation[] = [];
|
||||
|
||||
if (!isRemoteImage(transform.src)) {
|
||||
const autorotate = await this.autorotate(transform, inputBuffer)
|
||||
|
||||
const autorotate = await this.autorotate(transform, inputBuffer);
|
||||
|
||||
if (autorotate) {
|
||||
operations.push(autorotate);
|
||||
}
|
||||
|
@ -96,7 +99,7 @@ class SquooshService extends BaseSSRService {
|
|||
type: 'resize',
|
||||
width,
|
||||
height,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (!transform.format) {
|
||||
|
@ -108,12 +111,17 @@ class SquooshService extends BaseSSRService {
|
|||
throw new Error(`Unknown image output: "${transform.format}" used for ${transform.src}`);
|
||||
}
|
||||
|
||||
const data = await processBuffer(inputBuffer, operations, transform.format, transform.quality || 100);
|
||||
const data = await processBuffer(
|
||||
inputBuffer,
|
||||
operations,
|
||||
transform.format,
|
||||
transform.quality || 100
|
||||
);
|
||||
|
||||
return {
|
||||
data: Buffer.from(data),
|
||||
format: transform.format
|
||||
}
|
||||
format: transform.format,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
export default function execOnce<T extends (...args: any[]) => ReturnType<T>>(
|
||||
fn: T
|
||||
): T {
|
||||
let used = false
|
||||
let result: ReturnType<T>
|
||||
export default function execOnce<T extends (...args: any[]) => ReturnType<T>>(fn: T): T {
|
||||
let used = false;
|
||||
let result: ReturnType<T>;
|
||||
|
||||
return ((...args: any[]) => {
|
||||
if (!used) {
|
||||
used = true
|
||||
result = fn(...args)
|
||||
}
|
||||
return result
|
||||
}) as T
|
||||
return ((...args: any[]) => {
|
||||
if (!used) {
|
||||
used = true;
|
||||
result = fn(...args);
|
||||
}
|
||||
return result;
|
||||
}) as T;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ export interface Metadata extends ImageMetadata {
|
|||
}
|
||||
|
||||
export async function metadata(src: URL | string, data?: Buffer): Promise<Metadata | undefined> {
|
||||
const file = data || await fs.readFile(src);
|
||||
const file = data || (await fs.readFile(src));
|
||||
|
||||
const { width, height, type, orientation } = await sizeOf(file);
|
||||
const isPortrait = (orientation || 0) >= 5;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { OutputFormat, TransformOptions } from '../loaders/index.js';
|
||||
import { TransformOptions } from '../loaders/index.js';
|
||||
import { shorthash } from './shorthash.js';
|
||||
|
||||
export function isRemoteImage(src: string) {
|
||||
|
|
|
@ -1,125 +1,123 @@
|
|||
/* tslint-disable ban-types */
|
||||
import { Worker, parentPort } from 'worker_threads';
|
||||
import { TransformStream } from 'web-streams-polyfill';
|
||||
import { parentPort, Worker } from 'worker_threads';
|
||||
|
||||
function uuid() {
|
||||
return Array.from({ length: 16 }, () =>
|
||||
Math.floor(Math.random() * 256).toString(16),
|
||||
).join('');
|
||||
return Array.from({ length: 16 }, () => Math.floor(Math.random() * 256).toString(16)).join('');
|
||||
}
|
||||
|
||||
interface Job<I> {
|
||||
msg: I;
|
||||
resolve: (result: any) => void;
|
||||
reject: (reason: any) => void;
|
||||
msg: I;
|
||||
resolve: (result: any) => void;
|
||||
reject: (reason: any) => void;
|
||||
}
|
||||
|
||||
export default class WorkerPool<I, O> {
|
||||
public numWorkers: number;
|
||||
public jobQueue: TransformStream<Job<I>, Job<I>>;
|
||||
public workerQueue: TransformStream<Worker, Worker>;
|
||||
public done: Promise<void>;
|
||||
public numWorkers: number;
|
||||
public jobQueue: TransformStream<Job<I>, Job<I>>;
|
||||
public workerQueue: TransformStream<Worker, Worker>;
|
||||
public done: Promise<void>;
|
||||
|
||||
constructor(numWorkers: number, workerFile: string) {
|
||||
this.numWorkers = numWorkers;
|
||||
this.jobQueue = new TransformStream();
|
||||
this.workerQueue = new TransformStream();
|
||||
constructor(numWorkers: number, workerFile: string) {
|
||||
this.numWorkers = numWorkers;
|
||||
this.jobQueue = new TransformStream();
|
||||
this.workerQueue = new TransformStream();
|
||||
|
||||
const writer = this.workerQueue.writable.getWriter();
|
||||
for (let i = 0; i < numWorkers; i++) {
|
||||
writer.write(new Worker(workerFile));
|
||||
}
|
||||
writer.releaseLock();
|
||||
const writer = this.workerQueue.writable.getWriter();
|
||||
for (let i = 0; i < numWorkers; i++) {
|
||||
writer.write(new Worker(workerFile));
|
||||
}
|
||||
writer.releaseLock();
|
||||
|
||||
this.done = this._readLoop();
|
||||
}
|
||||
this.done = this._readLoop();
|
||||
}
|
||||
|
||||
async _readLoop() {
|
||||
const reader = this.jobQueue.readable.getReader();
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) {
|
||||
await this._terminateAll();
|
||||
return;
|
||||
}
|
||||
async _readLoop() {
|
||||
const reader = this.jobQueue.readable.getReader();
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) {
|
||||
await this._terminateAll();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
throw new Error('Reader did not return any value');
|
||||
}
|
||||
if (!value) {
|
||||
throw new Error('Reader did not return any value');
|
||||
}
|
||||
|
||||
const { msg, resolve, reject } = value;
|
||||
const worker = await this._nextWorker();
|
||||
this.jobPromise(worker, msg)
|
||||
.then((result) => resolve(result))
|
||||
.catch((reason) => reject(reason))
|
||||
.finally(() => {
|
||||
// Return the worker to the pool
|
||||
const writer = this.workerQueue.writable.getWriter();
|
||||
writer.write(worker);
|
||||
writer.releaseLock();
|
||||
});
|
||||
}
|
||||
}
|
||||
const { msg, resolve, reject } = value;
|
||||
const worker = await this._nextWorker();
|
||||
this.jobPromise(worker, msg)
|
||||
.then((result) => resolve(result))
|
||||
.catch((reason) => reject(reason))
|
||||
.finally(() => {
|
||||
// Return the worker to the pool
|
||||
const writer = this.workerQueue.writable.getWriter();
|
||||
writer.write(worker);
|
||||
writer.releaseLock();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async _nextWorker() {
|
||||
const reader = this.workerQueue.readable.getReader();
|
||||
const { value } = await reader.read();
|
||||
reader.releaseLock();
|
||||
if (!value) {
|
||||
throw new Error('No worker left');
|
||||
}
|
||||
async _nextWorker() {
|
||||
const reader = this.workerQueue.readable.getReader();
|
||||
const { value } = await reader.read();
|
||||
reader.releaseLock();
|
||||
if (!value) {
|
||||
throw new Error('No worker left');
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async _terminateAll() {
|
||||
for (let n = 0; n < this.numWorkers; n++) {
|
||||
const worker = await this._nextWorker();
|
||||
worker.terminate();
|
||||
}
|
||||
this.workerQueue.writable.close();
|
||||
}
|
||||
async _terminateAll() {
|
||||
for (let n = 0; n < this.numWorkers; n++) {
|
||||
const worker = await this._nextWorker();
|
||||
worker.terminate();
|
||||
}
|
||||
this.workerQueue.writable.close();
|
||||
}
|
||||
|
||||
async join() {
|
||||
this.jobQueue.writable.getWriter().close();
|
||||
await this.done;
|
||||
}
|
||||
async join() {
|
||||
this.jobQueue.writable.getWriter().close();
|
||||
await this.done;
|
||||
}
|
||||
|
||||
dispatchJob(msg: I): Promise<O> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const writer = this.jobQueue.writable.getWriter();
|
||||
writer.write({ msg, resolve, reject });
|
||||
writer.releaseLock();
|
||||
});
|
||||
}
|
||||
dispatchJob(msg: I): Promise<O> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const writer = this.jobQueue.writable.getWriter();
|
||||
writer.write({ msg, resolve, reject });
|
||||
writer.releaseLock();
|
||||
});
|
||||
}
|
||||
|
||||
private jobPromise(worker: Worker, msg: I) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = uuid();
|
||||
worker.postMessage({ msg, id });
|
||||
worker.on('message', function f({ error, result, id: rid }) {
|
||||
if (rid !== id) {
|
||||
return;
|
||||
}
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
worker.off('message', f);
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
private jobPromise(worker: Worker, msg: I) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = uuid();
|
||||
worker.postMessage({ msg, id });
|
||||
worker.on('message', function f({ error, result, id: rid }) {
|
||||
if (rid !== id) {
|
||||
return;
|
||||
}
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
worker.off('message', f);
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static useThisThreadAsWorker<I, O>(cb: (msg: I) => O) {
|
||||
parentPort!.on('message', async (data) => {
|
||||
const { msg, id } = data;
|
||||
try {
|
||||
const result = await cb(msg);
|
||||
parentPort!.postMessage({ result, id });
|
||||
} catch (e: any) {
|
||||
parentPort!.postMessage({ error: e.message, id });
|
||||
}
|
||||
});
|
||||
}
|
||||
static useThisThreadAsWorker<I, O>(cb: (msg: I) => O) {
|
||||
parentPort!.on('message', async (data) => {
|
||||
const { msg, id } = data;
|
||||
try {
|
||||
const result = await cb(msg);
|
||||
parentPort!.postMessage({ result, id });
|
||||
} catch (e: any) {
|
||||
parentPort!.postMessage({ error: e.message, id });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
import { dirname } from '../emscripten-utils.js';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
var Module = (function () {
|
||||
return function (Module) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
import { dirname } from '../emscripten-utils.js';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
var Module = (function () {
|
||||
return function (Module) {
|
||||
|
|
|
@ -83,7 +83,7 @@ const resizeInit = () => resize.default(fsp.readFile(pathify(resizeWasm.toString
|
|||
const rotateWasm = new URL('./rotate/rotate.wasm', import.meta.url)
|
||||
|
||||
// Our decoders currently rely on a `ImageData` global.
|
||||
import ImageData from './image_data.js';
|
||||
import ImageData from './image_data.js'
|
||||
(global as any).ImageData = ImageData
|
||||
|
||||
function resizeNameToIndex(
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { cpus } from 'os'
|
||||
import { isMainThread } from 'node:worker_threads';
|
||||
import { cpus } from 'os';
|
||||
import type { OutputFormat } from '../../loaders/index.js';
|
||||
import execOnce from '../../utils/execOnce.js';
|
||||
import WorkerPool from '../../utils/workerPool.js';
|
||||
import type { Operation } from './image.js';
|
||||
import * as impl from './impl.js';
|
||||
import execOnce from '../../utils/execOnce.js';
|
||||
import type { OutputFormat } from '../../loaders/index.js';
|
||||
|
||||
const getWorker = execOnce(
|
||||
() => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as impl from './impl.js';
|
||||
import type { OutputFormat } from '../../loaders/index.js';
|
||||
import * as impl from './impl.js';
|
||||
|
||||
type RotateOperation = {
|
||||
type: 'rotate'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
import { dirname } from '../emscripten-utils.js';
|
||||
import { createRequire } from 'module';
|
||||
import { dirname } from '../emscripten-utils.js';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
var Module = (function () {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
import { dirname } from '../emscripten-utils.js';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
var Module = (function () {
|
||||
return function (Module) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
import { dirname } from '../emscripten-utils.js';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
var Module = (function () {
|
||||
return function (Module) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
import { dirname } from '../emscripten-utils.js';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
var Module = (function () {
|
||||
return function (Module) {
|
||||
|
|
|
@ -89,7 +89,9 @@ export function createPlugin(config: AstroConfig, options: Required<IntegrationO
|
|||
return next();
|
||||
}
|
||||
|
||||
const transform = await globalThis.astroImage.defaultLoader.parseTransform(url.searchParams);
|
||||
const transform = await globalThis.astroImage.defaultLoader.parseTransform(
|
||||
url.searchParams
|
||||
);
|
||||
|
||||
if (!transform) {
|
||||
return next();
|
||||
|
|
Loading…
Reference in a new issue