Skip to content

Commit 6e16b68

Browse files
authored
Merge pull request #109 from z0ffy/feature/compare-output-size
* feat: add code size analyzer
2 parents 60fea4e + b505f6d commit 6e16b68

File tree

4 files changed

+114
-9
lines changed

4 files changed

+114
-9
lines changed

src/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { IndexHtmlTransformHook, PluginOption, Rollup } from 'vite';
22
import { Config, ViteConfigFn } from './type';
33
import {
4+
CodeSizeAnalyzer,
45
createWorkerTask,
5-
formatTime,
66
getChunkName,
77
getManualChunks,
88
getThreadPoolSize,
@@ -70,9 +70,10 @@ export default function viteBundleObfuscator(config?: Partial<Config>): PluginOp
7070
const transformIndexHtmlHandler: IndexHtmlTransformHook = async (html, { bundle }) => {
7171
if (!finalConfig.enable || !bundle) return html;
7272

73-
_log.forceLog('starting obfuscation process...');
74-
const now = performance.now();
73+
_log.forceLog(LOG_COLOR.info + '\nstarting obfuscation process...');
74+
const analyzer = new CodeSizeAnalyzer(_log);
7575
const bundleList = getValidBundleList(finalConfig, bundle);
76+
analyzer.start(bundleList);
7677

7778
if (isEnableThreadPool(finalConfig)) {
7879
const poolSize = Math.min(getThreadPoolSize(finalConfig), bundleList.length);
@@ -91,8 +92,7 @@ export default function viteBundleObfuscator(config?: Partial<Config>): PluginOp
9192
});
9293
}
9394

94-
const consume = formatTime(performance.now() - now);
95-
_log.forceLog(LOG_COLOR.info + '%s\x1b[0m %s', '✓', `obfuscation process completed in ${consume}.`);
95+
analyzer.end(bundleList);
9696

9797
return html;
9898
};

src/type.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { ObfuscatorOptions } from 'javascript-obfuscator';
22
import type { Plugin, Rollup } from 'vite';
3+
import { SizeUnit } from './utils/constants';
34

45
export type ViteConfigFn = Plugin['config'];
56

@@ -10,6 +11,13 @@ export interface WorkerMessage {
1011
chunk: BundleList;
1112
}
1213

