vite-plugin-singlefile-compression 2.2.1 → 2.2.3

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 CHANGED
@@ -152,21 +152,21 @@ type: `boolean`
152
152
  Preview: https://bddjr.github.io/vite-plugin-singlefile-compression/
153
153
 
154
154
  ```
155
- vite v8.0.3 building client environment for production...
155
+ vite v8.0.5 building client environment for production...
156
156
  ✓ 42 modules transformed.
157
157
  rendering chunks (1)...
158
158
 
159
- vite-plugin-singlefile-compression 2.2.1 deflate-raw base128-ascii
159
+ vite-plugin-singlefile-compression 2.2.3 deflate-raw base128-ascii
160
160
 
161
161
  file:///D:/code/js/vite-plugin-singlefile-compression/test/dist/index.html
162
- 122.739 kB -> 50.220 kB
162
+ 122.750 kB -> 50.221 kB
163
163
 
164
164
  Finish.
165
165
 
166
166
  computing gzip size...
167
- dist/index.html 50.22 kB │ gzip: 43.77 kB
167
+ dist/index.html 50.22 kB │ gzip: 43.79 kB
168
168
 
169
- ✓ built in 461ms
169
+ ✓ built in 275ms
170
170
  ```
171
171
 
172
172
  ## Clone
package/dist/index.d.ts CHANGED
@@ -2,27 +2,27 @@ import { Options as HtmlMinifierOptions } from "html-minifier-terser";
2
2
  import zlib from "zlib";
3
3
  import { PluginOption } from "vite";
4
4
 
5
- //#region _dist/compress.d.ts
5
+ //#region src/compress.d.ts
6
6
  declare const compressors: {
7
- "deflate-raw"(buf: zlib.InputType): Buffer;
8
- deflate(buf: zlib.InputType): Buffer;
9
- gzip(buf: zlib.InputType): Buffer;
10
- brotli: typeof zlib.brotliCompressSync;
11
- zstd: (buf: zlib.InputType) => NonSharedBuffer;
7
+ readonly "deflate-raw": (buf: zlib.InputType) => Buffer;
8
+ readonly deflate: (buf: zlib.InputType) => Buffer;
9
+ readonly gzip: (buf: zlib.InputType) => Buffer;
10
+ readonly brotli: typeof zlib.brotliCompressSync;
11
+ readonly zstd: (buf: zlib.InputType) => Buffer;
12
+ };
13
+ declare const compressFormatAlias: {
14
+ readonly deflateRaw: "deflate-raw";
15
+ readonly gz: "gzip";
16
+ readonly br: "brotli";
17
+ readonly brotliCompress: "brotli";
18
+ readonly zstandard: "zstd";
19
+ readonly zst: "zstd";
12
20
  };
13
- declare const compressFormatAlias: Readonly<{
14
- deflateRaw: "deflate-raw";
15
- gz: "gzip";
16
- br: "brotli";
17
- brotliCompress: "brotli";
18
- zstandard: "zstd";
19
- zst: "zstd";
20
- }>;
21
21
  type Compressor = ((buf: zlib.InputType) => (Buffer | Uint8Array | Promise<Buffer | Uint8Array>));
22
22
  type CompressFormat = keyof typeof compressors | CompressionFormat;
23
23
  type CompressFormatAlias = keyof typeof compressFormatAlias;
24
24
  //#endregion
