僅移除空白字元
使用 Bun 的 JavaScript 和 TypeScript 壓縮器減少包大小
Bun 內建了一個快速的 JavaScript 和 TypeScript 壓縮器。根據程式碼庫的不同,它可以將包體積減少 80% 或更多。它還可以讓輸出程式碼執行得更快。壓縮器會執行數十種最佳化,包括常量摺疊、死程式碼消除和語法轉換。與其他壓縮器不同,Bun 的壓縮器能讓 bun build 執行得更快,因為需要列印的程式碼更少。
CLI 用法
啟用所有壓縮
使用 --minify 標誌啟用所有壓縮模式:
bun build ./index.ts --minify --outfile=out.js
--minify 標誌啟用:
- 空白字元壓縮
- 語法壓縮
- 識別符號壓縮
生產模式
--production 標誌會自動啟用壓縮:
bun build ./index.ts --production --outfile=out.js
--production 標誌還會:
- 將
process.env.NODE_ENV設定為production - 啟用生產模式下的 JSX 匯入和轉換
細粒度控制
分別啟用特定的壓縮模式:
# 僅移除空白字元
bun build ./index.ts --minify-whitespace --outfile=out.js
# 僅壓縮語法
bun build ./index.ts --minify-syntax --outfile=out.js
# 僅壓縮識別符號
bun build ./index.ts --minify-identifiers --outfile=out.js
# 組合特定模式
bun build ./index.ts --minify-whitespace --minify-syntax --outfile=out.js
JavaScript API
使用 Bun 的打包器進行程式設計時,通過 minify 選項設定壓縮:
await Bun.build({
entrypoints: ["./index.ts"],
outdir: "./out",
minify: true, // 啟用所有壓縮模式
});
細粒度控制則傳入物件:
await Bun.build({
entrypoints: ["./index.ts"],
outdir: "./out",
minify: {
whitespace: true,
syntax: true,
identifiers: true,
},
});
壓縮模式
Bun 的壓縮器有三種彼此獨立的模式,你可以分別或同時啟用。
空白字元壓縮(--minify-whitespace)
移除輸出中的所有多餘空白字元、換行和格式。
語法壓縮(--minify-syntax)
將 JavaScript 語法重寫為更短的等效形式,並執行常量摺疊、死程式碼消除及其他最佳化。
識別符號壓縮(--minify-identifiers)
根據使用頻率重新命名區域性變數和函式名為更短的識別符號。
所有轉換。
布林字面量縮短
模式: --minify-syntax
將布林字面量轉換為更短的表示式。
true
false
!0
!1
布林代數最佳化
模式: --minify-syntax
通過邏輯規則簡化布林表示式。
if (!!x) y;
if (x && true) y;
if (x || false) y;
!true
!false
if(x)y;
if(x)y;
if(x)y;
!1
!0
undefined 縮短
模式: --minify-syntax
用更短的等效表示式替換 undefined。
undefined
let x = undefined;
void 0
let x=void 0;
undefined 相等性最佳化
模式: --minify-syntax
最佳化與 undefined 的寬鬆相等檢查。
x == undefined
x != undefined
x == null
x != null
Infinity 縮短
模式: --minify-syntax
將 Infinity 轉換為數學表示式。
Infinity
-Infinity
1/0
-1/0
typeof 最佳化
模式: --minify-syntax
最佳化 typeof 對比並求值常量 typeof 表示式。
typeof x === 'undefined'
typeof x !== 'undefined'
typeof require
typeof null
typeof true
typeof 123
typeof "str"
typeof 123n
typeof x>'u'
typeof x<'u'
"function"
"object"
"boolean"
"number"
"string"
"bigint"
數字格式化
模式: --minify-syntax
以最緊湊形式格式化數字。
10000
100000
1000000
1.0
-42.0
1e4
1e5
1e6
1
-42
算術常量摺疊
模式: --minify-syntax
編譯時計算算術運算。
1 + 2
10 - 5
3 * 4
10 / 2
10 % 3
2 ** 3
3
5
12
5
1
8
位運算常量摺疊
模式: --minify-syntax
編譯時計算位運算。
5 & 3
5 | 3
5 ^ 3
8 << 2
32 >> 2
~5
1
7
6
32
8
-6
字串拼接
模式: --minify-syntax
編譯時合併字串字面量。
"a" + "b"
"x" + 123
"foo" + "bar" + "baz"
"ab"
"x123"
"foobarbaz"
字串索引
模式: --minify-syntax
編譯時計算字串字元訪問。
"foo"[2]
"hello"[0]
"o"
"h"
模板字面量摺疊
模式: --minify-syntax
編譯時計算帶常量表達式的模板字面量。
`a${123}b`
`result: ${5 + 10}`
"a123b"
"result: 15"
模板字面量轉字串
模式: --minify-syntax
將不包含插值的模板字面量轉換為普通字串。
`Hello World`
`Line 1
Line 2`
"Hello World"
"Line 1\nLine 2"
字串引號最佳化
模式: --minify-syntax
選擇最優引號以減少轉義。
"It's a string"
'He said "hello"'
`Simple string`
"It's a string"
'He said "hello"'
"Simple string"
陣列展開內聯
模式: --minify-syntax
內聯對常量陣列的陣列展開操作。
[1, ...[2, 3], 4]
[...[a, b]]
[1,2,3,4]
[a,b]
陣列索引
模式: --minify-syntax
編譯時計算常量陣列訪問。
[x][0]
['a', 'b', 'c'][1]
['a', , 'c'][1]
x
'b'
void 0
屬性訪問最佳化
模式: --minify-syntax
可用時將括號訪問轉換為點訪問。
obj["property"]
obj["validName"]
obj["123"]
obj["invalid-name"]
obj.property
obj.validName
obj["123"]
obj["invalid-name"]
比較摺疊
模式: --minify-syntax
編譯時計算常量比較。
3 < 5
5 > 3
3 <= 3
5 >= 6
"a" < "b"
!0
!0
!0
!1
!0
邏輯操作摺疊
模式: --minify-syntax
簡化帶常量值的邏輯操作。
true && x
false && x
true || x
false || x
x
!1
!0
x
空值合併摺疊
模式: --minify-syntax
編譯時計算已知值的空值合併操作。
null ?? x
undefined ?? x
42 ?? x
x
x
42
逗號表示式簡化
模式: --minify-syntax
移除無副作用的逗號序列表達式。
(0, x)
(123, "str", x)
x
x
三元條件摺疊
模式: --minify-syntax
編譯時計算常量條件的三元表示式。
true ? a : b
false ? a : b
x ? true : false
x ? false : true
a
b
x ? !0 : !1
x ? !1 : !0
一元表示式摺疊
模式: --minify-syntax
簡化一元操作。
+123
+"123"
-(-x)
~~x
!!x
123
123
- -x
~~x
!!x
雙重否定移除
模式: --minify-syntax
移除不必要的雙重否定。
if (!!x) y;
!!!x
if(x)y;
!x
if 語句最佳化
模式: --minify-syntax
最佳化常量條件的 if 語句。
if (true) x;
if (false) x;
if (x) { a; }
if (x) {} else y;
x;
// 移除
if(x)a;
if(!x)y;
死程式碼消除
模式: --minify-syntax
移除不可達和無副作用程式碼。
if (false) {
unreachable();
}
function foo() {
return x;
deadCode();
}
function foo(){return x}
不可達分支移除
模式: --minify-syntax
移除永遠不會執行的分支。
while (false) {
neverRuns();
}
// 完全移除
空塊移除
模式: --minify-syntax
移除空塊和多餘的大括號。
{ }
if (x) { }
;
// 移除
單語句塊展開
模式: --minify-syntax
移除單語句塊多餘的大括號。
if (condition) {
doSomething();
}
if(condition)doSomething();
TypeScript 列舉內聯
模式: --minify-syntax
編譯時內聯 TypeScript 列舉值。
enum Color { Red, Green, Blue }
const x = Color.Red;
const x=0;
純淨標註支援
模式: 始終生效
遵循 /*@__PURE__*/ 標註以進行搖樹最佳化(移除未使用的程式碼)。
const x = /*@__PURE__*/ expensive();
// 如果 x 未使用...
// 完全移除
識別符號重新命名
模式: --minify-identifiers
根據使用頻率重新命名區域性變數為更短的名稱。
function calculateSum(firstNumber, secondNumber) {
const result = firstNumber + secondNumber;
return result;
}
function n(t,u){const c=t+u;return c}
命名策略:
- 使用頻率最高的識別符號會獲得最短的名稱;Bun 會根據每個字元在原始碼中的出現頻率對字母排序,因此最先使用的名稱通常是 t、e 和 n 這樣的字母,而不是 a、b、c
- 單字元:a-z、A-Z 和
_(共 53 個名稱;單獨的$已保留) - 雙字元:第二個字元也可以是數字(最多 3,456 個名稱)
- 根據需要使用三個或更多字元
保留識別符號:
- JavaScript 關鍵字和保留字
- 全域性識別符號
- 命名匯出(保持 API 穩定)
- CommonJS 名稱:
exports、module。
空白字元移除
模式: --minify-whitespace
移除所有多餘空白。
function add(a, b) {
return a + b;
}
let x = 10;
function add(a,b){return a+b}let x=10;
分號最佳化
模式: --minify-whitespace
僅在必要時插入分號。
let a = 1;
let b = 2;
return a + b;
let a=1;let b=2;return a+b
運算子空格移除
模式: --minify-whitespace
移除運算子周圍空格。
a + b
x = y * z
foo && bar || baz
a+b
x=y*z
foo&&bar||baz
註釋移除
模式: --minify-whitespace
移除註釋,但保留重要的許可證註釋。
// 該註釋被移除
/* 這個也是 */
/*! 但該許可證註釋被保留 */
function test() { /* 內聯註釋 */ }
/*! 但該許可證註釋被保留 */
function test(){}
物件和陣列格式化
模式: --minify-whitespace
移除物件和陣列字面量內空白。
const obj = {
name: "John",
age: 30
};
const arr = [1, 2, 3];
const obj={name:"John",age:30};const arr=[1,2,3];
控制流格式化
模式: --minify-whitespace
移除控制結構內空白。
if (condition) {
doSomething();
}
for (let i = 0; i < 10; i++) {
console.log(i);
}
if(condition)doSomething();for(let i=0;i<10;i++)console.log(i);
函式格式化
模式: --minify-whitespace
移除函式宣告內空白。
function myFunction(param1, param2) {
return param1 + param2;
}
const arrow = (a, b) => a + b;
function myFunction(param1,param2){return param1+param2}const arrow=(a,b)=>a+b;
括號最小化
模式: 始終生效
僅在優先順序需要時新增括號。
(a + b) * c
a + (b * c)
((x))
(a+b)*c
a+b*c
x
模板字面量值摺疊
模式: --minify-syntax
將非字串插值值轉為字串並摺疊進模板。
`hello ${123}`
`value: ${true}`
`result: ${null}`
`status: ${undefined}`
`big: ${10n}`
"hello 123"
"value: true"
"result: null"
"status: undefined"
"big: 10"
字串長度常量摺疊
模式: --minify-syntax
編譯時計算字串字面量的 .length 屬性。
"hello world".length
"test".length
11
4
建構函式呼叫簡化
模式: --minify-syntax
簡化內建型別的建構函式呼叫。
new Object()
new Object(null)
new Object({a: 1})
new Array()
new Array(x, y)
{}
{}
{a:1}
[]
[x,y]
單屬性物件內聯
模式: --minify-syntax
內聯只有單個屬性的物件的屬性訪問。
({fn: () => console.log('hi')}).fn
() => console.log('hi')
字串 charCodeAt 常量摺疊
模式: 始終生效
對 ASCII 字串字面量計算 charCodeAt()。
"hello".charCodeAt(1)
"A".charCodeAt(0)
101
65
void 0 等價 null 相等轉換
模式: --minify-syntax
將與 void 0 的寬鬆相等轉換為 null,因為兩者等價。
x == void 0
x != void 0
x == null
x != null
取反運算子最佳化
模式: --minify-syntax
將取反運算子移至逗號表示式內。
-(a, b)
-(x, y, z)
a,-b
x,y,-z
Import.meta 屬性內聯
模式: 打包模式下
建置時內聯已知的 import.meta 屬性值。
import.meta.dir
import.meta.file
import.meta.path
import.meta.url
"/path/to/directory"
"filename.js"
"/full/path/to/file.js"
"file:///full/path/to/file.js"
變數宣告合併
模式: --minify-syntax
合併相鄰的相同型別變數宣告。
let a = 1;
let b = 2;
const c = 3;
const d = 4;
let a=1,b=2;
const c=3,d=4;
表示式語句合併
模式: --minify-syntax
使用逗號運算子合併相鄰表示式語句。
console.log(1);
console.log(2);
console.log(3);
console.log(1),console.log(2),console.log(3);
return 語句合併
模式: --minify-syntax
合併 return 前的表示式,使用逗號運算子。
console.log(x);
return y;
return console.log(x),y;
throw 語句合併
模式: --minify-syntax
合併 throw 前的表示式,使用逗號運算子。
console.log(x);
throw new Error();
throw(console.log(x),new Error());
TypeScript 列舉跨模組內聯
模式: --minify-syntax(打包模式)
跨模組邊界內聯列舉值。
// lib.ts
export enum Color { Red, Green, Blue }
// 輸入(main.ts)
import { Color } from './lib';
const x = Color.Red;
const x=0;
計算屬性列舉內聯
模式: --minify-syntax
內聯用作計算屬性物件屬性的列舉值。
enum Keys { FOO = 'foo' }
const obj = { [Keys.FOO]: value }
const obj={foo:value}
箭頭函式主體簡化
模式: --minify-syntax
當箭頭函式僅傳回值時,使用表示式主體語法。
() => { return x; }
(a) => { return a + 1; }
() => x
a => a + 1
物件屬性簡寫
模式: 始終生效
當屬性名與值的識別符號相同時,使用簡寫語法。
{ x: x, y: y }
{ name: name, age: age }
{ x, y }
{ name, age }
移除 debugger 語句
模式: --drop=debugger
移除程式碼中的 debugger 語句。
function test() {
debugger;
return x;
}
function test(){return x}
移除 console 呼叫
模式: --drop=console
移除所有 console.* 方法呼叫。
console.log("debug");
console.warn("warning");
x = console.error("error");
void 0;
void 0;
x=void 0;
移除自定義函式呼叫
模式: --drop=<name>
移除對指定全域性函式及其方法的呼叫。
assert(condition);
assert.equal(a, b);
void 0;
void 0;
保留名稱
為了在壓縮識別符號的同時保留原始函式名和類名以便除錯,請使用 --keep-names 標誌:
bun build ./index.ts --minify --keep-names --outfile=out.js
或者在 JavaScript API 中:
await Bun.build({
entrypoints: ["./index.ts"],
outdir: "./out",
minify: {
identifiers: true,
keepNames: true,
},
});
--keep-names 會在繼續壓縮識別符號的同時,保留函式和類的 .name 屬性。
組合範例
同時使用三種壓縮模式:
const myVariable = 42;
const myFunction = () => {
const isValid = true;
const result = undefined;
return isValid ? myVariable : result;
};
const output = myFunction();
// Output with --minify (20 bytes, 89% reduction)
var t=()=>42,e=t();
何時使用壓縮
適用 --minify 的場景:
- 生產環境包
- 降低 CDN 頻寬成本
- 提升頁面載入速度
適用單獨模式的場景:
--minify-whitespace: 在不改變語義的情況下減小體積--minify-syntax: 在保留可讀識別符號以便除錯的同時生成更小的輸出--minify-identifiers: 最大限度地減小體積(結合--keep-names以獲得更好的堆疊跟蹤)
避免壓縮的場景:
- 開發建置(除錯更困難)
- 需要可讀錯誤資訊時
- 程式碼庫供消費者閱讀原始碼的庫。