-
Notifications
You must be signed in to change notification settings - Fork 5
/
set-image-dimensions.cjs
118 lines (94 loc) 路 2.53 KB
/
set-image-dimensions.cjs
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
118
'use strict';
const { Buffer } = require('node:buffer');
const { extname, dirname, isAbsolute, join, relative } = require('node:path');
const { JSDOM } = require('jsdom');
const sharp = require('sharp');
const { parse: parseSrcset } = require('srcset');
const config = require('../../config.cjs');
const isValidSourceUrl = (sourceUrl) => {
if (!sourceUrl) return false;
try {
return ['http:', 'https:'].includes(new URL(sourceUrl).protocol);
} catch {
return true;
}
};
const isUrl = (string) => {
try {
return Boolean(new URL(string));
} catch {
return false;
}
};
const getMetadata = async (sourceUrl) => {
if (isUrl(sourceUrl)) {
const response = await fetch(sourceUrl);
if (!response.ok) {
throw new Error(
`Failed to load resource: the server responded with a status of ${response.status}`,
);
}
const arrayBuffer = await response.arrayBuffer();
return sharp(Buffer.from(arrayBuffer)).metadata();
}
return sharp(sourceUrl).metadata();
};
const rebaseSourceUrl = (sourceUrl, outputPath) => {
if (isUrl(sourceUrl)) {
return sourceUrl;
}
if (isAbsolute(sourceUrl)) {
return join(config.get('srcDir'), sourceUrl);
}
return join(
config.get('srcDir'),
relative(
join(config.get('distDir'), config.get('publicPath')),
join(dirname(outputPath), sourceUrl),
),
);
};
const setDimensions = (element, width, height) => {
if (!element.hasAttribute('width')) {
element.setAttribute('width', width);
}
if (!element.hasAttribute('height')) {
element.setAttribute('height', height);
}
};
const setImageDimensions = async function (content) {
if (
!this.page.outputPath ||
!['.html', '.php'].includes(extname(this.page.outputPath))
) {
return content;
}
const dom = new JSDOM(content);
const {
window: { document },
} = dom;
await Promise.all([
...[...document.images]
.filter((element) => isValidSourceUrl(element.src))
.map(async (element) => {
const metadata = await getMetadata(
rebaseSourceUrl(element.src, this.page.outputPath),
);
setDimensions(element, metadata.width, metadata.height);
}),
...[...document.querySelectorAll('picture > source')]
.filter((element) => isValidSourceUrl(parseSrcset(element.srcset)[0].url))
.map(async (element) => {
const metadata = await getMetadata(
rebaseSourceUrl(
parseSrcset(element.srcset)[0].url,
this.page.outputPath,
),
);
setDimensions(element, metadata.width, metadata.height);
}),
]);
const result = dom.serialize();
return result;
};
module.exports = setImageDimensions;