运行时包管理器打包器测试运行器代码检查格式化指南参考博客反馈

仅移除空白字符

使用 Bun 的 JavaScript 和 TypeScript 压缩器减少包大小

Bun 内置了一个快速的 JavaScript 和 TypeScript 压缩器。根据代码库的不同,它可以将包体积减少 80% 或更多。它还可以让输出代码运行得更快。压缩器会执行数十种优化,包括常量折叠、死代码消除和语法转换。与其他压缩器不同,Bun 的压缩器能让 bun build 运行得更快,因为需要打印的代码更少。

CLI 用法

启用所有压缩

使用 --minify 标志启用所有压缩模式:

bash
bun build ./index.ts --minify --outfile=out.js

--minify 标志启用:

  • 空白字符压缩
  • 语法压缩
  • 标识符压缩

生产模式

--production 标志会自动启用压缩:

bash
bun build ./index.ts --production --outfile=out.js

--production 标志还会:

  • 将 process.env.NODE_ENV 设置为 production
  • 启用生产模式下的 JSX 导入和转换

细粒度控制

分别启用特定的压缩模式:

bash
# 仅移除空白字符
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 选项配置压缩:

TypeScript
await Bun.build({
  entrypoints: ["./index.ts"],
  outdir: "./out",
  minify: true, // 启用所有压缩模式
});

细粒度控制则传入对象:

TypeScript
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

将布尔字面量转换为更短的表达式。

Input
true
false
Output
!0
!1

布尔代数优化

模式: --minify-syntax

通过逻辑规则简化布尔表达式。

Input
if (!!x) y;
if (x && true) y;
if (x || false) y;
!true
!false
Output
if(x)y;
if(x)y;
if(x)y;
!1
!0

undefined 缩短

模式: --minify-syntax

用更短的等效表达式替换 undefined。

Input
undefined
let x = undefined;
Output
void 0
let x=void 0;

undefined 相等性优化

模式: --minify-syntax

优化与 undefined 的宽松相等检查。

Input
x == undefined
x != undefined
Output
x == null
x != null

Infinity 缩短

模式: --minify-syntax

将 Infinity 转换为数学表达式。

输入
Infinity
-Infinity
输出
1/0
-1/0

typeof 优化

模式: --minify-syntax

优化 typeof 对比并求值常量 typeof 表达式。

Input
typeof x === 'undefined'
typeof x !== 'undefined'
typeof require
typeof null
typeof true
typeof 123
typeof "str"
typeof 123n
Output
typeof x>'u'
typeof x<'u'
"function"
"object"
"boolean"
"number"
"string"
"bigint"

数字格式化

模式: --minify-syntax

以最紧凑形式格式化数字。

Input
10000
100000
1000000
1.0
-42.0
Output
1e4
1e5
1e6
1
-42

算术常量折叠

模式: --minify-syntax

编译时计算算术运算。

Input
1 + 2
10 - 5
3 * 4
10 / 2
10 % 3
2 ** 3
Output
3
5
12
5
1
8

位运算常量折叠

模式: --minify-syntax

编译时计算位运算。

Input
5 & 3
5 | 3
5 ^ 3
8 << 2
32 >> 2
~5
Output
1
7
6
32
8
-6

字符串拼接

模式: --minify-syntax

编译时合并字符串字面量。

Input
"a" + "b"
"x" + 123
"foo" + "bar" + "baz"
Output
"ab"
"x123"
"foobarbaz"

字符串索引

模式: --minify-syntax

编译时计算字符串字符访问。

Input
"foo"[2]
"hello"[0]
Output
"o"
"h"

模板字面量折叠

模式: --minify-syntax

编译时计算带常量表达式的模板字面量。

Input
`a${123}b`
`result: ${5 + 10}`
Output
"a123b"
"result: 15"

模板字面量转字符串

模式: --minify-syntax

将不包含插值的模板字面量转换为普通字符串。

输入
`Hello World`
`Line 1
Line 2`
输出
"Hello World"
"Line 1\nLine 2"

字符串引号优化

模式: --minify-syntax

选择最优引号以减少转义。

Input
"It's a string"
'He said "hello"'
`Simple string`
Output
"It's a string"
'He said "hello"'
"Simple string"

数组展开内联

模式: --minify-syntax

内联对常量数组的数组展开操作。

Input
[1, ...[2, 3], 4]
[...[a, b]]
Output
[1,2,3,4]
[a,b]

数组索引

模式: --minify-syntax

编译时计算常量数组访问。

Input
[x][0]
['a', 'b', 'c'][1]
['a', , 'c'][1]
Output
x
'b'
void 0

