-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Expand file tree
/
Copy pathindex.js
More file actions
117 lines (100 loc) · 4.28 KB
/
index.js
File metadata and controls
117 lines (100 loc) · 4.28 KB
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import process from 'node:process';
import { imagetools } from 'vite-imagetools';
import { image_plugin } from './vite-plugin.js';
/**
* @param {import('types/index.js').VitePluginOptions} [opts]
* @returns {import('vite').Plugin[]}
*/
export function enhancedImages(opts) {
const imagetools_instance = imagetools_plugin(opts);
return !process.versions.webcontainer
? [image_plugin(imagetools_instance), imagetools_instance]
: [];
}
/**
* @param {import('types/index.js').VitePluginOptions} [opts]
* @returns {import('vite').Plugin}
*/
function imagetools_plugin(opts) {
const get_formats = opts?.defaultFormats ?? default_formats;
const get_widths = opts?.defaultWidths ?? default_widths;
/** @type {Partial<import('vite-imagetools').VitePluginOptions>} */
const imagetools_opts = {
...opts?.imagetools,
defaultDirectives: async (url, metadata) => {
const { pathname, searchParams: qs } = url;
if (!qs.has('enhanced')) {
if (typeof opts?.imagetools?.defaultDirectives === 'function') {
return opts.imagetools.defaultDirectives(url, metadata);
}
if (opts?.imagetools?.defaultDirectives) {
return opts.imagetools.defaultDirectives;
}
return new URLSearchParams();
}
const meta = await metadata();
const img_width = qs.get('imgWidth');
const width = img_width ? parseInt(img_width) : meta.width;
if (!width) {
console.warn(`Could not determine width of image ${pathname}`);
return new URLSearchParams();
}
return new URLSearchParams({
as: 'picture',
format: get_formats(meta),
...get_widths(width, qs.get('imgSizes'))
});
},
namedExports: false
};
// TODO: generate img rather than picture if only a single format is provided
// by resolving the directives for the URL in the preprocessor
return imagetools(imagetools_opts);
}
/**
* @param {import('sharp').Metadata} meta
* @returns {string}
*/
function default_formats(meta) {
let fallback = 'jpg';
if (meta.pages && meta.pages > 1) {
fallback = meta.format === 'tiff' ? 'tiff' : 'gif';
} else if (meta.hasAlpha) {
fallback = 'png';
}
return `avif;webp;${fallback}`;
}
/**
* @param {number} width
* @param {string | null} sizes
* @returns {{ w: string; basePixels?: string }}
*/
function default_widths(width, sizes) {
// We don't really know what the user wants here. But if they have an image that's really big
// then we can probably assume they're always displaying it full viewport/breakpoint.
// If the user is displaying a responsive image then the size usually doesn't change that much
// Instead, the number of columns in the design may reduce and the image may take a greater
// fraction of the screen.
// Assume if they're bothering to specify sizes that it's going to take most of the screen
// as that's the case where an image may be rendered at very different sizes. Otherwise, it's
// probably a responsive image and a single size is okay (two when accounting for HiDPI).
if (sizes) {
// Use common device sizes. Doesn't hurt to include larger sizes as the user will rarely
// provide an image that large.
// https://screensiz.es/
// https://gs.statcounter.com/screen-resolution-stats (note: logical. we want physical)
// Include 1080 because lighthouse uses a moto g4 with 360 logical pixels and 3x pixel ratio.
return { w: `540;768;1080;1366;1536;1920;2560;3000;4096;5120;${width}` };
}
// Don't need more than 2x resolution. Note that due to this optimization, pixel density
// descriptors will often end up being cheaper as many mobile devices have pixel density ratios
// near 3 which would cause larger images to be chosen on mobile when using sizes.
// Most OLED screens that say they are 3x resolution, are actually 3x in the green color, but
// only 1.5x in the red and blue colors. Showing a 3x resolution image in the app vs a 2x
// resolution image will be visually the same, though the 3x image takes significantly more
// data. Even true 3x resolution screens are wasteful as the human eye cannot see that level of
// detail without something like a magnifying glass.
// https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/capping-image-fidelity-on-ultra-high-resolution-devices.html
const small_width = Math.round(width / 2).toString();
return { w: `${small_width};${width}`, basePixels: small_width };
}