vite-plugin-singlefile-compression 1.0.2 → 1.0.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 +30 -16
- package/dist/index.d.ts +10 -1
- package/dist/index.js +42 -19
- package/dist/template-assets.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -33,6 +33,20 @@ export default defineConfig({
|
|
|
33
33
|
// Add singleFileCompression
|
|
34
34
|
singleFileCompression(),
|
|
35
35
|
],
|
|
36
|
+
esbuild: {
|
|
37
|
+
// Remove license comments
|
|
38
|
+
legalComments: "none"
|
|
39
|
+
},
|
|
40
|
+
build: {
|
|
41
|
+
terserOptions: {
|
|
42
|
+
format: {
|
|
43
|
+
// Remove license comments
|
|
44
|
+
comments: false
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
target: 'esnext',
|
|
48
|
+
reportCompressedSize: false
|
|
49
|
+
},
|
|
36
50
|
```
|
|
37
51
|
|
|
38
52
|
Then modify [src/router/index.ts](test/src/router/index.ts#L5) , change `createWebHistory` to `createWebHashHistory`
|
|
@@ -42,6 +56,18 @@ const router = createRouter({
|
|
|
42
56
|
history: createWebHashHistory(),
|
|
43
57
|
```
|
|
44
58
|
|
|
59
|
+
## Options
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
export interface Options {
|
|
63
|
+
/**
|
|
64
|
+
* https://github.com/terser/html-minifier-terser?tab=readme-ov-file#options-quick-reference
|
|
65
|
+
* @default defaultHtmlMinifierTerserOptions
|
|
66
|
+
*/
|
|
67
|
+
htmlMinifierTerser?: htmlMinifierOptions | true | false
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
45
71
|
## Effect
|
|
46
72
|
|
|
47
73
|
```
|
|
@@ -52,28 +78,16 @@ rendering chunks (1)...
|
|
|
52
78
|
vite-plugin-singlefile-compression building...
|
|
53
79
|
|
|
54
80
|
file:///D:/bddjr/Desktop/code/js/vite-plugin-singlefile-compression/test/dist/index.html
|
|
55
|
-
97.
|
|
81
|
+
97.52 KiB -> 50.98 KiB
|
|
56
82
|
|
|
57
83
|
Finish.
|
|
58
84
|
|
|
59
|
-
dist/index.html 52.
|
|
60
|
-
✓ built in
|
|
85
|
+
dist/index.html 52.19 kB
|
|
86
|
+
✓ built in 685ms
|
|
61
87
|
```
|
|
62
88
|
|
|
63
89
|
```html
|
|
64
|
-
<!DOCTYPE html>
|
|
65
|
-
<html>
|
|
66
|
-
<head>
|
|
67
|
-
<meta charset="UTF-8">
|
|
68
|
-
<link rel="icon" href="data:logo-_cUAdIX-.svg">
|
|
69
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
70
|
-
<title>Vite App</title>
|
|
71
|
-
<script type="module">fetch("data:application/gzip;base64,H4sI******AQA=").then(r=>r.blob()).then(b=>new Response(b.stream().pipeThrough(new DecompressionStream("gzip")),{headers:{"Content-Type":"text/javascript"}}).blob()).then(b=>import(b=URL.createObjectURL(b)).finally(()=>URL.revokeObjectURL(b)))</script>
|
|
72
|
-
</head>
|
|
73
|
-
<body>
|
|
74
|
-
<div id="app"></div>
|
|
75
|
-
</body>
|
|
76
|
-
</html>
|
|
90
|
+
<!DOCTYPE html><meta charset=UTF-8><link rel=icon href=data:logo-_cUAdIX-.svg><meta name=viewport content="width=device-width,initial-scale=1"><title>Vite App</title><script type=module>fetch("data:application/gzip;base64,H4sI********hAEA").then(r=>r.blob()).then(b=>new Response(b.stream().pipeThrough(new DecompressionStream("gzip")),{headers:{"Content-Type":"text/javascript"}}).blob()).then(b=>import(b=URL.createObjectURL(b)).finally(()=>URL.revokeObjectURL(b)))</script><div id=app></div>
|
|
77
91
|
```
|
|
78
92
|
|
|
79
93
|
## Clone
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import { PluginOption } from "vite";
|
|
2
|
-
|
|
2
|
+
import { Options as htmlMinifierOptions } from 'html-minifier-terser';
|
|
3
|
+
export interface Options {
|
|
4
|
+
/**
|
|
5
|
+
* https://github.com/terser/html-minifier-terser?tab=readme-ov-file#options-quick-reference
|
|
6
|
+
* @default defaultHtmlMinifierTerserOptions
|
|
7
|
+
*/
|
|
8
|
+
htmlMinifierTerser?: htmlMinifierOptions | boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const defaultHtmlMinifierTerserOptions: htmlMinifierOptions;
|
|
11
|
+
export declare function singleFileCompression(options?: Options): PluginOption;
|
|
3
12
|
export default singleFileCompression;
|
package/dist/index.js
CHANGED
|
@@ -1,28 +1,47 @@
|
|
|
1
1
|
import mime from 'mime';
|
|
2
2
|
import pc from "picocolors";
|
|
3
3
|
import svgToTinyDataUri from "mini-svg-data-uri";
|
|
4
|
+
import { minify as htmlMinify } from 'html-minifier-terser';
|
|
4
5
|
import zlib from 'zlib';
|
|
5
6
|
import path from 'path';
|
|
6
7
|
import fs from 'fs';
|
|
7
|
-
|
|
8
|
+
import { pathToFileURL } from "url";
|
|
9
|
+
export const defaultHtmlMinifierTerserOptions = {
|
|
10
|
+
removeAttributeQuotes: true,
|
|
11
|
+
removeComments: true,
|
|
12
|
+
collapseWhitespace: true,
|
|
13
|
+
removeOptionalTags: true,
|
|
14
|
+
removeRedundantAttributes: true,
|
|
15
|
+
minifyJS: false,
|
|
16
|
+
};
|
|
17
|
+
export function singleFileCompression(options) {
|
|
18
|
+
const htmlMinifierOptions = options?.htmlMinifierTerser == null || options.htmlMinifierTerser === true
|
|
19
|
+
? defaultHtmlMinifierTerserOptions
|
|
20
|
+
: options.htmlMinifierTerser;
|
|
8
21
|
return {
|
|
9
|
-
name: "
|
|
22
|
+
name: "singleFileCompression",
|
|
10
23
|
enforce: "post",
|
|
11
24
|
config: setConfig,
|
|
12
|
-
generateBundle,
|
|
25
|
+
generateBundle: (_, bundle) => generateBundle(bundle, htmlMinifierOptions),
|
|
13
26
|
};
|
|
14
27
|
}
|
|
15
28
|
export default singleFileCompression;
|
|
16
29
|
const template = fs.readFileSync(path.join(import.meta.dirname, "template.js")).toString();
|
|
17
30
|
const templateAssets = fs.readFileSync(path.join(import.meta.dirname, "template-assets.js")).toString();
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
const distURL = pathToFileURL(path.resolve("dist")) + "/";
|
|
32
|
+
function gzipToBase64(buf) {
|
|
33
|
+
return zlib.gzipSync(buf, {
|
|
34
|
+
level: zlib.constants.Z_BEST_COMPRESSION,
|
|
35
|
+
}).toString('base64');
|
|
36
|
+
}
|
|
37
|
+
function KiB(size) {
|
|
38
|
+
return `${Math.ceil(size / 10.24) / 100} KiB`;
|
|
39
|
+
}
|
|
21
40
|
function setConfig(config) {
|
|
22
41
|
config.base = './';
|
|
23
42
|
if (!config.build)
|
|
24
43
|
config.build = {};
|
|
25
|
-
config.build.assetsInlineLimit =
|
|
44
|
+
config.build.assetsInlineLimit = () => true;
|
|
26
45
|
config.build.chunkSizeWarningLimit = Infinity;
|
|
27
46
|
config.build.cssCodeSplit = false;
|
|
28
47
|
config.build.assetsDir = 'assets';
|
|
@@ -31,17 +50,10 @@ function setConfig(config) {
|
|
|
31
50
|
config.build.rollupOptions = {};
|
|
32
51
|
config.build.rollupOptions.output = { inlineDynamicImports: true };
|
|
33
52
|
}
|
|
34
|
-
function
|
|
35
|
-
return zlib.gzipSync(buf, {
|
|
36
|
-
level: zlib.constants.Z_BEST_COMPRESSION,
|
|
37
|
-
}).toString('base64');
|
|
38
|
-
}
|
|
39
|
-
function KiB(size) {
|
|
40
|
-
return `${Math.ceil(size / 10.24) / 100} KiB`;
|
|
41
|
-
}
|
|
42
|
-
function generateBundle(_, bundle) {
|
|
53
|
+
async function generateBundle(bundle, htmlMinifierOptions) {
|
|
43
54
|
console.log(pc.cyan('\n\nvite-plugin-singlefile-compression ') + pc.green('building...'));
|
|
44
55
|
const globalDel = new Set();
|
|
56
|
+
const globalDoNotDel = new Set();
|
|
45
57
|
for (const htmlFileName of Object.keys(bundle)) {
|
|
46
58
|
// key format:
|
|
47
59
|
// index.html
|
|
@@ -54,7 +66,7 @@ function generateBundle(_, bundle) {
|
|
|
54
66
|
let newHtml = htmlChunk.source;
|
|
55
67
|
let oldSize = newHtml.length;
|
|
56
68
|
const thisDel = new Set();
|
|
57
|
-
// Fix async import
|
|
69
|
+
// Fix async import, fix new URL
|
|
58
70
|
const newJSCode = ["self.__VITE_PRELOAD__=void 0"];
|
|
59
71
|
// get css tag
|
|
60
72
|
newHtml = newHtml.replace(/\s*<link rel="stylesheet"[^>]* href="\.\/(assets\/[^"]+)"[^>]*>/, (match, name) => {
|
|
@@ -100,6 +112,14 @@ function generateBundle(_, bundle) {
|
|
|
100
112
|
thisDel.add(name);
|
|
101
113
|
const js = bundle[name];
|
|
102
114
|
oldSize += js.code.length;
|
|
115
|
+
// fix new URL
|
|
116
|
+
newJSCode.push(`import.meta.url=location.origin+location.pathname.replace(/[^/]*$/,"${name}")`);
|
|
117
|
+
for (const name in assets) {
|
|
118
|
+
// name: logo-XXXXXXXX.svg
|
|
119
|
+
if (js.code.includes(name))
|
|
120
|
+
globalDoNotDel.add("assets/" + name);
|
|
121
|
+
}
|
|
122
|
+
// add script
|
|
103
123
|
newJSCode.push(js.code.replace(/;?\n?$/, ''));
|
|
104
124
|
// gzip
|
|
105
125
|
return '<script type="module">'
|
|
@@ -108,10 +128,12 @@ function generateBundle(_, bundle) {
|
|
|
108
128
|
});
|
|
109
129
|
if (!ok)
|
|
110
130
|
continue;
|
|
131
|
+
if (htmlMinifierOptions)
|
|
132
|
+
newHtml = await htmlMinify(newHtml, htmlMinifierOptions);
|
|
111
133
|
// finish
|
|
112
134
|
htmlChunk.source = newHtml;
|
|
113
135
|
console.log("\n"
|
|
114
|
-
+ " " + pc.underline(pc.cyan(
|
|
136
|
+
+ " " + pc.underline(pc.cyan(distURL) + pc.greenBright(htmlFileName)) + '\n'
|
|
115
137
|
+ " " + pc.gray(KiB(oldSize) + " -> ") + pc.cyanBright(KiB(newHtml.length)) + '\n');
|
|
116
138
|
// delete assets
|
|
117
139
|
for (const name of thisDel) {
|
|
@@ -120,7 +142,8 @@ function generateBundle(_, bundle) {
|
|
|
120
142
|
}
|
|
121
143
|
// delete inlined assets
|
|
122
144
|
for (const name of globalDel) {
|
|
123
|
-
|
|
145
|
+
if (!globalDoNotDel.has(name))
|
|
146
|
+
delete bundle[name];
|
|
124
147
|
}
|
|
125
148
|
console.log(pc.green('Finish.\n'));
|
|
126
149
|
}
|
package/dist/template-assets.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{const a={"":""};for(const n in a){for(const e of document.querySelectorAll(`[src="data:${n}"]`))
|
|
1
|
+
{const a={"":""};for(const n in a){for(const e of document.querySelectorAll(`[src="data:${n}"]`))e.src=a[n];for(const e of document.querySelectorAll(`[href="data:${n}"]`))e.href=a[n]}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-singlefile-compression",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -38,15 +38,15 @@
|
|
|
38
38
|
"css"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
+
"@types/html-minifier-terser": "^7.0.2",
|
|
42
|
+
"@types/node": "^22.9.3",
|
|
41
43
|
"esbuild": "^0.24.0",
|
|
44
|
+
"html-minifier-terser": "^7.2.0",
|
|
42
45
|
"mime": "^4.0.4",
|
|
43
46
|
"mini-svg-data-uri": "^1.4.4",
|
|
44
47
|
"picocolors": "^1.1.1",
|
|
45
48
|
"rimraf": "^6.0.1",
|
|
46
49
|
"typescript": "^5.7.2",
|
|
47
50
|
"vite": "^5.4.11"
|
|
48
|
-
},
|
|
49
|
-
"devDependencies": {
|
|
50
|
-
"@types/node": "^22.9.3"
|
|
51
51
|
}
|
|
52
52
|
}
|