属性访问优化

模式: --minify-syntax

可用时将括号访问转换为点访问。

Input
obj["property"]
obj["validName"]
obj["123"]
obj["invalid-name"]
Output
obj.property
obj.validName
obj["123"]
obj["invalid-name"]

比较折叠

模式: --minify-syntax

编译时计算常量比较。

Input
3 < 5
5 > 3
3 <= 3
5 >= 6
"a" < "b"
Output
!0
!0
!0
!1
!0

逻辑操作折叠

模式: --minify-syntax

简化带常量值的逻辑操作。

Input
true && x
false && x
true || x
false || x
Output
x
!1
!0
x

空值合并折叠

模式: --minify-syntax

编译时计算已知值的空值合并操作。

Input
null ?? x
undefined ?? x
42 ?? x
Output
x
x
42

逗号表达式简化

模式: --minify-syntax

移除无副作用的逗号序列表达式。

Input
(0, x)
(123, "str", x)
Output
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

简化一元操作。

Input
+123
+"123"
-(-x)
~~x
!!x
Output
123
123
- -x
~~x
!!x

双重否定移除

模式: --minify-syntax

移除不必要的双重否定。

Input
if (!!x) y;
!!!x
Output
if(x)y;
!x

if 语句优化

模式: --minify-syntax

优化常量条件的 if 语句。

Input
if (true) x;
if (false) x;
if (x) { a; }
if (x) {} else y;
Output
x;
// 移除
if(x)a;
if(!x)y;

死代码消除

模式: --minify-syntax

移除不可达和无副作用代码。

Input
if (false) {
  unreachable();
}
function foo() {
  return x;
  deadCode();
}
Output
function foo(){return x}

不可达分支移除

模式: --minify-syntax

移除永远不会执行的分支。

Input
while (false) {
  neverRuns();
}
Output
// 完全移除

空块移除

模式: --minify-syntax

移除空块和多余的大括号。

Input
{ }
if (x) { }
Output
;
// 移除

单语句块展开

模式: --minify-syntax

移除单语句块多余的大括号。

Input
if (condition) {
  doSomething();
}
Output
if(condition)doSomething();

TypeScript 枚举内联

模式: --minify-syntax

编译时内联 TypeScript 枚举值。

Input
enum Color { Red, Green, Blue }
const x = Color.Red;
Output
const x=0;

纯净标注支持

模式: 始终生效

遵循 /*@__PURE__*/ 标注以进行摇树优化(移除未使用的代码)。

Input
const x = /*@__PURE__*/ expensive();
// 如果 x 未使用...
Output
// 完全移除

标识符重命名

模式: --minify-identifiers

根据使用频率重命名局部变量为更短的名称。

Input
function calculateSum(firstNumber, secondNumber) {
  const result = firstNumber + secondNumber;
  return result;
}
Output
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

移除所有多余空白。

Input
function add(a, b) {
    return a + b;
}
let x = 10;
Output
function add(a,b){return a+b}let x=10;

分号优化

模式: --minify-whitespace

仅在必要时插入分号。

Input
let a = 1;
let b = 2;
return a + b;
Output
let a=1;let b=2;return a+b

操作符空格移除

模式: --minify-whitespace

移除操作符周围空格。

Input
a + b
x = y * z
foo && bar || baz
Output
a+b
x=y*z
foo&&bar||baz

注释移除

模式: --minify-whitespace

移除注释,但保留重要的许可证注释。

Input
// 该注释被移除
/* 这个也是 */
/*! 但该许可证注释被保留 */
function test() { /* 内联注释 */ }
Output
/*! 但该许可证注释被保留 */
function test(){}

对象和数组格式化

模式: --minify-whitespace

移除对象和数组字面量内空白。

Input
const obj = {
    name: "John",
    age: 30
};
const arr = [1, 2, 3];
Output
const obj={name:"John",age:30};const arr=[1,2,3];

控制流格式化

模式: --minify-whitespace

移除控制结构内空白。

Input
if (condition) {
    doSomething();
}
for (let i = 0; i < 10; i++) {
    console.log(i);
}
Output
if(condition)doSomething();for(let i=0;i<10;i++)console.log(i);

函数格式化

模式: --minify-whitespace

移除函数声明内空白。

Input
function myFunction(param1, param2) {
    return param1 + param2;
}
const arrow = (a, b) => a + b;
Output
function myFunction(param1,param2){return param1+param2}const arrow=(a,b)=>a+b;

括号最小化

模式: 始终生效

仅在优先级需要时添加括号。

