死代码消除
Oxc 压缩器支持消除死代码。例如,它会移除 if (false) 块内的语句以及未使用的私有类字段。
此功能始终启用,但您可以通过启用一些选项来移除更多代码。
transformer 中的有用功能
除了以下选项外,您还可以使用 transformer 中的 define 功能将全局标识符替换为常量表达式,以移除更多死代码。
移除 Console
您可以通过启用 dropConsole 选项来移除所有 console.* 调用。此选项的行为类似于 Terser 的 drop_console 选项和 esbuild 的 drop: ['console'] 选项。
// 输入
const bar = window.bar();
console.log("foo", bar, baz());
// 输出
const bar = window.bar();// 示例
import { minify } from "oxc-minify";
const result = await minify("lib.js", code, {
compress: {
dropConsole: true,
},
});整个调用表达式会被移除
请注意,此选项会移除整个调用表达式,包括参数。这是有意为之的,因为如果参数计算成本高昂,移除调用参数的求值有助于提高运行时性能。但是,如果这些参数有任何副作用,此转换将改变代码的行为。如果您想保留参数,可以使用 compress.treeshake.manualPureFunctions: ['console'] 选项。
移除 Debugger
您可以通过启用 dropDebugger 选项来移除所有 debugger 语句。此选项默认启用。此选项的行为类似于 Terser 的 drop_debugger 选项和 esbuild 的 drop: ['debugger'] 选项。
// 输入
debugger;
// 输出// 示例
import { minify } from "oxc-minify";
const result = await minify("lib.js", code, {
compress: {
dropDebugger: true,
},
});移除标签
您可以通过启用 dropLabels 选项来移除具有指定标签的所有标签语句。此选项的行为类似于 esbuild 的 dropLabels 选项。
// 输入
DEV: console.log("foo");
console.log("bar");
// 输出
console.log("bar");// 示例
import { minify } from "oxc-minify";
const result = await minify("lib.js", code, {
compress: {
dropLabels: ["DEV"],
},
});未使用的声明
默认情况下,所有未使用的函数/类/变量声明都会被移除。您可以使用 unused 选项保留它们。
// 输入
{
function foo() {}
}
// 输出// 示例
import { minify } from "oxc-minify";
const result = await minify("lib.js", code, {
compress: {
unused: true, // 或 "keep_assign"
},
});保留 name 属性值
默认情况下,Oxc 压缩器假设您的代码不依赖函数/类的 name 属性。这是因为 name 属性是从函数/类名或变量名推断出来的,保留原始名称会阻止减小输出大小。
要保留 name 属性值,可以使用 keepNames 选项。
// 输入
var bar = function foo() {};
// 输出
var bar = function foo() {};// 示例
import { minify } from "oxc-minify";
const result = await minify("lib.js", code, {
compress: {
keepNames: true, // { function: true, class: true } 的简写
},
});mangle.keepNames 选项
如果您正在使用混淆功能,可能还需要启用 mangle.keepNames 选项。
控制副作用检测
有多个选项可以控制副作用检测。
纯注解
默认情况下,Oxc 压缩器会遵循纯注解。纯注解是标记表达式的注释,表示如果其返回值未被使用,可以安全地移除。详见规范提案草案。
可以通过将 compress.treeshake.annotations 选项设置为 false 来禁用此功能。
#__PURE__ / @__PURE__
#__PURE__ 注解用于标记函数调用,表示如果其返回值未被使用,可以安全地移除。注意,它只标记函数调用本身,不包括其参数。
如果您想标记其他表达式或覆盖参数,可以将它们包装在 IIFE 中并在其上放置 #__PURE__ 注解。
// 输入
/* #__PURE__ */ foo();
/* #__PURE__ */ new Foo();
/* #__PURE__ */ foo(bar());
/* #__PURE__ */ (() => {
foo(bar());
})();
console.log(/* #__PURE__ */ foo());
console.log(/* #__PURE__ */ new Foo());
// 输出
bar();
console.log(foo());
console.log(new Foo());函数不必是纯的
尽管名称如此,函数不必是纯的(纯函数 - 维基百科)。它不表示调用可以被缓存。换句话说,函数不必是引用透明的(引用透明 - 维基百科)。
#__NO_SIDE_EFFECTS__ / @__NO_SIDE_EFFECTS__
#__NO_SIDE_EFFECTS__ 注解用于标记函数声明,表示对其的所有调用如果返回值未被使用,可以安全地移除。如果您在多个位置调用该函数,这很有用。
// 输入
/* #__NO_SIDE_EFFECTS__ */
export function foo() {}
/* #__NO_SIDE_EFFECTS__ */
export const bar = () => {};
foo();
bar();
// 输出
export function foo() {}
export const bar = () => {};定义纯函数
除了使用纯注解标记函数外,您还可以通过 compress.treeshake.manualPureFunctions 选项标记函数。此选项是函数名称数组。此功能类似于 Rollup 的 treeshake.manualPureFunctions 选项和 Terser 的 pure_funcs 选项。
// 输入
foo();
foo.bar();
bar();
bar.baz();
new foo();
foo``;
// 输出
bar();// 示例
import { minify } from "oxc-minify";
const result = await minify("lib.js", code, {
compress: {
treeshake: {
manualPureFunctions: ["foo", "bar.baz"],
},
},
});忽略属性读取副作用
默认情况下,Oxc 压缩器假设属性读取有副作用。这是因为访问 null 的属性会抛出错误。此外,属性可能是 getter,而 getter 可能有副作用。您可以通过将 compress.treeshake.propertyReadSideEffects 选项设置为 false 来告诉 Oxc 压缩器忽略这些可能性。此功能类似于 Rollup 的 treeshake.propertyReadSideEffects 选项和 Terser 的 pure_getters 选项。
// 输入
const foo = {
get bar() {
console.log("effect");
return "bar";
},
};
foo.bar;
// 输出(启用 `compress.treeshake.propertyReadSideEffects: false` 时)忽略全局变量访问副作用
默认情况下,Oxc 压缩器假设全局变量访问有副作用。这是因为访问不存在的全局变量会抛出错误。此外,全局变量可能是 getter,而 getter 可能有副作用。您可以通过将 compress.treeshake.unknownGlobalSideEffects 选项设置为 false 来告诉 Oxc 压缩器忽略这些可能性。此功能类似于 Rollup 的 treeshake.unknownGlobalSideEffects 选项。
// 输入
const jQuery = $;
// 输出(启用 `compress.treeshake.propertyReadSideEffects: false` 时)忽略无效导入语句副作用
默认情况下,Oxc 压缩器假设导入语句没有副作用。导入语句在以下情况下有副作用:
- 导入无法解析
- 导入名称未从被导入模块导出
如果需要保留这些副作用,可以通过将 compress.treeshake.invalidImportSideEffects 选项设置为 true 来告诉 Oxc 压缩器保留它们。
// 输入
import { existing } from "cannot-be-resolved";
import { missing } from "somewhere";
// 输出(启用 `compress.treeshake.invalidImportSideEffects: true` 时)
import { existing } from "cannot-be-resolved";
import { missing } from "somewhere";
// 输出(启用 `compress.treeshake.invalidImportSideEffects: false` 时)