vite-plugin-singlefile-compression 2.1.1 → 2.2.0

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
@@ -4,7 +4,9 @@ Compress all assets and embeds them into `dist/index.html`, making it convenient
4
4
 
5
5
  The recipient can open it directly in the browser without manually unzipping the file.
6
6
 
7
- Using [DecompressionStream](https://developer.mozilla.org/docs/Web/API/DecompressionStream) + [base128-ascii](https://www.npmjs.com/package/base128-ascii).
7
+ Using [DecompressionStream](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream) + [base128-ascii](https://www.npmjs.com/package/base128-ascii).
8
+
9
+ Preview: https://bddjr.github.io/vite-plugin-singlefile-compression/
8
10
 
9
11
  ## Setup
10
12
 
@@ -43,107 +45,130 @@ singleFileCompression({
43
45
  }),
44
46
  ```
45
47
 
46
- More info see [src/options.ts](src/options.ts)
48
+ ### rename
49
+
50
+ Rename index.html
51
+
52
+ type: `string`
53
+
54
+ ### enableCompress
55
+
56
+ Enable compress.
57
+
58
+ default: `true`
59
+
60
+ type: `boolean`
61
+
62
+ ### useBase128
63
+
64
+ Use Base128 to encode compressed script.
65
+ If false, use Base64.
66
+ https://www.npmjs.com/package/base128-ascii
67
+
68
+ default: `true`
69
+
70
+ type: `boolean`
71
+
72
+ ### compressFormat
73
+
74
+ Compress format.
75
+
76
+ https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream/DecompressionStream
77
+
78
+ default: `"deflate-raw"`
79
+
80
+ type:
81
+ - `"deflate-raw"`
82
+ - `"deflate"`
83
+ - `"gzip"`
84
+ - `"brotli"`
85
+ - `"zstd"`
86
+ - `"deflateRaw"`
87
+ - `"gz"`
88
+ - `"br"`
89
+ - `"brotliCompress"`
90
+ - `"zstandard"`
91
+ - `"zst"`
92
+
93
+ ### compressor
94
+
95
+ Custom compressor.
96
+
97
+ type: `(buf: zlib.InputType) => (Buffer | Uint8Array | Promise<Buffer | Uint8Array>)`
98
+
99
+ ### htmlMinifierTerser
100
+
101
+ https://github.com/terser/html-minifier-terser?tab=readme-ov-file#options-quick-reference
102
+
103
+ default: `defaultHtmlMinifierTerserOptions`
104
+
105
+ type:
106
+ - `HtmlMinifierOptions`
107
+ - `boolean`
108
+
109
+ ### tryInlineHtmlAssets
110
+
111
+ Try inline html used assets, if inlined or not used in JS.
112
+
113
+ default: `true`
114
+
115
+ type: `boolean`
116
+
117
+ ### removeInlinedAssetFiles
118
+
119
+ Remove inlined asset files.
120
+
121
+ default: `true`
122
+
123
+ type: `boolean`
124
+
125
+ ### tryInlineHtmlPublicIcon
126
+
127
+ Try inline html icon, if icon is in public dir.
128
+
129
+ default: `true`
130
+
131
+ type: `boolean`
132
+
133
+ ### removeInlinedPublicIconFiles
134
+
135
+ Remove inlined html icon files.
136
+
137
+ default: `true`
138
+
139
+ type: `boolean`
140
+
141
+ ### useImportMetaPolyfill
142
+
143
+ Use import.meta polyfill.
144
+
145
+ default: `true`
146
+
147
+ type: `boolean`
47
148
 
48
- ```ts
49
- export interface Options {
50
- /**
51
- * Enable compress.
52
- * @default true
53
- */
54
- enableCompress?: boolean
55
-
56
- /**
57
- * Use Base128 to encode compressed script.
58
- * If false, use Base64.
59
- * https://www.npmjs.com/package/base128-ascii
60
- * @default true
61
- */
62
- useBase128?: boolean
63
-
64
- /**
65
- * Compress format.
66
- *
67
- * https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream/DecompressionStream
68
- *
69
- * @type {"deflate-raw" | "deflate" | "gzip" | "brotli" | "zstd" | "deflateRaw" | "gz" | "br" | "brotliCompress" | "zstandard" | "zst"}
70
- *
71
- * @default "deflate-raw"
72
- */
73
- compressFormat?: CompressFormat | CompressFormatAlias
74
-
75
- /**
76
- * Custom compressor.
77
- */
78
- compressor?: Compressor
79
-
80
- /**
81
- * Rename index.html
82
- */
83
- rename?: string
84
-
85
- /**
86
- * https://github.com/terser/html-minifier-terser?tab=readme-ov-file#options-quick-reference
87
- * @default defaultHtmlMinifierTerserOptions
88
- */
89
- htmlMinifierTerser?: HtmlMinifierOptions | boolean
90
-
91
- /**
92
- * Try inline html used assets, if inlined or not used in JS.
93
- * @default true
94
- */
95
- tryInlineHtmlAssets?: boolean
96
-
97
- /**
98
- * Remove inlined asset files.
99
- * @default true
100
- */
101
- removeInlinedAssetFiles?: boolean
102
-
103
- /**
104
- * Try inline html icon, if icon is in public dir.
105
- * @default true
106
- */
107
- tryInlineHtmlPublicIcon?: boolean
108
-
109
- /**
110
- * Remove inlined html icon files.
111
- * @default true
112
- */
113
- removeInlinedPublicIconFiles?: boolean
114
-
115
- /**
116
- * Use import.meta polyfill.
117
- * @default true
118
- */
119
- useImportMetaPolyfill?: boolean
120
- }
121
- ```
122
149
 
123
150
  ## Effect
124
151
 
125
152
  Preview: https://bddjr.github.io/vite-plugin-singlefile-compression/
126
153
 
127
154
  ```
128
- vite v8.0.0 building client environment for production...
155
+ vite v8.0.3 building client environment for production...
129
156
  ✓ 42 modules transformed.
130
157
  rendering chunks (1)...
131
158
 
132
- vite-plugin-singlefile-compression 2.1.1 deflate-raw base128-ascii
159
+ vite-plugin-singlefile-compression 2.2.0 deflate-raw base128-ascii
133
160
 
134
161
  file:///D:/code/js/vite-plugin-singlefile-compression/test/dist/index.html
135
- 124.013 kB -> 50.35 kB
162
+ 122.739 kB -> 50.220 kB
136
163
 
137
164
  Finish.
138
165
 
139
166
  computing gzip size...
140
- dist/index.html 50.35 kB │ gzip: 43.87 kB
167
+ dist/index.html 50.22 kB │ gzip: 43.77 kB
141
168
 
142
- ✓ built in 296ms
169
+ ✓ built in 317ms
143
170
  ```
144
171
 
145
- ![](effect.jpg)
146
-
147
172
  ## Clone
148
173
 
149
174
  ```
@@ -153,5 +178,5 @@ npm i
153
178
  cd test
154
179
  npm i
155
180
  cd ..
156
- node --run build
181
+ npm run build
157
182
  ```
package/dist/index.d.ts CHANGED
@@ -18,12 +18,16 @@ declare const compressFormatAlias: Readonly<{
18
18
  zstandard: "zstd";
19
19
  zst: "zstd";
20
20
  }>;
21
- type Compressor = ((buf: zlib.InputType) => (Buffer | Uint8Array));
22
- type CompressFormat = keyof typeof compressors;
21
+ type Compressor = ((buf: zlib.InputType) => (Buffer | Uint8Array | Promise<Buffer | Uint8Array>));
22
+ type CompressFormat = keyof typeof compressors | CompressionFormat;
23
23
  type CompressFormatAlias = keyof typeof compressFormatAlias;
24
24
  //#endregion
25
25
  //#region _dist/options.d.ts
26
26
  interface Options {
27
+ /**
28
+ * Rename index.html
29
+ */
30
+ rename?: string;
27
31
  /**
28
32
  * Enable compress.
29
33
  * @default true
@@ -50,10 +54,6 @@ interface Options {
50
54
  * Custom compressor.
51
55
  */
52
56
  compressor?: Compressor;
53
- /**
54
- * Rename index.html
55
- */
56
- rename?: string;
57
57
  /**
58
58
  * https://github.com/terser/html-minifier-terser?tab=readme-ov-file#options-quick-reference
59
59
  * @default defaultHtmlMinifierTerserOptions
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 mime from "mime";
11
11
  //#region _dist/getVersion.js
12
- var version = "2.1.1";
12
+ var version = "2.2.0";
13
13
  //#endregion
14
14
  //#region _dist/compress.js
15
15
  const compressors = {
@@ -46,11 +46,18 @@ function switchCompressor(format) {
46
46
  if (typeof f == "function") return f;
47
47
  }
48
48
  }
49
+ try {
50
+ const cs = new CompressionStream(format);
51
+ return (buf) => new Response(new ReadableStream({ start(controller) {
52
+ controller.enqueue(buf);
53
+ controller.close();
54
+ } }).pipeThrough(cs)).bytes();
55
+ } catch {}
49
56
  throw Error(`Could not get compressor: Unknown compress format '${format}', please set your compressor function.`);
50
57
  }
51
- function compress(format, buf, useBase128, compressor) {
58
+ async function compress(format, buf, useBase128, compressor) {
52
59
  if (typeof compressor != "function") compressor = switchCompressor(format);
53
- const outBuf = compressor(buf);
60
+ const outBuf = await compressor(buf);
54
61
  if (useBase128) return base128.encode(outBuf).toJSTemplateLiterals();
55
62
  if (Buffer.isBuffer(outBuf)) return outBuf.toString("base64");
56
63
  if (typeof outBuf.toBase64 == "function") return outBuf.toBase64();
@@ -60,7 +67,7 @@ function compress(format, buf, useBase128, compressor) {
60
67
  //#region _dist/templateRaw.js
61
68
  var raw = {
62
69
  "assets": "{let e={\"\":\"\"};for(let o in e)for(let s of document.querySelectorAll(`[src=\"data:${o}\"]`))s.src=e[o]}",
63
- "base128": "var a=\"<script>\",i=a.length,r=new Uint8Array(Math.floor(i/8*7)),c=0,o=0,e,t=()=>(e=a.charCodeAt(c++))>127?e=0:e;for(;c<i;)r[o++]=t()<<1|t()>>6,r[o++]=e<<2|t()>>5,r[o++]=e<<3|t()>>4,r[o++]=e<<4|t()>>3,r[o++]=e<<5|t()>>2,r[o++]=e<<6|t()>>1,r[o++]=e<<7|t();new Response(new Blob([r]).stream().pipeThrough(new DecompressionStream(\"<format>\")),{headers:{\"Content-Type\":\"text/javascript\"}}).blob().then(n=>(import(n=URL.createObjectURL(n)),URL.revokeObjectURL(n)))",
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)))",
64
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)))",
65
72
  "css": "document.head.appendChild(document.createElement(\"style\")).innerHTML=\"<style>\"",
