From 31c4031ba7aea132a861f2465f38a83741f0cd05 Mon Sep 17 00:00:00 2001 From: Erika <3019731+Princesseuh@users.noreply.github.com> Date: Wed, 26 Jul 2023 21:38:37 +0200 Subject: [PATCH] fix: squoosh not working on Windows in certain situations (#7826) --- .changeset/calm-balloons-study.md | 5 +++ packages/astro/src/assets/services/squoosh.ts | 14 ++------ packages/astro/src/assets/types.ts | 2 +- packages/astro/src/assets/utils/emitAsset.ts | 34 +++++++++++++------ packages/astro/src/assets/utils/metadata.ts | 19 ++--------- .../fixtures/core-image-ssr/src/pages/api.ts | 2 +- 6 files changed, 35 insertions(+), 41 deletions(-) create mode 100644 .changeset/calm-balloons-study.md diff --git a/.changeset/calm-balloons-study.md b/.changeset/calm-balloons-study.md new file mode 100644 index 000000000000..cf81946defac --- /dev/null +++ b/.changeset/calm-balloons-study.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix `astro:assets` not working on Windows in build when using Squoosh diff --git a/packages/astro/src/assets/services/squoosh.ts b/packages/astro/src/assets/services/squoosh.ts index c60142b2c37a..4ba78f8d3898 100644 --- a/packages/astro/src/assets/services/squoosh.ts +++ b/packages/astro/src/assets/services/squoosh.ts @@ -7,7 +7,6 @@ import { parseQuality, type BaseServiceTransform, type LocalImageService, - type LocalImageTransform, } from './service.js'; import { processBuffer } from './vendor/squoosh/image-pool.js'; import type { Operation } from './vendor/squoosh/image.js'; @@ -30,15 +29,8 @@ const qualityTable: Record< // Squoosh's PNG encoder does not support a quality setting, so we can skip that here }; -async function getRotationForEXIF( - transform: LocalImageTransform, - inputBuffer: Buffer -): Promise { - // check EXIF orientation data and rotate the image if needed - const filePath = transform.src.slice('/@fs'.length); - const filePathURL = new URL('.' + filePath, 'file:'); - const meta = await imageMetadata(filePathURL, inputBuffer); - +async function getRotationForEXIF(inputBuffer: Buffer): Promise { + const meta = await imageMetadata(inputBuffer); if (!meta) return undefined; // EXIF orientations are a bit hard to read, but the numbers are actually standard. See https://exiftool.org/TagNames/EXIF.html for a list. @@ -71,7 +63,7 @@ const service: LocalImageService = { const operations: Operation[] = []; - const rotation = await getRotationForEXIF(transform, inputBuffer); + const rotation = await getRotationForEXIF(inputBuffer); if (rotation) { operations.push(rotation); diff --git a/packages/astro/src/assets/types.ts b/packages/astro/src/assets/types.ts index d4a8c4c89590..5632d76917af 100644 --- a/packages/astro/src/assets/types.ts +++ b/packages/astro/src/assets/types.ts @@ -17,7 +17,7 @@ declare global { } /** - * Type returned by ESM imports of images and direct calls to imageMetadata + * Type returned by ESM imports of images */ export interface ImageMetadata { src: string; diff --git a/packages/astro/src/assets/utils/emitAsset.ts b/packages/astro/src/assets/utils/emitAsset.ts index e1d66dfc7476..9b83a020a795 100644 --- a/packages/astro/src/assets/utils/emitAsset.ts +++ b/packages/astro/src/assets/utils/emitAsset.ts @@ -1,4 +1,4 @@ -import fs from 'node:fs'; +import fs from 'node:fs/promises'; import path from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { prependForwardSlash, slash } from '../../core/path.js'; @@ -15,34 +15,46 @@ export async function emitESMImage( } const url = pathToFileURL(id); - const meta = await imageMetadata(url); + let fileData: Buffer; + try { + fileData = await fs.readFile(url); + } catch (err) { + return undefined; + } - if (!meta) { + const fileMetadata = await imageMetadata(fileData); + + if (!fileMetadata) { return undefined; } + const emittedImage: ImageMetadata = { + src: '', + ...fileMetadata, + }; + // Build if (!watchMode) { const pathname = decodeURI(url.pathname); - const filename = path.basename(pathname, path.extname(pathname) + `.${meta.format}`); + const filename = path.basename(pathname, path.extname(pathname) + `.${fileMetadata.format}`); const handle = fileEmitter({ name: filename, - source: await fs.promises.readFile(url), + source: await fs.readFile(url), type: 'asset', }); - meta.src = `__ASTRO_ASSET_IMAGE__${handle}__`; + emittedImage.src = `__ASTRO_ASSET_IMAGE__${handle}__`; } else { // Pass the original file information through query params so we don't have to load the file twice - url.searchParams.append('origWidth', meta.width.toString()); - url.searchParams.append('origHeight', meta.height.toString()); - url.searchParams.append('origFormat', meta.format); + url.searchParams.append('origWidth', fileMetadata.width.toString()); + url.searchParams.append('origHeight', fileMetadata.height.toString()); + url.searchParams.append('origFormat', fileMetadata.format); - meta.src = `/@fs` + prependForwardSlash(fileURLToNormalizedPath(url)); + emittedImage.src = `/@fs` + prependForwardSlash(fileURLToNormalizedPath(url)); } - return meta; + return emittedImage; } function fileURLToNormalizedPath(filePath: URL): string { diff --git a/packages/astro/src/assets/utils/metadata.ts b/packages/astro/src/assets/utils/metadata.ts index 8d1f1bc4a396..de4136b36b26 100644 --- a/packages/astro/src/assets/utils/metadata.ts +++ b/packages/astro/src/assets/utils/metadata.ts @@ -1,22 +1,8 @@ -import fs from 'node:fs/promises'; -import { fileURLToPath } from 'node:url'; import type { ImageInputFormat, ImageMetadata } from '../types.js'; import imageSize from '../vendor/image-size/index.js'; -export async function imageMetadata( - src: URL | string, - data?: Buffer -): Promise { - let file = data; - if (!file) { - try { - file = await fs.readFile(src); - } catch (e) { - return undefined; - } - } - - const { width, height, type, orientation } = imageSize(file); +export async function imageMetadata(data: Buffer): Promise | undefined> { + const { width, height, type, orientation } = imageSize(data); const isPortrait = (orientation || 0) >= 5; if (!width || !height || !type) { @@ -24,7 +10,6 @@ export async function imageMetadata( } return { - src: fileURLToPath(src), width: isPortrait ? height : width, height: isPortrait ? width : height, format: type as ImageInputFormat, diff --git a/packages/astro/test/fixtures/core-image-ssr/src/pages/api.ts b/packages/astro/test/fixtures/core-image-ssr/src/pages/api.ts index a5526e1a161e..c10946318d82 100644 --- a/packages/astro/test/fixtures/core-image-ssr/src/pages/api.ts +++ b/packages/astro/test/fixtures/core-image-ssr/src/pages/api.ts @@ -1,4 +1,4 @@ -import { APIRoute } from "../../../../../src/@types/astro"; +import type { APIRoute } from "../../../../../src/@types/astro"; export const get = (async ({ params, request }) => { const url = new URL(request.url);