vite-smart-img 1.1.7
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.d.ts +40 -0
- package/dist/index.js +384 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.cjs +310 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +37 -0
- package/dist/plugin.d.ts +37 -0
- package/dist/plugin.js +270 -0
- package/dist/plugin.js.map +1 -0
- package/dist/vite-asset-types.d.ts +39 -0
- package/package.json +52 -0
package/dist/plugin.cjs
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/plugin.ts
|
|
31
|
+
var plugin_exports = {};
|
|
32
|
+
__export(plugin_exports, {
|
|
33
|
+
imageThumbnails: () => imageThumbnails,
|
|
34
|
+
importedAssetsAlwaysFiles: () => importedAssetsAlwaysFiles,
|
|
35
|
+
smartImgLocalAssetImport: () => smartImgLocalAssetImport,
|
|
36
|
+
smartImgSvgAssetBuild: () => smartImgSvgAssetBuild
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(plugin_exports);
|
|
39
|
+
|
|
40
|
+
// src/plugin/imageThumbnails.ts
|
|
41
|
+
var import_sharp = __toESM(require("sharp"), 1);
|
|
42
|
+
var import_crypto = require("crypto");
|
|
43
|
+
var import_fs = require("fs");
|
|
44
|
+
var import_path2 = require("path");
|
|
45
|
+
|
|
46
|
+
// src/plugin/assetsPath.ts
|
|
47
|
+
var import_path = require("path");
|
|
48
|
+
var import_url = require("url");
|
|
49
|
+
function cleanLoadId(id) {
|
|
50
|
+
let raw = id.split("?")[0] ?? id;
|
|
51
|
+
if (raw.startsWith("\0")) return raw;
|
|
52
|
+
if (raw.startsWith("@fs/")) raw = raw.slice("@fs/".length);
|
|
53
|
+
else if (raw.startsWith("@fs\\")) raw = raw.slice("@fs\\".length);
|
|
54
|
+
if (raw.startsWith("file:")) {
|
|
55
|
+
try {
|
|
56
|
+
return (0, import_url.fileURLToPath)(raw);
|
|
57
|
+
} catch {
|
|
58
|
+
return raw;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return raw;
|
|
62
|
+
}
|
|
63
|
+
function isViteUrlImportRequest(id) {
|
|
64
|
+
const q = id.indexOf("?");
|
|
65
|
+
if (q === -1) return false;
|
|
66
|
+
const search = id.slice(q + 1);
|
|
67
|
+
if (!search) return false;
|
|
68
|
+
try {
|
|
69
|
+
return new URLSearchParams(search).has("url");
|
|
70
|
+
} catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function isPathInsideAssetsFolder(id) {
|
|
75
|
+
const fsPath = cleanLoadId(id);
|
|
76
|
+
if (fsPath.startsWith("\0")) return false;
|
|
77
|
+
const unified = (0, import_path.normalize)(fsPath).replace(/\\/g, "/");
|
|
78
|
+
return /(^|\/)assets\//.test(unified);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/plugin/imageThumbnails.ts
|
|
82
|
+
var SIZES = [
|
|
83
|
+
400,
|
|
84
|
+
600,
|
|
85
|
+
800,
|
|
86
|
+
1e3,
|
|
87
|
+
1200,
|
|
88
|
+
1400,
|
|
89
|
+
1600,
|
|
90
|
+
1800,
|
|
91
|
+
2e3,
|
|
92
|
+
2500,
|
|
93
|
+
3e3,
|
|
94
|
+
3500,
|
|
95
|
+
4e3,
|
|
96
|
+
5e3,
|
|
97
|
+
6e3,
|
|
98
|
+
7e3,
|
|
99
|
+
8e3
|
|
100
|
+
];
|
|
101
|
+
var SOURCE_EXTS = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png"]);
|
|
102
|
+
var JPEG_QUALITY = 85;
|
|
103
|
+
var WEBP_QUALITY = 82;
|
|
104
|
+
var ORIGINAL_QUALITY_CANDIDATES = [85, 80, 75, 70, 65];
|
|
105
|
+
function contentHash(buf) {
|
|
106
|
+
return (0, import_crypto.createHash)("sha256").update(buf).digest("hex").slice(0, 8);
|
|
107
|
+
}
|
|
108
|
+
function normalizeExt(ext) {
|
|
109
|
+
const e = ext.replace(/^\./, "").toLowerCase();
|
|
110
|
+
return e === "jpeg" ? "jpg" : e;
|
|
111
|
+
}
|
|
112
|
+
function smaller(a, b) {
|
|
113
|
+
return a.length <= b.length ? a : b;
|
|
114
|
+
}
|
|
115
|
+
function imageThumbnails() {
|
|
116
|
+
return {
|
|
117
|
+
name: "vite-smart-img-thumbnails",
|
|
118
|
+
apply: "build",
|
|
119
|
+
enforce: "pre",
|
|
120
|
+
async load(id) {
|
|
121
|
+
if (!isPathInsideAssetsFolder(id)) return null;
|
|
122
|
+
const pathOnly = cleanLoadId(id);
|
|
123
|
+
const ext = (0, import_path2.extname)(pathOnly).toLowerCase();
|
|
124
|
+
if (!SOURCE_EXTS.has(ext)) return null;
|
|
125
|
+
const rawContent = (0, import_fs.readFileSync)(pathOnly);
|
|
126
|
+
const cleanExt = normalizeExt(ext);
|
|
127
|
+
const isPng = cleanExt === "png";
|
|
128
|
+
let cleanedOriginal;
|
|
129
|
+
if (isPng) {
|
|
130
|
+
cleanedOriginal = await (0, import_sharp.default)(rawContent).rotate().png({ compressionLevel: 9 }).toBuffer();
|
|
131
|
+
} else {
|
|
132
|
+
cleanedOriginal = rawContent;
|
|
133
|
+
let found = false;
|
|
134
|
+
for (const q of ORIGINAL_QUALITY_CANDIDATES) {
|
|
135
|
+
const buf = await (0, import_sharp.default)(rawContent).rotate().jpeg({ quality: q, progressive: true }).toBuffer();
|
|
136
|
+
if (buf.length <= rawContent.length) {
|
|
137
|
+
cleanedOriginal = buf;
|
|
138
|
+
found = true;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (!found) {
|
|
143
|
+
cleanedOriginal = await (0, import_sharp.default)(rawContent).rotate().jpeg({ quality: 65, progressive: true }).toBuffer();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const hash = contentHash(cleanedOriginal);
|
|
147
|
+
const origFileName = `assets/img/${hash}.${cleanExt}`;
|
|
148
|
+
const origRef = this.emitFile({
|
|
149
|
+
type: "asset",
|
|
150
|
+
fileName: origFileName,
|
|
151
|
+
source: cleanedOriginal
|
|
152
|
+
});
|
|
153
|
+
const meta = await (0, import_sharp.default)(cleanedOriginal).metadata();
|
|
154
|
+
const originalW = meta.width && meta.width > 0 ? meta.width : 1;
|
|
155
|
+
const originalH = meta.height && meta.height > 0 ? meta.height : 1;
|
|
156
|
+
const applicableSizes = SIZES.filter((s) => s <= originalW);
|
|
157
|
+
const ctx = this;
|
|
158
|
+
await Promise.all(
|
|
159
|
+
applicableSizes.flatMap((size) => {
|
|
160
|
+
const base = (0, import_sharp.default)(cleanedOriginal).rotate().resize({
|
|
161
|
+
width: size,
|
|
162
|
+
withoutEnlargement: true,
|
|
163
|
+
fit: "inside"
|
|
164
|
+
});
|
|
165
|
+
return [
|
|
166
|
+
base.clone().webp({ quality: WEBP_QUALITY }).toBuffer().then((buf) => {
|
|
167
|
+
ctx.emitFile({
|
|
168
|
+
type: "asset",
|
|
169
|
+
fileName: `assets/img/${hash}-${size}.webp`,
|
|
170
|
+
source: smaller(buf, cleanedOriginal)
|
|
171
|
+
});
|
|
172
|
+
}),
|
|
173
|
+
base.clone()[isPng ? "png" : "jpeg"]({
|
|
174
|
+
...isPng ? { compressionLevel: 9 } : { quality: JPEG_QUALITY, progressive: true }
|
|
175
|
+
}).toBuffer().then((buf) => {
|
|
176
|
+
ctx.emitFile({
|
|
177
|
+
type: "asset",
|
|
178
|
+
fileName: `assets/img/${hash}-${size}.${cleanExt}`,
|
|
179
|
+
source: smaller(buf, cleanedOriginal)
|
|
180
|
+
});
|
|
181
|
+
})
|
|
182
|
+
];
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
return `const src = import.meta.ROLLUP_FILE_URL_${origRef}
|
|
186
|
+
export default { src, originalW: ${originalW}, originalH: ${originalH} }
|
|
187
|
+
`;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// src/plugin/importedAssetsAlwaysFiles.ts
|
|
193
|
+
function importedAssetsAlwaysFiles() {
|
|
194
|
+
return {
|
|
195
|
+
name: "vite-smart-img-imported-assets-always-files",
|
|
196
|
+
enforce: "pre",
|
|
197
|
+
config() {
|
|
198
|
+
return {
|
|
199
|
+
build: {
|
|
200
|
+
assetsInlineLimit: 0
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/plugin/smartImgLocalAssetImport.ts
|
|
208
|
+
var import_fs2 = require("fs");
|
|
209
|
+
var import_path3 = require("path");
|
|
210
|
+
var import_sharp2 = __toESM(require("sharp"), 1);
|
|
211
|
+
|
|
212
|
+
// src/plugin/parseSvgDimensions.ts
|
|
213
|
+
function parseSvgDimensions(svgSource) {
|
|
214
|
+
const widthAttr = svgSource.match(/\bwidth\s*=\s*["']([^"']+)["']/i);
|
|
215
|
+
const heightAttr = svgSource.match(/\bheight\s*=\s*["']([^"']+)["']/i);
|
|
216
|
+
if (widthAttr && heightAttr) {
|
|
217
|
+
const w = parseFloat(String(widthAttr[1]).replace(/px|pt|em|rem|%$/i, ""));
|
|
218
|
+
const h = parseFloat(String(heightAttr[1]).replace(/px|pt|em|rem|%$/i, ""));
|
|
219
|
+
if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {
|
|
220
|
+
return { originalW: Math.round(w), originalH: Math.round(h) };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const vb = svgSource.match(/viewBox\s*=\s*["']\s*([^"']+)\s*["']/i);
|
|
224
|
+
if (vb) {
|
|
225
|
+
const parts = vb[1].trim().split(/[\s,]+/).map((s) => Number(s));
|
|
226
|
+
if (parts.length >= 4) {
|
|
227
|
+
const w = parts[2];
|
|
228
|
+
const h = parts[3];
|
|
229
|
+
if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {
|
|
230
|
+
return { originalW: Math.round(w), originalH: Math.round(h) };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/plugin/smartImgLocalAssetImport.ts
|
|
238
|
+
var RASTER_EXT = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png"]);
|
|
239
|
+
function smartImgLocalAssetImport() {
|
|
240
|
+
return {
|
|
241
|
+
name: "vite-smart-img-local-asset-import",
|
|
242
|
+
enforce: "pre",
|
|
243
|
+
apply: "serve",
|
|
244
|
+
async load(id) {
|
|
245
|
+
if (isViteUrlImportRequest(id)) return null;
|
|
246
|
+
if (!isPathInsideAssetsFolder(id)) return null;
|
|
247
|
+
const pathOnly = cleanLoadId(id);
|
|
248
|
+
const ext = (0, import_path3.extname)(pathOnly).toLowerCase();
|
|
249
|
+
if (RASTER_EXT.has(ext)) {
|
|
250
|
+
const buf = (0, import_fs2.readFileSync)(pathOnly);
|
|
251
|
+
const meta = await (0, import_sharp2.default)(buf).rotate().metadata();
|
|
252
|
+
const originalW = meta.width && meta.width > 0 ? meta.width : 1;
|
|
253
|
+
const originalH = meta.height && meta.height > 0 ? meta.height : 1;
|
|
254
|
+
const urlParam = JSON.stringify(`${pathOnly}?url`);
|
|
255
|
+
return `import _smiResolvedUrl from ${urlParam}
|
|
256
|
+
export default { src: _smiResolvedUrl, originalW: ${originalW}, originalH: ${originalH} }
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
259
|
+
if (ext === ".svg") {
|
|
260
|
+
const source = (0, import_fs2.readFileSync)(pathOnly, "utf8");
|
|
261
|
+
const d = parseSvgDimensions(source) ?? { originalW: 1, originalH: 1 };
|
|
262
|
+
const urlParam = JSON.stringify(`${pathOnly}?url`);
|
|
263
|
+
return `import _smiResolvedUrl from ${urlParam}
|
|
264
|
+
export default { src: _smiResolvedUrl, originalW: ${d.originalW}, originalH: ${d.originalH} }
|
|
265
|
+
`;
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/plugin/smartImgSvgAssetBuild.ts
|
|
273
|
+
var import_crypto2 = require("crypto");
|
|
274
|
+
var import_fs3 = require("fs");
|
|
275
|
+
var import_path4 = require("path");
|
|
276
|
+
function contentHash2(text) {
|
|
277
|
+
return (0, import_crypto2.createHash)("sha256").update(text, "utf8").digest("hex").slice(0, 8);
|
|
278
|
+
}
|
|
279
|
+
function smartImgSvgAssetBuild() {
|
|
280
|
+
return {
|
|
281
|
+
name: "vite-smart-img-svg-asset-build",
|
|
282
|
+
enforce: "pre",
|
|
283
|
+
apply: "build",
|
|
284
|
+
load(id) {
|
|
285
|
+
if (!isPathInsideAssetsFolder(id)) return null;
|
|
286
|
+
const pathOnly = cleanLoadId(id);
|
|
287
|
+
if ((0, import_path4.extname)(pathOnly).toLowerCase() !== ".svg") return null;
|
|
288
|
+
const source = (0, import_fs3.readFileSync)(pathOnly, "utf8");
|
|
289
|
+
const dims = parseSvgDimensions(source) ?? { originalW: 1, originalH: 1 };
|
|
290
|
+
const hash = contentHash2(source);
|
|
291
|
+
const buf = Buffer.from(source, "utf8");
|
|
292
|
+
const origRef = this.emitFile({
|
|
293
|
+
type: "asset",
|
|
294
|
+
fileName: `assets/img/${hash}.svg`,
|
|
295
|
+
source: buf
|
|
296
|
+
});
|
|
297
|
+
return `const src = import.meta.ROLLUP_FILE_URL_${origRef}
|
|
298
|
+
export default { src, originalW: ${dims.originalW}, originalH: ${dims.originalH} }
|
|
299
|
+
`;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
304
|
+
0 && (module.exports = {
|
|
305
|
+
imageThumbnails,
|
|
306
|
+
importedAssetsAlwaysFiles,
|
|
307
|
+
smartImgLocalAssetImport,
|
|
308
|
+
smartImgSvgAssetBuild
|
|
309
|
+
});
|
|
310
|
+
//# sourceMappingURL=plugin.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/plugin/imageThumbnails.ts","../src/plugin/assetsPath.ts","../src/plugin/importedAssetsAlwaysFiles.ts","../src/plugin/smartImgLocalAssetImport.ts","../src/plugin/parseSvgDimensions.ts","../src/plugin/smartImgSvgAssetBuild.ts"],"sourcesContent":["export { imageThumbnails } from './plugin/imageThumbnails'\nexport { importedAssetsAlwaysFiles } from './plugin/importedAssetsAlwaysFiles'\nexport { smartImgLocalAssetImport } from './plugin/smartImgLocalAssetImport'\nexport { smartImgSvgAssetBuild } from './plugin/smartImgSvgAssetBuild'\n","/**\n * Vite-плагин продакшн-обработки изображений из папок assets/.\n *\n * Работает только в режиме `build` (apply: 'build').\n * В dev-режиме IS_DEV в smartImgManager грузит оригинал напрямую.\n *\n * Что делает при билде:\n * 1. Перехватывает импорты картинок из любой папки assets/ в проекте.\n * 2. Хеширует содержимое файла (SHA-256, 8 символов) → имя без коллизий.\n * 3. Прогоняет оригинал через sharp — снимает EXIF/метаданные, корректирует\n * ориентацию по EXIF (.rotate()) перед его удалением.\n * 4. Нарезает миниатюры для размеров из SIZES, не превышающих ширину оригинала.\n * 5. Для каждого размера создаёт .jpg/.png и .webp.\n * Если миниатюра тяжелее очищенного оригинала — записывает оригинал вместо неё.\n * 6. Эмитирует все файлы в dist/assets/ с точными именами (без Rollup-хеша).\n * 7. Модуль по умолчанию: `{ src, originalW, originalH }` — `src` как раньше (URL оригинала).\n */\n\nimport sharp from 'sharp'\nimport { createHash } from 'crypto'\nimport { readFileSync } from 'fs'\nimport { extname } from 'path'\nimport type { Plugin } from 'vite'\n\nimport { cleanLoadId, isPathInsideAssetsFolder } from './assetsPath'\n\n// ─── Конфигурация ─────────────────────────────────────────────────────────────\n\nconst SIZES = [\n 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000,\n 2500, 3000, 3500, 4000, 5000, 6000, 7000, 8000,\n] as const\n\nconst SOURCE_EXTS = new Set(['.jpg', '.jpeg', '.png'])\n\n/** Качество JPEG при нарезке миниатюр */\nconst JPEG_QUALITY = 85\n\n/** Качество WebP при нарезке миниатюр */\nconst WEBP_QUALITY = 82\n\n/**\n * Набор качеств JPEG для перебора при очистке оригинала.\n * Берём первое, при котором очищенный файл ≤ сырого исходника.\n */\nconst ORIGINAL_QUALITY_CANDIDATES = [85, 80, 75, 70, 65] as const\n\n// ─── Утилиты ──────────────────────────────────────────────────────────────────\n\nfunction contentHash(buf: Buffer): string {\n return createHash('sha256').update(buf).digest('hex').slice(0, 8)\n}\n\nfunction normalizeExt(ext: string): string {\n const e = ext.replace(/^\\./, '').toLowerCase()\n return e === 'jpeg' ? 'jpg' : e\n}\n\n/** Меньший из двух буферов */\nfunction smaller(a: Buffer, b: Buffer): Buffer {\n return a.length <= b.length ? a : b\n}\n\n// ─── Плагин ───────────────────────────────────────────────────────────────────\n\nexport function imageThumbnails(): Plugin {\n return {\n name: 'vite-smart-img-thumbnails',\n apply: 'build',\n enforce: 'pre',\n\n async load(id) {\n if (!isPathInsideAssetsFolder(id)) return null\n const pathOnly = cleanLoadId(id)\n const ext = extname(pathOnly).toLowerCase()\n if (!SOURCE_EXTS.has(ext)) return null\n\n const rawContent = readFileSync(pathOnly)\n const cleanExt = normalizeExt(ext)\n const isPng = cleanExt === 'png'\n\n // ── Шаг 1: очистить оригинал от метаданных ──────────────────────────────\n let cleanedOriginal: Buffer\n\n if (isPng) {\n cleanedOriginal = await sharp(rawContent)\n .rotate()\n .png({ compressionLevel: 9 })\n .toBuffer()\n } else {\n cleanedOriginal = rawContent\n let found = false\n for (const q of ORIGINAL_QUALITY_CANDIDATES) {\n const buf = await sharp(rawContent)\n .rotate()\n .jpeg({ quality: q, progressive: true })\n .toBuffer()\n if (buf.length <= rawContent.length) {\n cleanedOriginal = buf\n found = true\n break\n }\n }\n if (!found) {\n cleanedOriginal = await sharp(rawContent)\n .rotate()\n .jpeg({ quality: 65, progressive: true })\n .toBuffer()\n }\n }\n\n const hash = contentHash(cleanedOriginal)\n const origFileName = `assets/img/${hash}.${cleanExt}`\n\n const origRef = this.emitFile({\n type: 'asset',\n fileName: origFileName,\n source: cleanedOriginal,\n })\n\n // ── Шаг 2: нарезать миниатюры ──────────────────────────────────────────\n const meta = await sharp(cleanedOriginal).metadata()\n const originalW = meta.width && meta.width > 0 ? meta.width : 1\n const originalH = meta.height && meta.height > 0 ? meta.height : 1\n const applicableSizes = SIZES.filter((s) => s <= originalW)\n\n const ctx = this\n await Promise.all(\n applicableSizes.flatMap((size) => {\n const base = sharp(cleanedOriginal).rotate().resize({\n width: size,\n withoutEnlargement: true,\n fit: 'inside',\n })\n\n return [\n base\n .clone()\n .webp({ quality: WEBP_QUALITY })\n .toBuffer()\n .then((buf) => {\n ctx.emitFile({\n type: 'asset',\n fileName: `assets/img/${hash}-${size}.webp`,\n source: smaller(buf, cleanedOriginal),\n })\n }),\n\n base\n .clone()\n [isPng ? 'png' : 'jpeg']({\n ...(isPng\n ? { compressionLevel: 9 }\n : { quality: JPEG_QUALITY, progressive: true }),\n })\n .toBuffer()\n .then((buf) => {\n ctx.emitFile({\n type: 'asset',\n fileName: `assets/img/${hash}-${size}.${cleanExt}`,\n source: smaller(buf, cleanedOriginal),\n })\n }),\n ]\n }),\n )\n\n return (\n `const src = import.meta.ROLLUP_FILE_URL_${origRef}\\n` +\n `export default { src, originalW: ${originalW}, originalH: ${originalH} }\\n`\n )\n },\n }\n}\n","/**\r\n * Vite `load(id)` может отдавать POSIX-путь, `file://` URL или префикс `@fs/`.\r\n * Сегмент папки `assets` проверяем в унифицированном виде (`/assets/`), чтобы\r\n * работало на Windows и не зависело от `path.sep`.\r\n */\r\nimport { normalize } from 'path'\r\nimport { fileURLToPath } from 'url'\r\n\r\nexport function cleanLoadId(id: string): string {\r\n let raw = id.split('?')[0] ?? id\r\n if (raw.startsWith('\\0')) return raw\r\n\r\n if (raw.startsWith('@fs/')) raw = raw.slice('@fs/'.length)\r\n else if (raw.startsWith('@fs\\\\')) raw = raw.slice('@fs\\\\'.length)\r\n\r\n if (raw.startsWith('file:')) {\r\n try {\r\n return fileURLToPath(raw)\r\n } catch {\r\n return raw\r\n }\r\n }\r\n return raw\r\n}\r\n\r\n/**\r\n * Явный запрос URL ассета (`?url`, `?import&url`, …) — его обрабатывает встроенный пайплайн Vite.\r\n * Наш `load` для обёртки не должен перехватывать повторно (цикл / TDZ по имени импорта).\r\n */\r\nexport function isViteUrlImportRequest(id: string): boolean {\r\n const q = id.indexOf('?')\r\n if (q === -1) return false\r\n const search = id.slice(q + 1)\r\n if (!search) return false\r\n try {\r\n return new URLSearchParams(search).has('url')\r\n } catch {\r\n return false\r\n }\r\n}\r\n\r\n/** Файл лежит в каталоге `.../assets/...` (сегмент `assets` в пути). */\r\nexport function isPathInsideAssetsFolder(id: string): boolean {\r\n const fsPath = cleanLoadId(id)\r\n if (fsPath.startsWith('\\0')) return false\r\n const unified = normalize(fsPath).replace(/\\\\/g, '/')\r\n return /(^|\\/)assets\\//.test(unified)\r\n}\r\n","import type { Plugin } from 'vite'\r\n\r\n/**\r\n * При `vite build` не встраивает импортируемые статические ассеты внутрь JS (base64 / data URL).\r\n * Вместо этого они остаются отдельными файлами в `dist`, в коде — только строковые URL.\r\n *\r\n * Задаёт `build.assetsInlineLimit: 0` (в Vite один лимит на весь пайплайн статических импортов:\r\n * отключается inlining не только у изображений, но и у других мелких ассетов, которые Vite\r\n * мог бы положить в бандл).\r\n */\r\nexport function importedAssetsAlwaysFiles(): Plugin {\r\n return {\r\n name: 'vite-smart-img-imported-assets-always-files',\r\n enforce: 'pre',\r\n config() {\r\n return {\r\n build: {\r\n assetsInlineLimit: 0,\r\n },\r\n }\r\n },\r\n }\r\n}\r\n","/**\r\n * Только dev (`apply: 'serve'`): импорт `*.jpg|jpeg|png|svg` из `.../assets/...`\r\n * → `export default { src, originalW, originalH }` (как после production-плагинов).\r\n * Для растра — sharp.rotate().metadata(); для SVG — parseSvgDimensions.\r\n */\r\nimport { readFileSync } from 'fs'\r\nimport { extname } from 'path'\r\nimport type { Plugin } from 'vite'\r\nimport sharp from 'sharp'\r\nimport { cleanLoadId, isPathInsideAssetsFolder, isViteUrlImportRequest } from './assetsPath'\r\nimport { parseSvgDimensions } from './parseSvgDimensions'\r\n\r\nconst RASTER_EXT = new Set(['.jpg', '.jpeg', '.png'])\r\n\r\nexport function smartImgLocalAssetImport(): Plugin {\r\n return {\r\n name: 'vite-smart-img-local-asset-import',\r\n enforce: 'pre',\r\n apply: 'serve',\r\n\r\n async load(id) {\r\n // Обёртка импортирует `path?url`. Vite часто отдаёт `?import&url`, а не голый `?url`.\r\n if (isViteUrlImportRequest(id)) return null\r\n\r\n if (!isPathInsideAssetsFolder(id)) return null\r\n const pathOnly = cleanLoadId(id)\r\n const ext = extname(pathOnly).toLowerCase()\r\n\r\n if (RASTER_EXT.has(ext)) {\r\n const buf = readFileSync(pathOnly)\r\n const meta = await sharp(buf).rotate().metadata()\r\n const originalW = meta.width && meta.width > 0 ? meta.width : 1\r\n const originalH = meta.height && meta.height > 0 ? meta.height : 1\r\n const urlParam = JSON.stringify(`${pathOnly}?url`)\r\n return `import _smiResolvedUrl from ${urlParam}\\nexport default { src: _smiResolvedUrl, originalW: ${originalW}, originalH: ${originalH} }\\n`\r\n }\r\n\r\n if (ext === '.svg') {\r\n const source = readFileSync(pathOnly, 'utf8')\r\n const d = parseSvgDimensions(source) ?? { originalW: 1, originalH: 1 }\r\n const urlParam = JSON.stringify(`${pathOnly}?url`)\r\n return `import _smiResolvedUrl from ${urlParam}\\nexport default { src: _smiResolvedUrl, originalW: ${d.originalW}, originalH: ${d.originalH} }\\n`\r\n }\r\n\r\n return null\r\n },\r\n }\r\n}\r\n","/**\r\n * Базовый разбор width/height/viewBox у корневого <svg> (достаточно для типичных экспортов).\r\n * При неудаче возвращает null — вызывающий может подставить fallback.\r\n */\r\nexport function parseSvgDimensions(svgSource: string): { originalW: number; originalH: number } | null {\r\n const widthAttr = svgSource.match(/\\bwidth\\s*=\\s*[\"']([^\"']+)[\"']/i)\r\n const heightAttr = svgSource.match(/\\bheight\\s*=\\s*[\"']([^\"']+)[\"']/i)\r\n if (widthAttr && heightAttr) {\r\n const w = parseFloat(String(widthAttr[1]).replace(/px|pt|em|rem|%$/i, ''))\r\n const h = parseFloat(String(heightAttr[1]).replace(/px|pt|em|rem|%$/i, ''))\r\n if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {\r\n return { originalW: Math.round(w), originalH: Math.round(h) }\r\n }\r\n }\r\n const vb = svgSource.match(/viewBox\\s*=\\s*[\"']\\s*([^\"']+)\\s*[\"']/i)\r\n if (vb) {\r\n const parts = vb[1].trim().split(/[\\s,]+/).map((s) => Number(s))\r\n if (parts.length >= 4) {\r\n const w = parts[2]\r\n const h = parts[3]\r\n if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {\r\n return { originalW: Math.round(w), originalH: Math.round(h) }\r\n }\r\n }\r\n }\r\n return null\r\n}\r\n","/**\r\n * Только build: SVG из `.../assets/...` → тот же контракт `{ src, originalW, originalH }`.\r\n * Растр по-прежнему в `imageThumbnails`.\r\n */\r\nimport { createHash } from 'crypto'\r\nimport { readFileSync } from 'fs'\r\nimport { extname } from 'path'\r\nimport type { Plugin } from 'vite'\r\nimport { cleanLoadId, isPathInsideAssetsFolder } from './assetsPath'\r\nimport { parseSvgDimensions } from './parseSvgDimensions'\r\n\r\nfunction contentHash(text: string): string {\r\n return createHash('sha256').update(text, 'utf8').digest('hex').slice(0, 8)\r\n}\r\n\r\nexport function smartImgSvgAssetBuild(): Plugin {\r\n return {\r\n name: 'vite-smart-img-svg-asset-build',\r\n enforce: 'pre',\r\n apply: 'build',\r\n\r\n load(id) {\r\n if (!isPathInsideAssetsFolder(id)) return null\r\n const pathOnly = cleanLoadId(id)\r\n if (extname(pathOnly).toLowerCase() !== '.svg') return null\r\n\r\n const source = readFileSync(pathOnly, 'utf8')\r\n const dims = parseSvgDimensions(source) ?? { originalW: 1, originalH: 1 }\r\n const hash = contentHash(source)\r\n const buf = Buffer.from(source, 'utf8')\r\n const origRef = this.emitFile({\r\n type: 'asset',\r\n fileName: `assets/img/${hash}.svg`,\r\n source: buf,\r\n })\r\n\r\n return (\r\n `const src = import.meta.ROLLUP_FILE_URL_${origRef}\\n` +\r\n `export default { src, originalW: ${dims.originalW}, originalH: ${dims.originalH} }\\n`\r\n )\r\n },\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACkBA,mBAAkB;AAClB,oBAA2B;AAC3B,gBAA6B;AAC7B,IAAAA,eAAwB;;;AChBxB,kBAA0B;AAC1B,iBAA8B;AAEvB,SAAS,YAAY,IAAoB;AAC9C,MAAI,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AAC9B,MAAI,IAAI,WAAW,IAAI,EAAG,QAAO;AAEjC,MAAI,IAAI,WAAW,MAAM,EAAG,OAAM,IAAI,MAAM,OAAO,MAAM;AAAA,WAChD,IAAI,WAAW,OAAO,EAAG,OAAM,IAAI,MAAM,QAAQ,MAAM;AAEhE,MAAI,IAAI,WAAW,OAAO,GAAG;AAC3B,QAAI;AACF,iBAAO,0BAAc,GAAG;AAAA,IAC1B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,uBAAuB,IAAqB;AAC1D,QAAM,IAAI,GAAG,QAAQ,GAAG;AACxB,MAAI,MAAM,GAAI,QAAO;AACrB,QAAM,SAAS,GAAG,MAAM,IAAI,CAAC;AAC7B,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI;AACF,WAAO,IAAI,gBAAgB,MAAM,EAAE,IAAI,KAAK;AAAA,EAC9C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,yBAAyB,IAAqB;AAC5D,QAAM,SAAS,YAAY,EAAE;AAC7B,MAAI,OAAO,WAAW,IAAI,EAAG,QAAO;AACpC,QAAM,cAAU,uBAAU,MAAM,EAAE,QAAQ,OAAO,GAAG;AACpD,SAAO,iBAAiB,KAAK,OAAO;AACtC;;;ADnBA,IAAM,QAAQ;AAAA,EACZ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC7C;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAC5C;AAEA,IAAM,cAAc,oBAAI,IAAI,CAAC,QAAQ,SAAS,MAAM,CAAC;AAGrD,IAAM,eAAe;AAGrB,IAAM,eAAe;AAMrB,IAAM,8BAA8B,CAAC,IAAI,IAAI,IAAI,IAAI,EAAE;AAIvD,SAAS,YAAY,KAAqB;AACxC,aAAO,0BAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,CAAC;AAClE;AAEA,SAAS,aAAa,KAAqB;AACzC,QAAM,IAAI,IAAI,QAAQ,OAAO,EAAE,EAAE,YAAY;AAC7C,SAAO,MAAM,SAAS,QAAQ;AAChC;AAGA,SAAS,QAAQ,GAAW,GAAmB;AAC7C,SAAO,EAAE,UAAU,EAAE,SAAS,IAAI;AACpC;AAIO,SAAS,kBAA0B;AACxC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,IAET,MAAM,KAAK,IAAI;AACb,UAAI,CAAC,yBAAyB,EAAE,EAAG,QAAO;AAC1C,YAAM,WAAW,YAAY,EAAE;AAC/B,YAAM,UAAM,sBAAQ,QAAQ,EAAE,YAAY;AAC1C,UAAI,CAAC,YAAY,IAAI,GAAG,EAAG,QAAO;AAElC,YAAM,iBAAa,wBAAa,QAAQ;AACxC,YAAM,WAAW,aAAa,GAAG;AACjC,YAAM,QAAQ,aAAa;AAG3B,UAAI;AAEJ,UAAI,OAAO;AACT,0BAAkB,UAAM,aAAAC,SAAM,UAAU,EACrC,OAAO,EACP,IAAI,EAAE,kBAAkB,EAAE,CAAC,EAC3B,SAAS;AAAA,MACd,OAAO;AACL,0BAAkB;AAClB,YAAI,QAAQ;AACZ,mBAAW,KAAK,6BAA6B;AAC3C,gBAAM,MAAM,UAAM,aAAAA,SAAM,UAAU,EAC/B,OAAO,EACP,KAAK,EAAE,SAAS,GAAG,aAAa,KAAK,CAAC,EACtC,SAAS;AACZ,cAAI,IAAI,UAAU,WAAW,QAAQ;AACnC,8BAAkB;AAClB,oBAAQ;AACR;AAAA,UACF;AAAA,QACF;AACA,YAAI,CAAC,OAAO;AACV,4BAAkB,UAAM,aAAAA,SAAM,UAAU,EACrC,OAAO,EACP,KAAK,EAAE,SAAS,IAAI,aAAa,KAAK,CAAC,EACvC,SAAS;AAAA,QACd;AAAA,MACF;AAEA,YAAM,OAAO,YAAY,eAAe;AACxC,YAAM,eAAe,cAAc,IAAI,IAAI,QAAQ;AAEnD,YAAM,UAAU,KAAK,SAAS;AAAA,QAC5B,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ;AAAA,MACV,CAAC;AAGD,YAAM,OAAO,UAAM,aAAAA,SAAM,eAAe,EAAE,SAAS;AACnD,YAAM,YAAY,KAAK,SAAS,KAAK,QAAQ,IAAI,KAAK,QAAQ;AAC9D,YAAM,YAAY,KAAK,UAAU,KAAK,SAAS,IAAI,KAAK,SAAS;AACjE,YAAM,kBAAkB,MAAM,OAAO,CAAC,MAAM,KAAK,SAAS;AAE1D,YAAM,MAAM;AACZ,YAAM,QAAQ;AAAA,QACZ,gBAAgB,QAAQ,CAAC,SAAS;AAChC,gBAAM,WAAO,aAAAA,SAAM,eAAe,EAAE,OAAO,EAAE,OAAO;AAAA,YAClD,OAAO;AAAA,YACP,oBAAoB;AAAA,YACpB,KAAK;AAAA,UACP,CAAC;AAED,iBAAO;AAAA,YACL,KACG,MAAM,EACN,KAAK,EAAE,SAAS,aAAa,CAAC,EAC9B,SAAS,EACT,KAAK,CAAC,QAAQ;AACb,kBAAI,SAAS;AAAA,gBACX,MAAM;AAAA,gBACN,UAAU,cAAc,IAAI,IAAI,IAAI;AAAA,gBACpC,QAAQ,QAAQ,KAAK,eAAe;AAAA,cACtC,CAAC;AAAA,YACH,CAAC;AAAA,YAEH,KACG,MAAM,EACN,QAAQ,QAAQ,MAAM,EAAE;AAAA,cACvB,GAAI,QACA,EAAE,kBAAkB,EAAE,IACtB,EAAE,SAAS,cAAc,aAAa,KAAK;AAAA,YACjD,CAAC,EACA,SAAS,EACT,KAAK,CAAC,QAAQ;AACb,kBAAI,SAAS;AAAA,gBACX,MAAM;AAAA,gBACN,UAAU,cAAc,IAAI,IAAI,IAAI,IAAI,QAAQ;AAAA,gBAChD,QAAQ,QAAQ,KAAK,eAAe;AAAA,cACtC,CAAC;AAAA,YACH,CAAC;AAAA,UACL;AAAA,QACF,CAAC;AAAA,MACH;AAEA,aACE,2CAA2C,OAAO;AAAA,mCACd,SAAS,gBAAgB,SAAS;AAAA;AAAA,IAE1E;AAAA,EACF;AACF;;;AEnKO,SAAS,4BAAoC;AAClD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AACP,aAAO;AAAA,QACL,OAAO;AAAA,UACL,mBAAmB;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACjBA,IAAAC,aAA6B;AAC7B,IAAAC,eAAwB;AAExB,IAAAC,gBAAkB;;;ACJX,SAAS,mBAAmB,WAAoE;AACrG,QAAM,YAAY,UAAU,MAAM,iCAAiC;AACnE,QAAM,aAAa,UAAU,MAAM,kCAAkC;AACrE,MAAI,aAAa,YAAY;AAC3B,UAAM,IAAI,WAAW,OAAO,UAAU,CAAC,CAAC,EAAE,QAAQ,oBAAoB,EAAE,CAAC;AACzE,UAAM,IAAI,WAAW,OAAO,WAAW,CAAC,CAAC,EAAE,QAAQ,oBAAoB,EAAE,CAAC;AAC1E,QAAI,OAAO,SAAS,CAAC,KAAK,OAAO,SAAS,CAAC,KAAK,IAAI,KAAK,IAAI,GAAG;AAC9D,aAAO,EAAE,WAAW,KAAK,MAAM,CAAC,GAAG,WAAW,KAAK,MAAM,CAAC,EAAE;AAAA,IAC9D;AAAA,EACF;AACA,QAAM,KAAK,UAAU,MAAM,uCAAuC;AAClE,MAAI,IAAI;AACN,UAAM,QAAQ,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,QAAQ,EAAE,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC;AAC/D,QAAI,MAAM,UAAU,GAAG;AACrB,YAAM,IAAI,MAAM,CAAC;AACjB,YAAM,IAAI,MAAM,CAAC;AACjB,UAAI,OAAO,SAAS,CAAC,KAAK,OAAO,SAAS,CAAC,KAAK,IAAI,KAAK,IAAI,GAAG;AAC9D,eAAO,EAAE,WAAW,KAAK,MAAM,CAAC,GAAG,WAAW,KAAK,MAAM,CAAC,EAAE;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;ADdA,IAAM,aAAa,oBAAI,IAAI,CAAC,QAAQ,SAAS,MAAM,CAAC;AAE7C,SAAS,2BAAmC;AACjD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,IAEP,MAAM,KAAK,IAAI;AAEb,UAAI,uBAAuB,EAAE,EAAG,QAAO;AAEvC,UAAI,CAAC,yBAAyB,EAAE,EAAG,QAAO;AAC1C,YAAM,WAAW,YAAY,EAAE;AAC/B,YAAM,UAAM,sBAAQ,QAAQ,EAAE,YAAY;AAE1C,UAAI,WAAW,IAAI,GAAG,GAAG;AACvB,cAAM,UAAM,yBAAa,QAAQ;AACjC,cAAM,OAAO,UAAM,cAAAC,SAAM,GAAG,EAAE,OAAO,EAAE,SAAS;AAChD,cAAM,YAAY,KAAK,SAAS,KAAK,QAAQ,IAAI,KAAK,QAAQ;AAC9D,cAAM,YAAY,KAAK,UAAU,KAAK,SAAS,IAAI,KAAK,SAAS;AACjE,cAAM,WAAW,KAAK,UAAU,GAAG,QAAQ,MAAM;AACjD,eAAO,+BAA+B,QAAQ;AAAA,oDAAuD,SAAS,gBAAgB,SAAS;AAAA;AAAA,MACzI;AAEA,UAAI,QAAQ,QAAQ;AAClB,cAAM,aAAS,yBAAa,UAAU,MAAM;AAC5C,cAAM,IAAI,mBAAmB,MAAM,KAAK,EAAE,WAAW,GAAG,WAAW,EAAE;AACrE,cAAM,WAAW,KAAK,UAAU,GAAG,QAAQ,MAAM;AACjD,eAAO,+BAA+B,QAAQ;AAAA,oDAAuD,EAAE,SAAS,gBAAgB,EAAE,SAAS;AAAA;AAAA,MAC7I;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AE3CA,IAAAC,iBAA2B;AAC3B,IAAAC,aAA6B;AAC7B,IAAAC,eAAwB;AAKxB,SAASC,aAAY,MAAsB;AACzC,aAAO,2BAAW,QAAQ,EAAE,OAAO,MAAM,MAAM,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,CAAC;AAC3E;AAEO,SAAS,wBAAgC;AAC9C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,IAEP,KAAK,IAAI;AACP,UAAI,CAAC,yBAAyB,EAAE,EAAG,QAAO;AAC1C,YAAM,WAAW,YAAY,EAAE;AAC/B,cAAI,sBAAQ,QAAQ,EAAE,YAAY,MAAM,OAAQ,QAAO;AAEvD,YAAM,aAAS,yBAAa,UAAU,MAAM;AAC5C,YAAM,OAAO,mBAAmB,MAAM,KAAK,EAAE,WAAW,GAAG,WAAW,EAAE;AACxE,YAAM,OAAOA,aAAY,MAAM;AAC/B,YAAM,MAAM,OAAO,KAAK,QAAQ,MAAM;AACtC,YAAM,UAAU,KAAK,SAAS;AAAA,QAC5B,MAAM;AAAA,QACN,UAAU,cAAc,IAAI;AAAA,QAC5B,QAAQ;AAAA,MACV,CAAC;AAED,aACE,2CAA2C,OAAO;AAAA,mCACd,KAAK,SAAS,gBAAgB,KAAK,SAAS;AAAA;AAAA,IAEpF;AAAA,EACF;AACF;","names":["import_path","sharp","import_fs","import_path","import_sharp","sharp","import_crypto","import_fs","import_path","contentHash"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Vite-плагин продакшн-обработки изображений из папок assets/.
|
|
5
|
+
*
|
|
6
|
+
* Работает только в режиме `build` (apply: 'build').
|
|
7
|
+
* В dev-режиме IS_DEV в smartImgManager грузит оригинал напрямую.
|
|
8
|
+
*
|
|
9
|
+
* Что делает при билде:
|
|
10
|
+
* 1. Перехватывает импорты картинок из любой папки assets/ в проекте.
|
|
11
|
+
* 2. Хеширует содержимое файла (SHA-256, 8 символов) → имя без коллизий.
|
|
12
|
+
* 3. Прогоняет оригинал через sharp — снимает EXIF/метаданные, корректирует
|
|
13
|
+
* ориентацию по EXIF (.rotate()) перед его удалением.
|
|
14
|
+
* 4. Нарезает миниатюры для размеров из SIZES, не превышающих ширину оригинала.
|
|
15
|
+
* 5. Для каждого размера создаёт .jpg/.png и .webp.
|
|
16
|
+
* Если миниатюра тяжелее очищенного оригинала — записывает оригинал вместо неё.
|
|
17
|
+
* 6. Эмитирует все файлы в dist/assets/ с точными именами (без Rollup-хеша).
|
|
18
|
+
* 7. Модуль по умолчанию: `{ src, originalW, originalH }` — `src` как раньше (URL оригинала).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
declare function imageThumbnails(): Plugin;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* При `vite build` не встраивает импортируемые статические ассеты внутрь JS (base64 / data URL).
|
|
25
|
+
* Вместо этого они остаются отдельными файлами в `dist`, в коде — только строковые URL.
|
|
26
|
+
*
|
|
27
|
+
* Задаёт `build.assetsInlineLimit: 0` (в Vite один лимит на весь пайплайн статических импортов:
|
|
28
|
+
* отключается inlining не только у изображений, но и у других мелких ассетов, которые Vite
|
|
29
|
+
* мог бы положить в бандл).
|
|
30
|
+
*/
|
|
31
|
+
declare function importedAssetsAlwaysFiles(): Plugin;
|
|
32
|
+
|
|
33
|
+
declare function smartImgLocalAssetImport(): Plugin;
|
|
34
|
+
|
|
35
|
+
declare function smartImgSvgAssetBuild(): Plugin;
|
|
36
|
+
|
|
37
|
+
export { imageThumbnails, importedAssetsAlwaysFiles, smartImgLocalAssetImport, smartImgSvgAssetBuild };
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Vite-плагин продакшн-обработки изображений из папок assets/.
|
|
5
|
+
*
|
|
6
|
+
* Работает только в режиме `build` (apply: 'build').
|
|
7
|
+
* В dev-режиме IS_DEV в smartImgManager грузит оригинал напрямую.
|
|
8
|
+
*
|
|
9
|
+
* Что делает при билде:
|
|
10
|
+
* 1. Перехватывает импорты картинок из любой папки assets/ в проекте.
|
|
11
|
+
* 2. Хеширует содержимое файла (SHA-256, 8 символов) → имя без коллизий.
|
|
12
|
+
* 3. Прогоняет оригинал через sharp — снимает EXIF/метаданные, корректирует
|
|
13
|
+
* ориентацию по EXIF (.rotate()) перед его удалением.
|
|
14
|
+
* 4. Нарезает миниатюры для размеров из SIZES, не превышающих ширину оригинала.
|
|
15
|
+
* 5. Для каждого размера создаёт .jpg/.png и .webp.
|
|
16
|
+
* Если миниатюра тяжелее очищенного оригинала — записывает оригинал вместо неё.
|
|
17
|
+
* 6. Эмитирует все файлы в dist/assets/ с точными именами (без Rollup-хеша).
|
|
18
|
+
* 7. Модуль по умолчанию: `{ src, originalW, originalH }` — `src` как раньше (URL оригинала).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
declare function imageThumbnails(): Plugin;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* При `vite build` не встраивает импортируемые статические ассеты внутрь JS (base64 / data URL).
|
|
25
|
+
* Вместо этого они остаются отдельными файлами в `dist`, в коде — только строковые URL.
|
|
26
|
+
*
|
|
27
|
+
* Задаёт `build.assetsInlineLimit: 0` (в Vite один лимит на весь пайплайн статических импортов:
|
|
28
|
+
* отключается inlining не только у изображений, но и у других мелких ассетов, которые Vite
|
|
29
|
+
* мог бы положить в бандл).
|
|
30
|
+
*/
|
|
31
|
+
declare function importedAssetsAlwaysFiles(): Plugin;
|
|
32
|
+
|
|
33
|
+
declare function smartImgLocalAssetImport(): Plugin;
|
|
34
|
+
|
|
35
|
+
declare function smartImgSvgAssetBuild(): Plugin;
|
|
36
|
+
|
|
37
|
+
export { imageThumbnails, importedAssetsAlwaysFiles, smartImgLocalAssetImport, smartImgSvgAssetBuild };
|