66
73
  "icon": "document.querySelector(\"link[rel=icon]\").href=\"<icon>\"",
@@ -82,8 +89,8 @@ const files = {
82
89
  importmeta: split2(raw.importmeta, "\"<path>\"")
83
90
  };
84
91
  const template = {
85
- base(script, format, useBase128, compressor) {
86
- script = compress(format, script, useBase128, compressor);
92
+ async base(script, format, useBase128, compressor) {
93
+ script = await compress(format, script, useBase128, compressor);
87
94
  if (useBase128) return files.base128.replace("<format>", format).split("\"<script>\"", 2).join(script);
88
95
  return files.base64.replace("<format>", format).split("<script>", 2).join(script);
89
96
  },
@@ -108,7 +115,8 @@ function bufferToDataURL(name, b) {
108
115
  //#endregion
109
116
  //#region _dist/kB.js
110
117
  function kB(size) {
111
- return `${size / 1e3} kB`;
118
+ const s = String(size).padStart(4, "0");
119
+ return `${s.slice(0, -3)}.${s.slice(-3)} kB`;
112
120
  }
113
121
  //#endregion
114
122
  //#region _dist/options.js
@@ -123,16 +131,16 @@ const defaultHtmlMinifierTerserOptions = {
123
131
  function getInnerOptions(opt) {
124
132
  opt ||= {};
125
133
  return {
126
- enableCompress: opt.enableCompress ?? true,
127
134
  rename: opt.rename == null ? void 0 : String(opt.rename),
135
+ enableCompress: opt.enableCompress ?? true,
136
+ useBase128: opt.useBase128 ?? true,
137
+ compressFormat: opt.compressFormat ? compressFormatAlias.hasOwnProperty(opt.compressFormat) ? compressFormatAlias[opt.compressFormat] : String(opt.compressFormat) : "deflate-raw",
138
+ compressor: typeof opt.compressor == "function" ? opt.compressor : void 0,
128
139
  htmlMinifierTerser: opt.htmlMinifierTerser == null || opt.htmlMinifierTerser === true ? defaultHtmlMinifierTerserOptions : opt.htmlMinifierTerser,
129
140
  tryInlineHtmlAssets: opt.tryInlineHtmlAssets ?? true,
130
141
  removeInlinedAssetFiles: opt.removeInlinedAssetFiles ?? true,
131
142
  tryInlineHtmlPublicIcon: opt.tryInlineHtmlPublicIcon ?? true,
132
143
  removeInlinedPublicIconFiles: opt.removeInlinedPublicIconFiles ?? true,
133
- useBase128: opt.useBase128 ?? true,
134
- compressFormat: opt.compressFormat ? compressFormatAlias.hasOwnProperty(opt.compressFormat) ? compressFormatAlias[opt.compressFormat] : String(opt.compressFormat) : "deflate-raw",
135
- compressor: typeof opt.compressor == "function" ? opt.compressor : void 0,
136
144
  useImportMetaPolyfill: opt.useImportMetaPolyfill ?? true
137
145
  };
138
146
  }
@@ -147,7 +155,7 @@ function singleFileCompression(opt) {
147
155
  let conf;
148
156
  const innerOptions = getInnerOptions(opt);
149
157
  return {
150
- name: "singleFileCompression",
158
+ name: "vite-plugin-singlefile-compression",
151
159
  enforce: "post",
152
160
  config(...args) {
153
161
  return setConfig.call(this, innerOptions, ...args);
@@ -155,8 +163,8 @@ function singleFileCompression(opt) {
155
163
  configResolved(c) {
156
164
  conf = c;
157
165
  },
158
- generateBundle(outputOptions, bundle) {
159
- return generateBundle(bundle, conf, innerOptions);
166
+ generateBundle(outputOptions, bundle, isWrite) {
167
+ return generateBundle.call(this, bundle, conf, innerOptions);
160
168
  }
161
169
  };
162
170
  }
@@ -175,7 +183,7 @@ function setConfig(opt, config, env) {
175
183
  }
176
184
  }
177
185
  async function generateBundle(bundle, config, options) {
178
- console.log(pc.reset("\n\n") + pc.cyan("vite-plugin-singlefile-compression " + version) + " " + (options.enableCompress ? pc.green(options.compressFormat + " " + (options.useBase128 ? "base128-ascii" : "base64")) : pc.red("disable compress")));
186
+ console.log(pc.reset("\n\n") + pc.cyan("vite-plugin-singlefile-compression " + version) + " " + (options.enableCompress ? pc.green(options.compressFormat + " " + (options.useBase128 ? "base128-ascii" : "base64")) : pc.red("disable-compress")));
179
187
  if (options.rename && options.rename != "index.html" && Object.prototype.hasOwnProperty.call(bundle, "index.html") && !Object.prototype.hasOwnProperty.call(bundle, options.rename)) {
180
188
  bundle[options.rename] = bundle["index.html"];
181
189
  bundle[options.rename].fileName = options.rename;
@@ -297,7 +305,7 @@ async function generateBundle(bundle, config, options) {
297
305
  newJSCode.push(code);
298
306
  } else inlineHtmlAssets();
299
307
  let outputScript = newJSCode.join(";");
300
- if (options.enableCompress) outputScript = template.base(outputScript, options.compressFormat, options.useBase128, options.compressor);
308
+ if (options.enableCompress) outputScript = await template.base(outputScript, options.compressFormat, options.useBase128, options.compressor);
301
309
  else outputScript = outputScript.replaceAll("<\/script", "<\\/script");
302
310
  htmlChunk.source = htmlChunk.source.split(fakeScript, 2).join(outputScript);
303
311
  console.log(" " + pc.gray(kB(oldSize) + " -> ") + pc.cyanBright(kB(htmlChunk.source.length)) + "\n");
@@ -307,7 +315,7 @@ async function generateBundle(bundle, config, options) {
307
315
  for (const name of globalDelete) if (!globalDoNotDelete.has(name)) delete bundle[name];
308
316
  }
309
317
  if (options.removeInlinedPublicIconFiles) for (const name of globalRemoveDistFileNames) try {
310
- fs.unlinkSync(path.join(config.build.outDir, name));
318
+ fs.rmSync(path.join(config.build.outDir, name), { force: true });
311
319
  } catch (e) {
312
320
  console.error(e);
313
321
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-singlefile-compression",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
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.",
@@ -48,19 +48,20 @@
48
48
  ],
49
49
  "dependencies": {
50
50
  "@types/html-minifier-terser": ">=7.0.2",
51
+ "@types/node": "*",
51
52
  "base128-ascii": ">=2.1.11",
52
53
  "html-minifier-terser": ">=7.2.0",
53
54
  "jsdom": ">=28.1.0",
54
55
  "mime": ">=4.1.0",
55
56
  "mini-svg-data-uri": ">=1.4.4",
56
- "picocolors": ">=1.1.1"
57
+ "picocolors": ">=1.1.1",
58
+ "vite": ">=3.0.0"
57
59
  },
58
60
  "devDependencies": {
61
+ "@bddjr/rimraf": "^0.1.0",
59
62
  "@types/jsdom": ">=28.0.0",
60
63
  "@types/node": "^22.19.15",
61
64
  "esbuild": "^0.27.4",
62
- "marked": "^17.0.4",
63
- "rimraf": ">=6.1.3",
64
65
  "rolldown": ">=1.0.0-rc.9",
65
66
  "rolldown-plugin-dts": "^0.22.5",
66
67
  "rollup": ">=4.59.0",