-
Notifications
You must be signed in to change notification settings - Fork 6
/
size.mjs
110 lines (95 loc) · 2.86 KB
/
size.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { minify, transform } from "@swc/core";
import { readFile } from "fs/promises";
import watcher from "@parcel/watcher";
import { relative } from "path";
import { createBrotliCompress, constants } from "node:zlib";
import { Readable } from "stream";
import bytes from "bytes-iec";
import picocolors from "picocolors";
const { blue, green, gray, red } = picocolors;
const srcPath = relative(process.cwd(), process.argv[2]);
const watch = !!process.argv.find((arg) => arg === "--watch");
const debouncedMeasure = debounce(measure, 50);
measure();
if (watch)
watcher.subscribe(process.cwd(), (error, events) => {
if (error) {
console.error("The filesystem watcher encountered an error:");
console.error(error);
process.exit(1);
}
events.forEach((event) => {
if (event.type !== "create" && event.type !== "update") return;
const path = relative(process.cwd(), event.path);
if (srcPath !== path) return;
debouncedMeasure();
});
});
let lastLength;
let lastSize;
async function measure() {
const code = await readFile(srcPath, "utf-8");
const processedCode = srcPath.endsWith(".ts")
? await transform(code, {
jsc: { target: "esnext", parser: { syntax: "typescript" } },
})
: code;
minify(processedCode, {
compress: true,
mangle: true,
sourceMap: false,
module: true,
})
.then(({ code }) => Promise.all([code, measureSize(code)]).then([code]))
.then(([code, size]) => {
if (code.length === lastLength && size === lastSize) return;
watch && console.clear();
console.log(`Last write: ${blue(new Date().toString())}`);
console.log("");
console.log("Source code:");
console.log("");
console.log(gray(code));
console.log("");
console.log(
`Length: ${blue(code.length)} ${formatDiff(code.length - lastLength)}`
);
console.log("");
console.log(
`Size: ${blue(bytes(size, { decimalPlaces: 3 }))} ${formatDiff(
size - lastSize
)}`
);
console.log("");
lastLength = code.length;
lastSize = size;
});
}
function formatDiff(diff) {
if (!diff) return "";
return diff > 0 ? red(`+${diff}`) : green(diff);
}
function measureSize(code) {
return new Promise((resolve, reject) => {
let size = 0;
const stream = new Readable();
stream.push(code);
stream.push(null);
let pipe = stream.pipe(
createBrotliCompress({
params: {
[constants.BROTLI_PARAM_QUALITY]: 11, // Use maximum compression quality
},
})
);
pipe.on("error", reject);
pipe.on("data", (buf) => (size += buf.length));
pipe.on("end", () => resolve(size));
});
}
function debounce(func, waitFor) {
let timeout;
return (...args) => {
if (timeout !== null) clearTimeout(timeout);
timeout = setTimeout(() => func(...args), waitFor);
};
}