Input
(a + b) * c
a + (b * c)
((x))
Output
(a+b)*c
a+b*c
x

模板字面量值折叠

模式: --minify-syntax

将非字符串插值值转为字符串并折叠进模板。

Input
`hello ${123}`
`value: ${true}`
`result: ${null}`
`status: ${undefined}`
`big: ${10n}`
Output
"hello 123"
"value: true"
"result: null"
"status: undefined"
"big: 10"

字符串长度常量折叠

模式: --minify-syntax

编译时计算字符串字面量的 .length 属性。

Input
"hello world".length
"test".length
Output
11
4

构造函数调用简化

模式: --minify-syntax

简化内置类型的构造函数调用。

Input
new Object()
new Object(null)
new Object({a: 1})
new Array()
new Array(x, y)
Output
{}
{}
{a:1}
[]
[x,y]

单属性对象内联

模式: --minify-syntax

内联只有单个属性的对象的属性访问。

Input
({fn: () => console.log('hi')}).fn
Output
() => console.log('hi')

字符串 charCodeAt 常量折叠

模式: 始终生效

对 ASCII 字符串字面量计算 charCodeAt()。

输入
"hello".charCodeAt(1)
"A".charCodeAt(0)
输出
101
65

void 0 等价 null 相等转换

模式: --minify-syntax

将与 void 0 的宽松相等转换为 null,因为两者等价。

Input
x == void 0
x != void 0
Output
x == null
x != null

取反操作符优化

模式: --minify-syntax

将取反操作符移至逗号表达式内。

Input
-(a, b)
-(x, y, z)
Output
a,-b
x,y,-z

Import.meta 属性内联

模式: 打包模式下

构建时内联已知的 import.meta 属性值。

Input
import.meta.dir
import.meta.file
import.meta.path
import.meta.url
Output
"/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

使用逗号运算符合并相邻表达式语句。

Input
console.log(1);
console.log(2);
console.log(3);
Output
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 前的表达式,使用逗号运算符。

Input
console.log(x);
throw new Error();
Output
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

内联用作计算属性对象属性的枚举值。

Input
enum Keys { FOO = 'foo' }
const obj = { [Keys.FOO]: value }
Output
const obj={foo:value}

箭头函数主体简化

模式: --minify-syntax

当箭头函数仅返回值时,使用表达式主体语法。

输入
() => { return x; }
(a) => { return a + 1; }
输出
() => x
a => a + 1

对象属性简写

模式: 始终生效

当属性名与值的标识符相同时,使用简写语法。

Input
{ x: x, y: y }
{ name: name, age: age }
Output
{ x, y }
{ name, age }

移除 debugger 语句

模式: --drop=debugger

移除代码中的 debugger 语句。

Input
function test() {
  debugger;
  return x;
}
Output
function test(){return x}

移除 console 调用

模式: --drop=console

移除所有 console.* 方法调用。

Input
console.log("debug");
console.warn("warning");
x = console.error("error");
Output
void 0;
void 0;
x=void 0;

移除自定义函数调用

模式: --drop=<name>

移除对指定全局函数及其方法的调用。

输入
assert(condition);
assert.equal(a, b);
输出(使用
void 0;
void 0;

保留名称

为了在压缩标识符的同时保留原始函数名和类名以便调试,请使用 --keep-names 标志:

bash
bun build ./index.ts --minify --keep-names --outfile=out.js

或者在 JavaScript API 中:

TypeScript
await Bun.build({
  entrypoints: ["./index.ts"],
  outdir: "./out",
  minify: {
    identifiers: true,
    keepNames: true,
  },
});

--keep-names 会在继续压缩标识符的同时,保留函数和类的 .name 属性。

组合示例

同时使用三种压缩模式:

input.ts
const myVariable = 42;

const myFunction = () => {
  const isValid = true;
  const result = undefined;
  return isValid ? myVariable : result;
};

const output = myFunction();
output.js
// Output with --minify (20 bytes, 89% reduction)
var t=()=>42,e=t();

何时使用压缩

适用 --minify 的场景:

  • 生产环境包
  • 降低 CDN 带宽成本
  • 提升页面加载速度

适用单独模式的场景:

  • --minify-whitespace: 在不改变语义的情况下减小体积
  • --minify-syntax: 在保留可读标识符以便调试的同时生成更小的输出
  • --minify-identifiers: 最大限度地减小体积(结合 --keep-names 以获得更好的堆栈跟踪)

避免压缩的场景:

  • 开发构建(调试更困难)
  • 需要可读错误信息时
  • 代码库供消费者阅读源码的库。