Skip to content

Commit

Permalink
fix: squoosh not working on Windows in certain situations (#7826)
Browse files Browse the repository at this point in the history
  • Loading branch information
Princesseuh authored Jul 26, 2023
1 parent 54fb03b commit 31c4031
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 41 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-balloons-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fix `astro:assets` not working on Windows in build when using Squoosh
14 changes: 3 additions & 11 deletions packages/astro/src/assets/services/squoosh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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<Operation | undefined> {
// 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<Operation | undefined> {
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.
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/assets/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
34 changes: 23 additions & 11 deletions packages/astro/src/assets/utils/emitAsset.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 {
Expand Down
19 changes: 2 additions & 17 deletions packages/astro/src/assets/utils/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
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<ImageMetadata | undefined> {
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<Omit<ImageMetadata, 'src'> | undefined> {
const { width, height, type, orientation } = imageSize(data);
const isPortrait = (orientation || 0) >= 5;

if (!width || !height || !type) {
return undefined;
}

return {
src: fileURLToPath(src),
width: isPortrait ? height : width,
height: isPortrait ? width : height,
format: type as ImageInputFormat,
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
Expand Down

0 comments on commit 31c4031

Please sign in to comment.