@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.
Files changed (2) hide show
  1. package/dist/index.js +98 -1
  2. 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
- outputs.push(outputFor(asset.path, cached.content));
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.35",
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.35",
17
+ "@riebeckite/core": "0.0.37",
18
18
  "svgo": "^4.1.0"
19
19
  },
20
20
  "devDependencies": {
21
- "@riebeckite/plugin-image-optimizer": "0.0.35",
22
- "@riebeckite/plugin-obsidian-markdown": "0.0.35",
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
  },