25
- //#region _dist/options.d.ts
25
+ //#region src/options.d.ts
26
26
  interface Options {
27
27
  /**
28
28
  * Rename index.html
@@ -87,7 +87,7 @@ interface Options {
87
87
  }
88
88
  declare const defaultHtmlMinifierTerserOptions: HtmlMinifierOptions;
89
89
  //#endregion
90
- //#region _dist/index.d.ts
90
+ //#region src/index.d.ts
91
91
  declare function singleFileCompression(opt?: Options): PluginOption;
92
92
  //#endregion
93
93
  export { CompressFormat, CompressFormatAlias, Compressor, HtmlMinifierOptions, Options, singleFileCompression as default, singleFileCompression, defaultHtmlMinifierTerserOptions };
package/dist/index.js CHANGED
@@ -8,10 +8,10 @@ import base128 from "base128-ascii";
8
8
  import zlib from "zlib";
9
9
  import svgToTinyDataUri from "mini-svg-data-uri";
10
10
  import mime from "mime";
11
- //#region _dist/getVersion.js
12
- var version = "2.2.1";
11
+ //#region package.json
12
+ var version = "2.2.3";
13
13
  //#endregion
14
- //#region _dist/compress.js
14
+ //#region src/compress.ts
15
15
  const compressors = {
16
16
  "deflate-raw"(buf) {
17
17
  return zlib.deflateRawSync(buf, { level: zlib.constants.Z_BEST_COMPRESSION });
@@ -25,14 +25,14 @@ const compressors = {
25
25
  brotli: zlib.brotliCompressSync,
26
26
  zstd: zlib.zstdCompressSync && ((buf) => zlib.zstdCompressSync(buf, { params: { [zlib.constants.ZSTD_c_compressionLevel]: 19 } }))
27
27
  };
28
- const compressFormatAlias = Object.freeze({
28
+ const compressFormatAlias = {
29
29
  deflateRaw: "deflate-raw",
30
30
  gz: "gzip",
31
31
  br: "brotli",
32
32
  brotliCompress: "brotli",
33
33
  zstandard: "zstd",
34
34
  zst: "zstd"
35
- });
35
+ };
36
36
  function switchCompressor(format) {
37
37
  if (compressors.hasOwnProperty(format)) {
38
38
  const f = compressors[format];
@@ -64,62 +64,59 @@ async function compress(format, buf, useBase128, compressor) {
64
64
  return Buffer.from(outBuf).toString("base64");
65
65
  }
66
66
  //#endregion
67
- //#region _dist/templateRaw.js
68
- var raw = {
69
- "assets": "{let e={\"\":\"\"};for(let o in e)for(let s of document.querySelectorAll(`[src=\"data:${o}\"]`))s.src=e[o]}",
70
- "base128": "var a=\"<script>\",c=a.length,r=new Uint8Array(c/8*7),p=0,n=0,e,t=o=>(e=a.charCodeAt(p++))>127?e=0:e,i=Response;for(;p<c;)r[n++]=t()<<1|t()>>6,r[n++]=e<<2|t()>>5,r[n++]=e<<3|t()>>4,r[n++]=e<<4|t()>>3,r[n++]=e<<5|t()>>2,r[n++]=e<<6|t()>>1,r[n++]=e<<7|t();new i(new i(r).body.pipeThrough(new DecompressionStream(\"<format>\")),{headers:{\"Content-Type\":\"text/javascript\"}}).blob().then(o=>(import(o=URL.createObjectURL(o)),URL.revokeObjectURL(o)))",
71
- "base64": "fetch(\"data:;base64,<script>\").then(e=>new Response(e.body.pipeThrough(new DecompressionStream(\"<format>\")),{headers:{\"Content-Type\":\"text/javascript\"}}).blob()).then(e=>(import(e=URL.createObjectURL(e)),URL.revokeObjectURL(e)))",
72
- "css": "document.head.appendChild(document.createElement(\"style\")).innerHTML=\"<style>\"",
73
- "icon": "document.querySelector(\"link[rel=icon]\").href=\"<icon>\"",
74
- "importmeta": "{let e=import.meta,r=e.resolve,l=e.url=new URL(\"<path>\",location).href;e.resolve=function(t){return/^\\.{0,2}\\//.test(t)?new URL(t,l).href:r.apply(this,arguments)}}"
75
- };
76
- //#endregion
77
- //#region _dist/getTemplate.js
78
- function split2(str, separator) {
79
- const s = str.split(separator);
80
- if (s.length !== 2) throw Error("s.length!==2");
81
- return s;
82
- }
67
+ //#region _dist/templateRaw.ts
83
68
  const files = {
84
- base64: raw.base64,
85
- base128: raw.base128,
86
- assets: split2(raw.assets, "{\"\":\"\"}"),
87
- css: split2(raw.css, "\"<style>\""),
88
- icon: split2(raw.icon, "\"<icon>\""),
89
- importmeta: split2(raw.importmeta, "\"<path>\"")
69
+ "assets": ["{let e=", ";for(let l in e)for(let r of document.querySelectorAll(`[src=\"data:${l}\"]`))r.src=e[l]}"],
70
+ "base128": [
71
+ "for(var e,t=",
72
+ ",r=t.length,n=new Uint8Array(r/8*7),o=0,a=0,_=r=>(e=t.charCodeAt(o++))>127?e=0:e,p=Response;o<r;)n[a++]=_()<<1|_()>>6,n[a++]=e<<2|_()>>5,n[a++]=e<<3|_()>>4,n[a++]=e<<4|_()>>3,n[a++]=e<<5|_()>>2,n[a++]=e<<6|_()>>1,n[a++]=e<<7|_();new p(new p(n).body.pipeThrough(new DecompressionStream(",
73
+ ")),{headers:{\"Content-Type\":\"text/javascript\"}}).blob().then(e=>(import(e=URL.createObjectURL(e)),URL.revokeObjectURL(e)))"
74
+ ],
75
+ "base64": [
76
+ "fetch(\"data:;base64,",
77
+ "\").then(e=>new Response(e.body.pipeThrough(new DecompressionStream(",
78
+ ")),{headers:{\"Content-Type\":\"text/javascript\"}}).blob()).then(e=>(import(e=URL.createObjectURL(e)),URL.revokeObjectURL(e)))"
79
+ ],
80
+ "css": "document.head.appendChild(document.createElement(\"style\")).innerHTML=",
81
+ "icon": "document.querySelector(\"link[rel=icon]\").href=",
82
+ "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)}}"]
90
83
  };
84
+ //#endregion
85
+ //#region src/getTemplate.ts
91
86
  const template = {
92
87
  async base(script, format, useBase128, compressor) {
93
88
  script = await compress(format, script, useBase128, compressor);
94
- if (useBase128) return files.base128.replace("<format>", format).split("\"<script>\"", 2).join(script);
95
- return files.base64.replace("<format>", format).split("<script>", 2).join(script);
89
+ const t = useBase128 ? files.base128 : files.base64;
90
+ return t[0].concat(script, t[1], JSON.stringify(format), t[2]);
96
91
  },
97
92
  assets(assetsJSON) {
98
- return files.assets.join(assetsJSON);
93
+ const t = files.assets;
94
+ return t[0].concat(JSON.stringify(assetsJSON), t[1]);
99
95
  },
100
96
  css(cssSource) {
101
- return files.css.join(JSON.stringify(cssSource));
97
+ return files.css + JSON.stringify(cssSource);
102
98
  },
103
99
  icon(dataURL) {
104
- return files.icon.join(JSON.stringify(dataURL));
100
+ return files.icon + JSON.stringify(dataURL);
105
101
  },
106
102
  importmeta(p) {
107
- return files.importmeta.join(JSON.stringify(p));
103
+ const t = files.importmeta;
104
+ return t[0].concat(JSON.stringify(p), t[1]);
108
105
  }
109
106
  };
110
107
  //#endregion
111
- //#region _dist/dataurl.js
108
+ //#region src/dataurl.ts
112
109
  function bufferToDataURL(name, b) {
113
110
  return /\.svg$/i.test(name) ? svgToTinyDataUri(b.toString()) : `data:${mime.getType(name)};base64,${b.toString("base64")}`;
114
111
  }
115
112
  //#endregion
116
- //#region _dist/kB.js
113
+ //#region src/kB.ts
117
114
  function kB(size) {
118
115
  const s = String(size).padStart(4, "0");
119
116
  return `${s.slice(0, -3)}.${s.slice(-3)} kB`;
120
117
  }
121
118
  //#endregion
122
- //#region _dist/options.js
119
+ //#region src/options.ts
123
120
  const defaultHtmlMinifierTerserOptions = {
124
121
  removeAttributeQuotes: true,
125
122
  removeComments: true,
@@ -145,12 +142,12 @@ function getInnerOptions(opt) {
145
142
  };
146
143
  }
147
144
  //#endregion
148
- //#region _dist/cutPrefix.js
145
+ //#region src/cutPrefix.ts
149
146
  function cutPrefix(str, prefix) {
150
147
  return str.startsWith(prefix) ? str.slice(prefix.length) : str;
151
148
  }
152
149
  //#endregion
153
- //#region _dist/index.js
150
+ //#region src/index.ts
154
151
  function singleFileCompression(opt) {
155
152
  let conf;
156
153
  const innerOptions = getInnerOptions(opt);
@@ -195,7 +192,7 @@ async function generateBundle(bundle, config, options) {
195
192
  for (const htmlFileName of bundleHTMLNames) {
196
193
  console.log("\n " + pc.underline(pc.cyan(distURL) + pc.greenBright(bundle[htmlFileName].fileName)));
197
194
  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) : "";
198
- let oldSize = oldHTML.length;
195
+ let oldSize = Buffer.byteLength(oldHTML);
199
196
  if (scriptElement) {
200
197
  scriptElement.remove();
201
198
  scriptElement.removeAttribute("src");
@@ -210,7 +207,7 @@ async function generateBundle(bundle, config, options) {
210
207
  thisDel.add(name);
211
208
  const cssSource = bundle[name].source;
212
209
  if (cssSource) {
213
- oldSize += cssSource.length;
210
+ oldSize += Buffer.byteLength(cssSource);
214
211
  for (const name of bundleAssetsNames) if (cssSource.includes(name.slice(assetsDir.length))) globalDoNotDelete.add(name);
215
212
  allCSS += cssSource.replace(/\s*(\/\*[^*]*\*\/)?\s*$/, "");
216
213
  }
@@ -232,10 +229,15 @@ async function generateBundle(bundle, config, options) {
232
229
  const a = bundle[bundleName];
233
230
  if (!a) continue;
234
231
  thisDel.add(bundleName);
235
- oldSize += a.source.length;
236
232
  let dataURL;
237
- if (Object.prototype.hasOwnProperty.call(globalAssetsDataURL, name)) dataURL = globalAssetsDataURL[name];
238
- else globalAssetsDataURL[name] = dataURL = bufferToDataURL(name, Buffer.from(a.source));
233
+ if (Object.prototype.hasOwnProperty.call(globalAssetsDataURL, name)) {
234
+ oldSize += Buffer.byteLength(a.source);
235
+ dataURL = globalAssetsDataURL[name];
236
+ } else {
237
+ const buf = Buffer.from(a.source);
238
+ oldSize += buf.length;
239
+ globalAssetsDataURL[name] = dataURL = bufferToDataURL(name, buf);
240
+ }
239
241
  if (options.enableCompress) assetsDataURL[name] = dataURL;
240
242
  else element.src = dataURL;
241
243
  }
@@ -290,7 +292,7 @@ async function generateBundle(bundle, config, options) {
290
292
  if (scriptElement) {
291
293
  thisDel.add(scriptName);
292
294
  let { code } = bundle[scriptName];
293
- oldSize += code.length;
295
+ oldSize += Buffer.byteLength(code);
294
296
  code = code.replace(/;?\n?$/, "");
295
297
  for (const name of bundleAssetsNames) {
296
298
  const assetName = name.slice(assetsDir.length);
@@ -301,14 +303,15 @@ async function generateBundle(bundle, config, options) {
301
303
  }
302
304
  inlineHtmlAssets();
303
305
  if (options.useImportMetaPolyfill) newJSCode.push(template.importmeta(scriptName));
304
- if (/\b__VITE_PRELOAD__\b/.test(code)) newJSCode.push("var __VITE_PRELOAD__");
306
+ if (/\b__VITE_PRELOAD__\b/.test(code)) if (code.startsWith("var ")) code = "var __VITE_PRELOAD__," + code.slice(4);
307
+ else newJSCode.push("var __VITE_PRELOAD__");
305
308
  newJSCode.push(code);
306
309
  } else inlineHtmlAssets();
307
310
  let outputScript = newJSCode.join(";");
308
311
  if (options.enableCompress) outputScript = await template.base(outputScript, options.compressFormat, options.useBase128, options.compressor);
309
312
  else outputScript = outputScript.replaceAll("<\/script", "<\\/script");
310
- htmlChunk.source = htmlChunk.source.split(fakeScript, 2).join(outputScript);
311
- console.log(" " + pc.gray(kB(oldSize) + " -> ") + pc.cyanBright(kB(htmlChunk.source.length)) + "\n");
313
+ htmlChunk.source = htmlChunk.source.replace(fakeScript, () => outputScript);
314
+ console.log(" " + pc.gray(kB(oldSize) + " -> ") + pc.cyanBright(kB(Buffer.byteLength(htmlChunk.source))) + "\n");
312
315
  for (const name of thisDel) globalDelete.add(name);
313
316
  }
314
317
  if (options.removeInlinedAssetFiles) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-singlefile-compression",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
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.",
@@ -11,7 +11,7 @@
11
11
  ],
12
12
  "type": "module",
13
13
  "scripts": {
14
- "build": "rimraf dist _dist && tsc && node build.js && cd test && node --run build",
14
+ "build": "tsc && node build.js && tsc _dist/templateRaw.ts --ignoreConfig --noEmit && cd test && node --run build",
15
15
  "prepublishOnly": "node --run build"
16
16
  },
17
17
  "repository": {
@@ -32,7 +32,7 @@
32
32
  "compression",
33
33
  "compress",
34
34
  "compressionstream",
35
- "decompres",
35
+ "decompress",
36
36
  "decompression",
37
37
  "decompressionstream",
38
38
  "compression streams api",
@@ -90,13 +90,11 @@
90
90
  "vite": ">=3.0.0"
91
91
  },
92
92
  "devDependencies": {
93
- "@bddjr/rimraf": "^0.1.0",
94
93
  "@types/jsdom": ">=28.0.0",
95
94
  "@types/node": "^22.19.15",
96
- "esbuild": "^0.27.4",
97
95
  "rolldown": ">=1.0.0-rc.9",
98
96
  "rolldown-plugin-dts": "^0.22.5",
99
- "rollup": ">=4.59.0",
97
+ "terser": "^5.46.1",
100
98
  "typescript": ">=5.9.3",
101
99
  "vite": ">=8.0.0"
102
100
  }