@riebeckite/plugin-svg-optimizer 0.0.35 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +98 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ function resolveSvgOptimizerOptions(options = {}) {
|
|
|
16
16
|
function svgOptimizer(options = {}) {
|
|
17
17
|
const resolved = resolveSvgOptimizerOptions(options);
|
|
18
18
|
const config = svgoConfig(resolved);
|
|
19
|
+
let stats = emptyStats();
|
|
19
20
|
return definePlugin({
|
|
20
21
|
name: PLUGIN_NAME,
|
|
21
22
|
order: 60,
|
|
@@ -26,16 +27,20 @@ function svgOptimizer(options = {}) {
|
|
|
26
27
|
}),
|
|
27
28
|
options,
|
|
28
29
|
transformAssets: async ({ assets, readAsset, cache, logger, tracer }) => {
|
|
30
|
+
stats = emptyStats();
|
|
29
31
|
if (resolved.keepOriginal) return [];
|
|
30
32
|
const outputs = [];
|
|
31
33
|
for (const asset of assets) {
|
|
32
34
|
if (extensionOf(asset.path) !== "svg") continue;
|
|
35
|
+
stats.inputs += 1;
|
|
33
36
|
if (asset.size !== void 0 && asset.size > DEFAULT_MAX_INPUT_BYTES) {
|
|
37
|
+
stats.skipped.push({ path: asset.path, reason: "oversized" });
|
|
34
38
|
logger.warn(`Skipped oversized SVG asset: ${asset.path}`);
|
|
35
39
|
continue;
|
|
36
40
|
}
|
|
37
41
|
const input = await readAsset(asset.path);
|
|
38
42
|
if (!input || input.byteLength > DEFAULT_MAX_INPUT_BYTES) {
|
|
43
|
+
stats.skipped.push({ path: asset.path, reason: "unreadable" });
|
|
39
44
|
logger.warn(
|
|
40
45
|
`Skipped oversized or unreadable SVG asset: ${asset.path}`
|
|
41
46
|
);
|
|
@@ -44,14 +49,22 @@ function svgOptimizer(options = {}) {
|
|
|
44
49
|
const cacheKey = assetCacheKey(asset.path, input);
|
|
45
50
|
const cached = await cache.get(cacheKey);
|
|
46
51
|
if (isCachedSvgTransform(cached)) {
|
|
52
|
+
stats.cacheHits += 1;
|
|
47
53
|
tracer.event("svg-transform.cache-hit", { path: asset.path });
|
|
48
54
|
if (cached.content !== null) {
|
|
49
|
-
|
|
55
|
+
const output = outputFor(asset.path, cached.content);
|
|
56
|
+
stats.optimized += 1;
|
|
57
|
+
stats.savedBytes += input.byteLength - output.content.byteLength;
|
|
58
|
+
outputs.push(output);
|
|
59
|
+
} else {
|
|
60
|
+
stats.noReduction += 1;
|
|
50
61
|
}
|
|
51
62
|
continue;
|
|
52
63
|
}
|
|
64
|
+
stats.cacheMisses += 1;
|
|
53
65
|
const source = decode(input);
|
|
54
66
|
if (source === null) {
|
|
67
|
+
stats.skipped.push({ path: asset.path, reason: "invalid UTF-8" });
|
|
55
68
|
logger.warn(
|
|
56
69
|
`Skipped SVG asset that is not valid UTF-8: ${asset.path}`
|
|
57
70
|
);
|
|
@@ -60,6 +73,7 @@ function svgOptimizer(options = {}) {
|
|
|
60
73
|
}
|
|
61
74
|
const unsafe = unsafeReason(source);
|
|
62
75
|
if (unsafe) {
|
|
76
|
+
stats.skipped.push({ path: asset.path, reason: unsafe });
|
|
63
77
|
logger.warn(
|
|
64
78
|
`Skipped SVG asset containing ${unsafe}: ${asset.path}. Optimization is not sanitization.`
|
|
65
79
|
);
|
|
@@ -70,6 +84,7 @@ function svgOptimizer(options = {}) {
|
|
|
70
84
|
try {
|
|
71
85
|
optimized = optimize(source, config).data;
|
|
72
86
|
} catch {
|
|
87
|
+
stats.skipped.push({ path: asset.path, reason: "optimize failed" });
|
|
73
88
|
logger.warn(
|
|
74
89
|
`Skipped SVG asset that could not be optimized: ${asset.path}`
|
|
75
90
|
);
|
|
@@ -78,6 +93,7 @@ function svgOptimizer(options = {}) {
|
|
|
78
93
|
}
|
|
79
94
|
const content = Buffer.from(optimized, "utf8");
|
|
80
95
|
if (content.byteLength >= input.byteLength) {
|
|
96
|
+
stats.noReduction += 1;
|
|
81
97
|
tracer.event("svg-transform.no-reduction", { path: asset.path });
|
|
82
98
|
await cache.set(cacheKey, { content: null });
|
|
83
99
|
continue;
|
|
@@ -86,6 +102,8 @@ function svgOptimizer(options = {}) {
|
|
|
86
102
|
content: content.toString("base64")
|
|
87
103
|
});
|
|
88
104
|
tracer.event("svg-transform.run", { path: asset.path });
|
|
105
|
+
stats.optimized += 1;
|
|
106
|
+
stats.savedBytes += input.byteLength - content.byteLength;
|
|
89
107
|
outputs.push({
|
|
90
108
|
sourcePath: asset.path,
|
|
91
109
|
path: asset.path,
|
|
@@ -94,6 +112,69 @@ function svgOptimizer(options = {}) {
|
|
|
94
112
|
});
|
|
95
113
|
}
|
|
96
114
|
return outputs;
|
|
115
|
+
},
|
|
116
|
+
inspector: {
|
|
117
|
+
apiVersion: 1,
|
|
118
|
+
tabs: [
|
|
119
|
+
{
|
|
120
|
+
id: "svg-optimizer",
|
|
121
|
+
title: { en: "SVG optimization", ja: "SVG 最適化" },
|
|
122
|
+
description: {
|
|
123
|
+
en: "Optimization results, cache use, and skipped assets.",
|
|
124
|
+
ja: "最適化結果、キャッシュ利用、スキップしたアセットを表示します。"
|
|
125
|
+
},
|
|
126
|
+
order: 23,
|
|
127
|
+
collect: () => resolved.keepOriginal ? {
|
|
128
|
+
kind: "key-value",
|
|
129
|
+
items: [
|
|
130
|
+
{
|
|
131
|
+
key: { en: "Status", ja: "状態" },
|
|
132
|
+
value: "disabled (keepOriginal)"
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
} : {
|
|
136
|
+
kind: "key-value",
|
|
137
|
+
items: [
|
|
138
|
+
{ key: { en: "Inputs", ja: "入力" }, value: stats.inputs },
|
|
139
|
+
{
|
|
140
|
+
key: { en: "Optimized", ja: "最適化" },
|
|
141
|
+
value: stats.optimized
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
key: { en: "No reduction", ja: "削減なし" },
|
|
145
|
+
value: stats.noReduction
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
key: { en: "Cache hits", ja: "キャッシュヒット" },
|
|
149
|
+
value: stats.cacheHits
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
key: { en: "Cache misses", ja: "キャッシュミス" },
|
|
153
|
+
value: stats.cacheMisses
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
key: { en: "Saved", ja: "削減量" },
|
|
157
|
+
value: formatBytes(stats.savedBytes)
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
key: { en: "Skipped", ja: "スキップ" },
|
|
161
|
+
value: stats.skipped.length
|
|
162
|
+
},
|
|
163
|
+
...stats.skipped.length > 0 ? [
|
|
164
|
+
{
|
|
165
|
+
key: {
|
|
166
|
+
en: "Skipped assets",
|
|
167
|
+
ja: "スキップしたアセット"
|
|
168
|
+
},
|
|
169
|
+
value: stats.skipped.slice(0, 20).map(
|
|
170
|
+
(skipped) => `${skipped.path} (${skipped.reason})`
|
|
171
|
+
).join("; ")
|
|
172
|
+
}
|
|
173
|
+
] : []
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
]
|
|
97
178
|
}
|
|
98
179
|
});
|
|
99
180
|
}
|
|
@@ -166,6 +247,22 @@ function outputFor(sourcePath, content) {
|
|
|
166
247
|
mimeType: MIME_TYPE
|
|
167
248
|
};
|
|
168
249
|
}
|
|
250
|
+
function emptyStats() {
|
|
251
|
+
return {
|
|
252
|
+
inputs: 0,
|
|
253
|
+
optimized: 0,
|
|
254
|
+
noReduction: 0,
|
|
255
|
+
cacheHits: 0,
|
|
256
|
+
cacheMisses: 0,
|
|
257
|
+
savedBytes: 0,
|
|
258
|
+
skipped: []
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function formatBytes(bytes) {
|
|
262
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
263
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
264
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
265
|
+
}
|
|
169
266
|
export {
|
|
170
267
|
resolveSvgOptimizerOptions,
|
|
171
268
|
svgOptimizer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/plugin-svg-optimizer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.37",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@riebeckite/core": "0.0.
|
|
17
|
+
"@riebeckite/core": "0.0.37",
|
|
18
18
|
"svgo": "^4.1.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@riebeckite/plugin-image-optimizer": "0.0.
|
|
22
|
-
"@riebeckite/plugin-obsidian-markdown": "0.0.
|
|
21
|
+
"@riebeckite/plugin-image-optimizer": "0.0.37",
|
|
22
|
+
"@riebeckite/plugin-obsidian-markdown": "0.0.37",
|
|
23
23
|
"sharp": "^0.35.5",
|
|
24
24
|
"tsx": "^4.22.4"
|
|
25
25
|
},
|