vite-plugin-singlefile-compression 2.4.0 → 2.4.1
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/README.md +5 -5
- package/dist/index.js +82 -71
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -170,21 +170,21 @@ type: `boolean`
|
|
|
170
170
|
Preview: https://bddjr.github.io/vite-plugin-singlefile-compression/#/
|
|
171
171
|
|
|
172
172
|
```
|
|
173
|
-
vite v8.0.
|
|
173
|
+
vite v8.0.10 building client environment for production...
|
|
174
174
|
✓ 43 modules transformed.
|
|
175
175
|
rendering chunks (1)...
|
|
176
176
|
|
|
177
|
-
vite-plugin-singlefile-compression 2.4.
|
|
177
|
+
vite-plugin-singlefile-compression 2.4.1 deflate-raw base128-ascii
|
|
178
178
|
|
|
179
179
|
file:///D:/code/js/vite-plugin-singlefile-compression/test/dist/index.html
|
|
180
|
-
126.
|
|
180
|
+
126.509 kB -> 59.596 kB
|
|
181
181
|
|
|
182
182
|
Finish.
|
|
183
183
|
|
|
184
184
|
computing gzip size...
|
|
185
|
-
dist/index.html 59.
|
|
185
|
+
dist/index.html 59.59 kB │ gzip: 44.92 kB
|
|
186
186
|
|
|
187
|
-
✓ built in
|
|
187
|
+
✓ built in 307ms
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
## Clone
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import zlib from "zlib";
|
|
|
9
9
|
import svgToTinyDataUri from "mini-svg-data-uri";
|
|
10
10
|
import { lookup } from "mrmime";
|
|
11
11
|
//#region package.json
|
|
12
|
-
var version = "2.4.
|
|
12
|
+
var version = "2.4.1";
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/compress.ts
|
|
15
15
|
const compressors = {
|
|
@@ -77,8 +77,6 @@ const files = {
|
|
|
77
77
|
"\").then(e=>new Response(e.body.pipeThrough(new DecompressionStream(",
|
|
78
78
|
"))).text()).then(e=>{var t=document.createElement(\"script\");t.type=\"module\",t.innerHTML=e,document.head.appendChild(t)})"
|
|
79
79
|
],
|
|
80
|
-
"css": "document.head.appendChild(document.createElement(\"style\")).innerHTML=",
|
|
81
|
-
"icon": "document.querySelector(\"link[rel=icon]\").href=",
|
|
82
80
|
"importmeta": ["{let e=import.meta,t=e.resolve,r=e.url=new URL(", ",location).href;e.resolve=function(e){return/^\\.{0,2}\\//.test(e)?new URL(e,r).href:t.apply(this,arguments)}}"]
|
|
83
81
|
};
|
|
84
82
|
//#endregion
|
|
@@ -93,12 +91,6 @@ const template = {
|
|
|
93
91
|
const t = files.assets;
|
|
94
92
|
return t[0].concat(JSON.stringify(assetsJSON), t[1]);
|
|
95
93
|
},
|
|
96
|
-
css(cssSource) {
|
|
97
|
-
return files.css + JSON.stringify(cssSource);
|
|
98
|
-
},
|
|
99
|
-
icon(dataURL) {
|
|
100
|
-
return files.icon + JSON.stringify(dataURL);
|
|
101
|
-
},
|
|
102
94
|
importmeta(p) {
|
|
103
95
|
const t = files.importmeta;
|
|
104
96
|
return t[0].concat(JSON.stringify(p), t[1]);
|
|
@@ -188,12 +180,12 @@ async function generateBundle(bundle, config, options) {
|
|
|
188
180
|
bundle[options.rename].fileName = options.rename;
|
|
189
181
|
delete bundle["index.html"];
|
|
190
182
|
}
|
|
191
|
-
const distURL = pathToFileURL(config.build.outDir).href + "/", assetsDir = path.posix.join(config.build.assetsDir, "/"), assetsDirWithBase = config.base + assetsDir, assetsHrefSelector = `[href^="${assetsDirWithBase}"]`, assetsSrcSelector = `[src^="${assetsDirWithBase}"]`, fakeScript = `
|
|
183
|
+
const distURL = pathToFileURL(config.build.outDir).href + "/", assetsDir = path.posix.join(config.build.assetsDir, "/"), assetsDirWithBase = config.base + assetsDir, assetsHrefSelector = `[href^="${assetsDirWithBase}"]`, assetsSrcSelector = `[src^="${assetsDirWithBase}"]`, fakeScript = `_${Math.random().toString(36).slice(2, 10)}()`, globalDelete = /* @__PURE__ */ new Set(), globalDoNotDelete = /* @__PURE__ */ new Set(), globalRemoveDistFileNames = /* @__PURE__ */ new Set(), globalAssetsDataURL = {}, globalPublicFilesCache = {}, bundleAssetsNames = [], bundleHTMLNames = [];
|
|
192
184
|
for (const name in bundle) if (name.startsWith(assetsDir)) bundleAssetsNames.push(name);
|
|
193
185
|
else if (/\.html$/i.test(name)) bundleHTMLNames.push(name);
|
|
194
186
|
for (const htmlFileName of bundleHTMLNames) {
|
|
195
187
|
console.log("\n " + pc.underline(pc.cyan(distURL) + pc.greenBright(bundle[htmlFileName].fileName)));
|
|
196
|
-
const htmlChunk = bundle[htmlFileName], oldHTML = htmlChunk.source, dom = new JSDOM(oldHTML), document = dom.window.document, thisDel = /* @__PURE__ */ new Set(), newJSCode = [], scriptElement = document.querySelector(`script[type=module]${assetsSrcSelector}`), scriptName = scriptElement ? cutPrefix(scriptElement.src, config.base) : "";
|
|
188
|
+
const htmlChunk = bundle[htmlFileName], oldHTML = htmlChunk.source, dom = new JSDOM(oldHTML), document = dom.window.document, thisDel = /* @__PURE__ */ new Set(), newJSCode = [], scriptElement = document.querySelector(`script[type=module]${assetsSrcSelector}`), scriptName = scriptElement ? cutPrefix(scriptElement.src, config.base) : "", compressHeadElements = [];
|
|
197
189
|
let oldSize = Buffer.byteLength(oldHTML);
|
|
198
190
|
if (scriptElement) {
|
|
199
191
|
scriptElement.remove();
|
|
@@ -211,16 +203,18 @@ async function generateBundle(bundle, config, options) {
|
|
|
211
203
|
if (cssSource) {
|
|
212
204
|
oldSize += Buffer.byteLength(cssSource);
|
|
213
205
|
for (const name of bundleAssetsNames) if (cssSource.includes(name.slice(assetsDir.length))) globalDoNotDelete.add(name);
|
|
214
|
-
allCSS += cssSource.replace(
|
|
206
|
+
allCSS += cssSource.replace(/(\s*\/\*([^*]|\*(?!\/))*\*\/)*\s*$/, "");
|
|
215
207
|
}
|
|
216
208
|
if (options.enableCompress) element.remove();
|
|
217
209
|
}
|
|
218
|
-
if (allCSS)
|
|
219
|
-
else {
|
|
210
|
+
if (allCSS) {
|
|
220
211
|
const e = document.createElement("style");
|
|
221
212
|
e.innerHTML = allCSS;
|
|
222
|
-
|
|
223
|
-
|
|
213
|
+
if (options.enableCompress) compressHeadElements.push(e);
|
|
214
|
+
else {
|
|
215
|
+
linkStylesheet[0].before(e);
|
|
216
|
+
for (const e of linkStylesheet) e.remove();
|
|
217
|
+
}
|
|
224
218
|
}
|
|
225
219
|
const assetsDataURL = {};
|
|
226
220
|
if (options.tryInlineHtmlAssets) for (const element of document.querySelectorAll(assetsSrcSelector)) {
|
|
@@ -245,61 +239,73 @@ async function generateBundle(bundle, config, options) {
|
|
|
245
239
|
}
|
|
246
240
|
if (options.enableCompress) element.src = `data:${name}`;
|
|
247
241
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (
|
|
242
|
+
const createIconElement = (href) => {
|
|
243
|
+
const e = document.createElement("link");
|
|
244
|
+
e.rel = "icon";
|
|
245
|
+
if (href != null) e.href = href;
|
|
246
|
+
return e;
|
|
247
|
+
};
|
|
248
|
+
const getPublicIcon = (faviconName) => {
|
|
249
|
+
if (Object.prototype.hasOwnProperty.call(globalPublicFilesCache, faviconName)) return globalPublicFilesCache[faviconName];
|
|
250
|
+
let _path = path.join(config.build.outDir, faviconName);
|
|
251
|
+
if (fs.existsSync(_path)) globalRemoveDistFileNames.add(faviconName);
|
|
252
252
|
else {
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
_path = path.join(config.publicDir, faviconName);
|
|
254
|
+
if (!fs.existsSync(_path)) return null;
|
|
255
255
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
256
|
+
const b = fs.readFileSync(_path);
|
|
257
|
+
return globalPublicFilesCache[faviconName] = {
|
|
258
|
+
buffer: b,
|
|
259
|
+
dataURL: bufferToDataURL(faviconName, b),
|
|
260
|
+
size: b.length
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
const linkFaviconAll = document.querySelectorAll(`link[rel=icon][href]:not([href=""]),link[rel="shortcut icon"][href]:not([href=""])`);
|
|
264
|
+
if (linkFaviconAll.length == 0) {
|
|
265
|
+
if (options.tryInlineHtmlPublicIcon) {
|
|
266
|
+
const fileCache = getPublicIcon("favicon.ico");
|
|
267
|
+
if (fileCache) {
|
|
268
|
+
oldSize += fileCache.size;
|
|
269
|
+
const e = createIconElement(fileCache.dataURL);
|
|
270
|
+
if (options.enableCompressInlinedIcon) compressHeadElements.push(e);
|
|
271
|
+
else document.head.appendChild(e);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
} else for (const linkFavicon of linkFaviconAll) {
|
|
275
|
+
let faviconName = linkFavicon.href;
|
|
276
|
+
const faviconIsDataURL = /^data:/i.test(faviconName);
|
|
262
277
|
if (!faviconIsDataURL) faviconName = cutPrefix(faviconName, config.base);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
else
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
278
|
+
const setFaviconDataURL = (dataURL) => {
|
|
279
|
+
if (options.enableCompressInlinedIcon) if (linkFavicon) {
|
|
280
|
+
linkFavicon.remove();
|
|
281
|
+
linkFavicon.href = dataURL;
|
|
282
|
+
compressHeadElements.push(linkFavicon);
|
|
283
|
+
} else compressHeadElements.push(createIconElement(dataURL));
|
|
284
|
+
else if (linkFavicon) linkFavicon.href = dataURL;
|
|
285
|
+
else document.head.appendChild(createIconElement(dataURL));
|
|
286
|
+
};
|
|
287
|
+
if (faviconIsDataURL) {
|
|
288
|
+
if (options.enableCompressInlinedIcon) {
|
|
289
|
+
linkFavicon.remove();
|
|
290
|
+
compressHeadElements.push(linkFavicon);
|
|
291
|
+
}
|
|
292
|
+
} else if (bundleAssetsNames.includes(faviconName)) {
|
|
293
|
+
const asset = bundle[faviconName];
|
|
294
|
+
if (asset) {
|
|
295
|
+
setFaviconDataURL(bufferToDataURL(faviconName, Buffer.from(asset.source)));
|
|
296
|
+
thisDel.add(faviconName);
|
|
297
|
+
}
|
|
298
|
+
} else if (options.tryInlineHtmlPublicIcon) {
|
|
299
|
+
const fileCache = getPublicIcon(faviconName);
|
|
300
|
+
if (fileCache) {
|
|
301
|
+
oldSize += fileCache.size;
|
|
302
|
+
setFaviconDataURL(fileCache.dataURL);
|
|
303
|
+
}
|
|
274
304
|
}
|
|
275
305
|
}
|
|
276
|
-
if (
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
linkFavicon.href = "data:";
|
|
280
|
-
}
|
|
281
|
-
} else if (bundleAssetsNames.includes(faviconName)) {
|
|
282
|
-
const asset = bundle[faviconName];
|
|
283
|
-
if (asset) {
|
|
284
|
-
setFaviconDataURL(bufferToDataURL(faviconName, Buffer.from(asset.source)));
|
|
285
|
-
thisDel.add(faviconName);
|
|
286
|
-
}
|
|
287
|
-
} else if (options.tryInlineHtmlPublicIcon) try {
|
|
288
|
-
if (!Object.prototype.hasOwnProperty.call(globalPublicFilesCache, faviconName)) {
|
|
289
|
-
let Path = path.join(config.build.outDir, faviconName);
|
|
290
|
-
if (fs.existsSync(Path)) globalRemoveDistFileNames.add(faviconName);
|
|
291
|
-
else Path = path.join(config.publicDir, faviconName);
|
|
292
|
-
const b = fs.readFileSync(Path);
|
|
293
|
-
globalPublicFilesCache[faviconName] = {
|
|
294
|
-
dataURL: bufferToDataURL(faviconName, b),
|
|
295
|
-
size: b.length
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
const { dataURL, size } = globalPublicFilesCache[faviconName];
|
|
299
|
-
oldSize += size;
|
|
300
|
-
setFaviconDataURL(dataURL);
|
|
301
|
-
} catch (e) {
|
|
302
|
-
if (linkFavicon) console.error(e);
|
|
306
|
+
if (compressHeadElements.length) {
|
|
307
|
+
const html = compressHeadElements.map((v) => v.outerHTML).join("");
|
|
308
|
+
newJSCode.push(`document.head.insertAdjacentHTML("beforeend",${JSON.stringify(html)})`);
|
|
303
309
|
}
|
|
304
310
|
htmlChunk.source = dom.serialize();
|
|
305
311
|
if (options.htmlMinifierTerser) htmlChunk.source = await minify(htmlChunk.source, options.htmlMinifierTerser);
|
|
@@ -313,7 +319,7 @@ async function generateBundle(bundle, config, options) {
|
|
|
313
319
|
thisDel.add(scriptName);
|
|
314
320
|
let { code } = bundle[scriptName];
|
|
315
321
|
oldSize += Buffer.byteLength(code);
|
|
316
|
-
code = code.replace(/;?\
|
|
322
|
+
code = code.replace(/;?\s*$/, "");
|
|
317
323
|
for (const name of bundleAssetsNames) {
|
|
318
324
|
const assetName = name.slice(assetsDir.length);
|
|
319
325
|
if (code.includes(assetName)) globalDoNotDelete.add(name);
|
|
@@ -333,10 +339,15 @@ async function generateBundle(bundle, config, options) {
|
|
|
333
339
|
if (options.removeInlinedAssetFiles) {
|
|
334
340
|
for (const name of globalDelete) if (!globalDoNotDelete.has(name)) delete bundle[name];
|
|
335
341
|
}
|
|
336
|
-
if (options.removeInlinedPublicIconFiles)
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
342
|
+
if (options.removeInlinedPublicIconFiles) {
|
|
343
|
+
const { outDir } = config.build;
|
|
344
|
+
const mustStartsWith = path.resolve(outDir) + path.sep;
|
|
345
|
+
for (const name of globalRemoveDistFileNames) try {
|
|
346
|
+
const _path = path.resolve(outDir, name);
|
|
347
|
+
if (_path.startsWith(mustStartsWith)) fs.rmSync(_path, { force: true });
|
|
348
|
+
} catch (e) {
|
|
349
|
+
console.error(e);
|
|
350
|
+
}
|
|
340
351
|
}
|
|
341
352
|
console.log(pc.green("Finish.") + pc.reset("\n"));
|
|
342
353
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-singlefile-compression",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"author": "bddjr",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Compress all assets and embeds them into dist/index.html, making it convenient to share as a single HTML file.",
|
|
@@ -101,10 +101,10 @@
|
|
|
101
101
|
"@bddjr/types-rollupoptions-4.43.0": "4.43.0",
|
|
102
102
|
"@types/jsdom": ">=28.0.1",
|
|
103
103
|
"@types/node": "^24.12.2",
|
|
104
|
-
"rolldown": ">=1.0.0-rc.
|
|
104
|
+
"rolldown": ">=1.0.0-rc.17",
|
|
105
105
|
"rolldown-plugin-dts": ">=0.23.2",
|
|
106
|
-
"terser": ">=5.46.
|
|
107
|
-
"typescript": ">=6.0.
|
|
108
|
-
"vite": ">=8.0.
|
|
106
|
+
"terser": ">=5.46.2",
|
|
107
|
+
"typescript": ">=6.0.3",
|
|
108
|
+
"vite": ">=8.0.10"
|
|
109
109
|
}
|
|
110
110
|
}
|