diff --git a/crates/oxc_mangler/src/lib.rs b/crates/oxc_mangler/src/lib.rs index 38e4e28c7f2b5..2ba45c40374cb 100644 --- a/crates/oxc_mangler/src/lib.rs +++ b/crates/oxc_mangler/src/lib.rs @@ -424,8 +424,32 @@ fn is_keyword(s: &str) -> bool { #[repr(C, align(64))] struct Aligned64([u8; 64]); +/// The characters are in frequency order, so that the characters with higher frequency are used first. +/// +/// This idea was inspired by nanoid. +/// +/// This list was generated by the following steps: +/// 1. Generate a source code with replacing all manglable variable names with `$` (assuming `$` is the least used character). +/// You can do this by passing the following `blank` function to the `generate_name` parameter of [Mangler::build_with_symbols_and_scopes_impl]. +/// ```no_run +/// fn blank(_: usize) -> InlineString<12> { +/// let mut str = InlineString::new(); +/// unsafe { str.push_unchecked(b"$"[0]); } +/// str +/// } +/// ``` +/// 2. Run the following command in `target/minifier/default` to check generate the list: +/// ```shell +/// find . -type f -exec cat {} + | `# concat all files in that directory` \ +/// tr -d '\n' | fold -w1 | `# separate each characters in to each line` \ +/// grep -E '[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789]' | `# filter the character` \ +/// sort | uniq -c | `# count each characters` \ +/// sort -nr | awk '{print $2}' | tr -d '\n' `# format output` +/// ``` +/// The result I got is `etnriaoscludfpmhg_10vy2436b8x579SCwTEDOkAjMNPFILRzBVHUWGKqJYXZQ`. +/// 3. Add `$` at the end and then move all numbers to the end of the list. const BASE54_CHARS: Aligned64 = - Aligned64(*b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"); + Aligned64(*b"etnriaoscludfpmhg_vybxSCwTEDOkAjMNPFILRzBVHUWGKqJYXZQ$1024368579"); /// Get the shortest mangled name for a given n. /// Code adapted from [terser](https://github.com/terser/terser/blob/8b966d687395ab493d2c6286cc9dd38650324c11/lib/scope.js#L1041-L1051) diff --git a/crates/oxc_minifier/tests/mangler/snapshots/mangler.snap b/crates/oxc_minifier/tests/mangler/snapshots/mangler.snap index 3cc8414ab9a3d..85ab853cc83aa 100644 --- a/crates/oxc_minifier/tests/mangler/snapshots/mangler.snap +++ b/crates/oxc_minifier/tests/mangler/snapshots/mangler.snap @@ -2,23 +2,23 @@ source: crates/oxc_minifier/tests/mangler/mod.rs --- function foo(a) {a} -function foo(a) { - a; +function foo(e) { + e; } function foo(a) { let _ = { x } } -function foo(a) { - let b = { x }; +function foo(e) { + let t = { x }; } function foo(a) { let { x } = y } -function foo(a) { - let { x: b } = y; +function foo(e) { + let { x: t } = y; } var x; function foo(a) { ({ x } = y) } var x; -function foo(b) { +function foo(t) { ({x} = y); } @@ -32,165 +32,165 @@ function _(exports) { } function foo(foo_a, foo_b, foo_c) {}; function bar(bar_a, bar_b, bar_c) {} -function foo(a, b, c) {} +function foo(e, t, n) {} ; -function bar(a, b, c) {} +function bar(e, t, n) {} function _() { function foo() { var x; foo; } } function _() { - function a() { - var b; - a; + function e() { + var t; + e; } } function _() { var x; function foo() { var y; function bar() { x } } } function _() { - var a; - function b() { - var b; - function c() { - a; + var e; + function t() { + var t; + function n() { + e; } } } function _() { function x(a) {} } function _() { - function a(a) {} + function e(e) {} } function _() { function x(a) { x } } function _() { - function a(b) { - a; + function e(t) { + e; } } function _() { var x; { var y }} function _() { - var a; + var e; { - var b; + var t; } } function _() { var x; { let y }} function _() { - var a; + var e; { - let a; + let e; } } function _() { let x; { let y }} function _() { - let a; + let e; { - let a; + let e; } } function _() { var x; { const y }} function _() { - var a; + var e; { - const a; + const e; } } function _() { let x; { const y }} function _() { - let a; + let e; { - const a; + const e; } } function _() { var x; { class Y{} }} function _() { - var a; + var e; { - class a {} + class e {} } } function _() { let x; { class Y{} }} function _() { - let a; + let e; { - class a {} + class e {} } } function _() { var x; try { throw 0 } catch (e) { e } } function _() { - var a; + var e; try { throw 0; - } catch (a) { - a; + } catch (e) { + e; } } function _() { var x; try { throw 0 } catch (e) { var e } } function _() { - var a; + var e; try { throw 0; - } catch (b) { - var b; + } catch (t) { + var t; } } function _() { var x; try { throw 0 } catch { var e } } function _() { - var a; + var e; try { throw 0; } catch { - var b; + var t; } } function _() { var x; var y; } function _() { - var a; - var b; + var e; + var t; } function _() { var x; let y; } function _() { - var a; - let b; + var e; + let t; } function _() { { var x; var y; } } function _() { { - var a; - var b; + var e; + var t; } } function _() { { var x; let y; } } function _() { { - var a; - let b; + var e; + let t; } } function _() { let a; { let b; { let c; { let d; var x; } } } } function _() { - let a; + let e; { - let a; + let e; { - let a; + let e; { - let a; - var b; + let e; + var t; } } } @@ -198,23 +198,23 @@ function _() { function _() { let a; { let b; { let c; { console.log(a); let d; var x; } } } } function _() { - let a; + let e; { - let c; + let n; { - let c; + let n; { - console.log(a); - let c; - var b; + console.log(e); + let n; + var t; } } } } function foo(a) {a} -function a(a) { - a; +function e(e) { + e; } export function foo() {}; foo() @@ -223,15 +223,15 @@ export function foo() {} foo(); export default function foo() {}; foo() -export default function a() {} +export default function e() {} ; -a(); +e(); export const foo = 1; foo export const foo = 1; foo; const foo = 1; foo; export { foo } -const a = 1; -a; -export { a as foo }; +const e = 1; +e; +export { e as foo }; diff --git a/napi/minify/test/minify.test.ts b/napi/minify/test/minify.test.ts index 3841d0c5dba05..d09e8f54c0f1f 100644 --- a/napi/minify/test/minify.test.ts +++ b/napi/minify/test/minify.test.ts @@ -8,7 +8,7 @@ describe('simple', () => { it('matches output', () => { const ret = minify('test.js', code, { sourcemap: true }); expect(ret).toStrictEqual({ - 'code': 'function foo(){var a;a(void 0)}foo();', + 'code': 'function foo(){var e;e(void 0)}foo();', 'map': { 'mappings': 'AAAA,SAAS,KAAM,CAAE,IAAIA,EAAK,SAAc,AAAE,CAAC,KAAK', 'names': [ diff --git a/napi/minify/test/terser.test.ts b/napi/minify/test/terser.test.ts index 4b27910500e08..e447e3332185a 100644 --- a/napi/minify/test/terser.test.ts +++ b/napi/minify/test/terser.test.ts @@ -24,13 +24,16 @@ import { run_code } from './sandbox'; function run(input: string, expected: string[], prepend_code?: string) { const consoleMock = vi.spyOn(console, 'log').mockImplementation(() => undefined); - const minified = minify('test.mjs', input).code; - expect(minified).not.toBeFalsy(); - // Use `consoleMock` instead of the returned output. - const _ = run_code(minified, prepend_code); - const calls = consoleMock.mock.calls.map((args) => args.map(convert).join(' ')); - expect(calls).toStrictEqual(expected); - consoleMock.mockReset(); + try { + const minified = minify('test.mjs', input).code; + expect(minified).not.toBeFalsy(); + // Use `consoleMock` instead of the returned output. + const _ = run_code(minified, prepend_code); + const calls = consoleMock.mock.calls.map((args) => args.map(convert).join(' ')); + expect(calls).toStrictEqual(expected); + } finally { + consoleMock.mockReset(); + } } function convert(arg: any) { @@ -4451,7 +4454,8 @@ test('issue_1922_1', () => { run(code, expected); }); -test('issue_1922_2', () => { +// TODO: mangler does not support eval yet +test('issue_1922_2', { todo: true }, () => { const code = 'console.log(function(){var a;eval("a = 1");return a}(1));'; const expected = ['1']; run(code, expected); diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index 1154b4e11d03f..47ed2f45096e9 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -1,27 +1,27 @@ | Oxc | ESBuild | Oxc | ESBuild | Original | minified | minified | gzip | gzip | Fixture ------------------------------------------------------------------------------------- -72.14 kB | 23.57 kB | 23.70 kB | 8.55 kB | 8.54 kB | react.development.js +72.14 kB | 23.57 kB | 23.70 kB | 8.52 kB | 8.54 kB | react.development.js -173.90 kB | 59.68 kB | 59.82 kB | 19.25 kB | 19.33 kB | moment.js +173.90 kB | 59.68 kB | 59.82 kB | 19.20 kB | 19.33 kB | moment.js -287.63 kB | 89.52 kB | 90.07 kB | 31.07 kB | 31.95 kB | jquery.js +287.63 kB | 89.52 kB | 90.07 kB | 30.95 kB | 31.95 kB | jquery.js -342.15 kB | 117.69 kB | 118.14 kB | 43.66 kB | 44.37 kB | vue.js +342.15 kB | 117.69 kB | 118.14 kB | 43.55 kB | 44.37 kB | vue.js -544.10 kB | 71.49 kB | 72.48 kB | 25.92 kB | 26.20 kB | lodash.js +544.10 kB | 71.49 kB | 72.48 kB | 25.89 kB | 26.20 kB | lodash.js -555.77 kB | 271.48 kB | 270.13 kB | 88.45 kB | 90.80 kB | d3.js +555.77 kB | 271.48 kB | 270.13 kB | 88.38 kB | 90.80 kB | d3.js -1.01 MB | 457.63 kB | 458.89 kB | 123.79 kB | 126.71 kB | bundle.min.js +1.01 MB | 457.63 kB | 458.89 kB | 123.53 kB | 126.71 kB | bundle.min.js -1.25 MB | 650.59 kB | 646.76 kB | 161.49 kB | 163.73 kB | three.js +1.25 MB | 650.59 kB | 646.76 kB | 161.11 kB | 163.73 kB | three.js -2.14 MB | 718.83 kB | 724.14 kB | 162.40 kB | 181.07 kB | victory.js +2.14 MB | 718.83 kB | 724.14 kB | 162.15 kB | 181.07 kB | victory.js -3.20 MB | 1.01 MB | 1.01 MB | 325.18 kB | 331.56 kB | echarts.js +3.20 MB | 1.01 MB | 1.01 MB | 324.36 kB | 331.56 kB | echarts.js -6.69 MB | 2.30 MB | 2.31 MB | 469.99 kB | 488.28 kB | antd.js +6.69 MB | 2.30 MB | 2.31 MB | 469.42 kB | 488.28 kB | antd.js -10.95 MB | 3.37 MB | 3.49 MB | 866.64 kB | 915.50 kB | typescript.js +10.95 MB | 3.37 MB | 3.49 MB | 864.74 kB | 915.50 kB | typescript.js