/
Picture.runtime.astro
92 lines (84 loc) · 2.37 KB
/
Picture.runtime.astro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
---
import type { PictureComponentRemoteImageProps } from '@astrojs/image/components/';
import { join as joinPath } from 'node:path';
import { readFileSync } from 'node:fs';
import { getPicture } from './get-picture';
export type Props = Omit<PictureComponentRemoteImageProps, 'aspectRatio'> & {
aspectRatio?: PictureComponentRemoteImageProps['aspectRatio'],
fetchpriority?: 'high' | 'low' | 'auto',
};
const { STOREFRONT_BASE_DIR } = process.env;
const baseDir = STOREFRONT_BASE_DIR || process.cwd();
type OriginalImage = { filepath: string, width: number, height: number };
const originalImages: OriginalImage[] = [];
const manifestFilepath = joinPath(baseDir, 'dist/server/images.src.csv');
readFileSync(manifestFilepath, 'utf-8').split(/\n/).forEach((line) => {
const [filepath, width, height] = line.split(',');
originalImages.push({
filepath,
width: Number(width),
height: Number(height),
});
});
const tryImageSize = (src: string) => {
let dimensions: { width?: number, height?: number } = {};
if (typeof src === 'string' && src.startsWith('/')) {
const originalImage = originalImages.find(({ filepath }) => {
return new RegExp(`^/${filepath}\\??.*`).test(src);
});
if (originalImage) {
const { width, height } = originalImage;
dimensions = { width, height };
}
}
return dimensions;
};
const getAspectRatio = (src: string | { width?: number, height?: number }) => {
if (typeof src === 'string') {
src = tryImageSize(src);
}
if (src.width) {
return src.height ? src.width / src.height : 1;
}
return 0;
};
const {
src,
alt,
sizes,
widths,
aspectRatio: propAspectRatio,
fit,
background,
position,
formats = ['avif', 'webp'],
loading = 'lazy',
decoding = 'async',
...attrs
} = Astro.props;
let aspectRatio = propAspectRatio;
if ((!attrs.width || !attrs.height) && !aspectRatio && typeof src === 'string') {
const { width, height } = tryImageSize(src);
if (height) {
aspectRatio = getAspectRatio({ width, height });
attrs.width = width;
attrs.height = height;
}
}
const { image, sources } = await getPicture({
src,
widths,
formats,
aspectRatio,
fit,
background,
position,
alt,
});
delete image.width;
delete image.height;
---
<picture>
{sources.map((attrs) => <source {...attrs} sizes={sizes} />)}
<img {...image} loading={loading} decoding={decoding} {...attrs} />
</picture>