14+
export type SizeResult = { original: FormatSizeResult; gzip: FormatSizeResult };
15+
16+
export interface FormatSizeResult {
17+
value: number;
18+
unit: SizeUnit;
19+
}
20+
1321
export interface ObfuscationResult {
1422
fileName: string;
1523
obfuscatedCode: string;

src/utils/constants.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,14 @@ export const VENDOR_MODULES = 'vendor-modules';
4444

4545
export const CHUNK_PREFIX = 'vendor-';
4646

47+
export enum SizeUnit {
48+
B = 'B',
49+
KB = 'KB',
50+
MB = 'MB',
51+
}
52+
4753
export const LOG_COLOR = Object.freeze({
4854
info: '\x1b[36m', // Cyan
4955
warn: '\x1b[33m', // Yellow
56+
success: '\x1b[32m', // Green
5057
});

src/utils/index.ts

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import * as vite from 'vite';
22
import { Rollup } from 'vite';
3-
import { BundleList, Config, ObfuscationResult } from '../type';
4-
import os from 'node:os';
5-
import { isBoolean, isFileNameExcluded, isObject } from './is';
63
import { Worker } from 'node:worker_threads';
74
import path from 'node:path';
5+
import os from 'node:os';
6+
import { gzipSync } from 'node:zlib';
87
import javascriptObfuscator from 'javascript-obfuscator';
9-
import { CHUNK_PREFIX, VENDOR_MODULES } from './constants';
8+
9+
import type { BundleList, Config, FormatSizeResult, ObfuscationResult, SizeResult } from '../type';
10+
import { isBoolean, isFileNameExcluded, isObject } from './is';
11+
import { CHUNK_PREFIX, LOG_COLOR, SizeUnit, VENDOR_MODULES } from './constants';
1012

1113
export class Log {
1214
private readonly _log: (msg: string) => void;
@@ -133,3 +135,91 @@ export function createWorkerTask(finalConfig: Config, chunk: BundleList) {
133135
});
134136
});
135137
}
138+
139+
export function formatSize(bytes: number): FormatSizeResult {
140+
const units = Object.values(SizeUnit);
141+
let i = 0;
142+
while (bytes >= 1024 && i < units.length - 1) {
143+
bytes /= 1024;
144+
i++;
145+
}
146+
return {
147+
value: Number(bytes.toFixed(2)),
148+
unit: units[i],
149+
};
150+
}
151+
152+
export class CodeSizeAnalyzer {
153+
private _log;
154+
private originalSize: SizeResult;
155+
private obfuscatedSize: SizeResult;
156+
private startTime: number;
157+
private endTime: number;
158+
159+
constructor(log: Log) {
160+
this._log = log;
161+
this.originalSize = this.createEmptySizeResult();
162+
this.obfuscatedSize = this.createEmptySizeResult();
163+
this.startTime = 0;
164+
this.endTime = 0;
165+
}
166+
167+
private createEmptySizeResult(): SizeResult {
168+
return {
169+
original: { value: 0, unit: SizeUnit.B },
170+
gzip: { value: 0, unit: SizeUnit.B },
171+
};
172+
}
173+
174+
start(originalBundleList: BundleList): void {
175+
this.startTime = performance.now();
176+
this.originalSize = this.calculateBundleSize(originalBundleList);
177+
}
178+
179+
end(obfuscatedBundleList: BundleList): void {
180+
this.obfuscatedSize = this.calculateBundleSize(obfuscatedBundleList);
181+
this.endTime = performance.now();
182+
this.logResult();
183+
}
184+
185+
private calculateBundleSize(bundleList: BundleList): { original: FormatSizeResult; gzip: FormatSizeResult } {
186+
const { totalSize, gzipSize } = bundleList.reduce(
187+
(acc, [, bundleItem]) => {
188+
if (bundleItem.code) {
189+
const { code } = bundleItem;
190+
acc.totalSize += Buffer.byteLength(code, 'utf-8');
191+
acc.gzipSize += gzipSync(code, { level: 9 }).byteLength;
192+
}
193+
return acc;
194+
},
195+
{ totalSize: 0, gzipSize: 0 },
196+
);
197+
198+
return {
199+
original: formatSize(totalSize),
200+
gzip: formatSize(gzipSize),
201+
};
202+
}
203+
204+
private analyze(): string {
205+
const { originalSize, obfuscatedSize } = this;
206+
207+
const consume = formatTime(this.endTime - this.startTime);
208+
209+
const percentageIncrease = (
210+
((obfuscatedSize.original.value - originalSize.original.value) / originalSize.original.value)
211+
* 100
212+
).toFixed(2);
213+
214+
const gzipPercentageIncrease = (
215+
((obfuscatedSize.gzip.value - originalSize.gzip.value) / originalSize.gzip.value)
216+
* 100
217+
).toFixed(2);
218+
219+
return `✓ obfuscated in ${consume} | 📦 ${originalSize.original.value}${originalSize.original.unit} (gzip: ${originalSize.gzip.value}${originalSize.gzip.unit}) → 🔒 ${obfuscatedSize.original.value}${obfuscatedSize.original.unit} (gzip: ${obfuscatedSize.gzip.value}${obfuscatedSize.gzip.unit}) | 📈 ${percentageIncrease}% (gzip: ${gzipPercentageIncrease}%)`;
220+
}
221+
222+
private logResult(): void {
223+
this._log.forceLog(LOG_COLOR.success + '%s\x1b[0m', this.analyze());
224+
}
225+
}

0 commit comments

Comments
 (0)