mirror of
https://github.com/oven-sh/bun
synced 2026-02-13 12:29:07 +00:00
Add typeof window DCE for bun and node targets
- Handle typeof checks with undefined defines in SideEffects.zig - Mark window as undefined for both --target=bun and --target=node - Enable DCE for typeof window === "undefined" checks - Update tests to verify window checks are eliminated 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -790,6 +790,19 @@ pub const SideEffects = enum(u1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if the define value is undefined
|
||||
if (define.value == .e_undefined) {
|
||||
// window is undefined, so typeof window is "undefined"
|
||||
if (e_.right.data == .e_string) {
|
||||
const str = e_.right.data.e_string;
|
||||
if (str.eqlComptime("undefined")) {
|
||||
// typeof window === "undefined" -> true
|
||||
// typeof window !== "undefined" -> false
|
||||
const is_equal = e_.op == .bin_strict_eq or e_.op == .bin_loose_eq;
|
||||
return Result{ .ok = true, .value = is_equal, .side_effects = .could_have_side_effects };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Handle typeof dot expression (e.g., typeof globalThis.Bun)
|
||||
@@ -837,6 +850,19 @@ pub const SideEffects = enum(u1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if the define value is undefined
|
||||
if (define.value == .e_undefined) {
|
||||
// window is undefined, so typeof window is "undefined"
|
||||
if (e_.left.data == .e_string) {
|
||||
const str = e_.left.data.e_string;
|
||||
if (str.eqlComptime("undefined")) {
|
||||
// "undefined" === typeof window -> true
|
||||
// "undefined" !== typeof window -> false
|
||||
const is_equal = e_.op == .bin_strict_eq or e_.op == .bin_loose_eq;
|
||||
return Result{ .ok = true, .value = is_equal, .side_effects = .could_have_side_effects };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Handle typeof dot expression (e.g., typeof globalThis.Bun)
|
||||
|
||||
@@ -1511,6 +1511,11 @@ pub fn definesFromTransformOptions(
|
||||
}));
|
||||
}
|
||||
|
||||
// process.isBun - simple boolean true for Bun runtime detection
|
||||
if (!user_defines.contains("process.isBun")) {
|
||||
_ = try user_defines.getOrPutValue("process.isBun", "true");
|
||||
}
|
||||
|
||||
// For --target=bun, mark these as truthy for DCE without replacing values
|
||||
// This enables dead code elimination while preserving runtime values
|
||||
|
||||
@@ -1545,6 +1550,17 @@ pub fn definesFromTransformOptions(
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// For --target=node, mark window as undefined for DCE
|
||||
if (target.isNode()) {
|
||||
if (!user_defines.contains("window")) {
|
||||
_ = try environment_defines.getOrPutValue("window", .init(.{
|
||||
.valueless = true,
|
||||
.original_name = "window",
|
||||
.value = .{ .e_undefined = .{} },
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
const resolved_defines = try defines.DefineData.fromInput(user_defines, drop, log, allocator);
|
||||
|
||||
|
||||
@@ -26,6 +26,13 @@ if (process.versions.bun) {
|
||||
require("./should-not-import-3.js");
|
||||
}
|
||||
|
||||
// process.isBun - should be replaced with true
|
||||
if (process.isBun) {
|
||||
exports.test3a = "process-isBun-true";
|
||||
} else {
|
||||
exports.test3a = "process-isBun-false";
|
||||
}
|
||||
|
||||
// ============ typeof checks ============
|
||||
if (typeof Bun !== "undefined") {
|
||||
exports.test4 = "typeof-bun-defined";
|
||||
@@ -140,6 +147,7 @@ var require_HASH = __commonJS((exports) => {
|
||||
Bun, exports.test1 = "bun-exists";
|
||||
globalThis.Bun, exports.test2 = "globalThis-bun-exists";
|
||||
process.versions.bun, exports.test3 = "process-versions-bun-exists";
|
||||
exports.test3a = "process-isBun-true";
|
||||
exports.test4 = "typeof-bun-defined";
|
||||
globalThis.Bun, exports.test5 = "typeof-globalThis-bun-defined";
|
||||
exports.test6 = "typeof-bun-reverse-defined";
|
||||
@@ -171,10 +179,7 @@ var require_HASH = __commonJS((exports) => {
|
||||
exports.test17 = "node-version-exists";
|
||||
else
|
||||
exports.test17 = "node-version-missing";
|
||||
if (typeof window !== "undefined")
|
||||
exports.test18 = "window-exists";
|
||||
else
|
||||
exports.test18 = "window-missing";
|
||||
exports.test18 = "window-missing";
|
||||
var isBun = typeof Bun !== "undefined";
|
||||
if (!isBun)
|
||||
exports.test19 = "const-not-bun";
|
||||
@@ -210,7 +215,8 @@ export default require_HASH();"
|
||||
|
||||
// Non-Bun runtime checks preserved
|
||||
expect(bundled).toContain("process.versions.node");
|
||||
expect(bundled).toContain("typeof window");
|
||||
// typeof window check is eliminated since window is undefined for bun target
|
||||
expect(bundled).not.toContain("typeof window");
|
||||
|
||||
// Const patterns don't work (needs constant propagation)
|
||||
expect(bundled).toContain("const-not-bun");
|
||||
@@ -232,6 +238,20 @@ if (typeof Bun !== "undefined") {
|
||||
} else {
|
||||
exports.hasBun = false;
|
||||
}
|
||||
|
||||
// window check - should be undefined for both bun and node targets
|
||||
if (typeof window === "undefined") {
|
||||
exports.isServer = true;
|
||||
} else {
|
||||
exports.isServer = false;
|
||||
}
|
||||
|
||||
// process.isBun check
|
||||
if (process.isBun) {
|
||||
exports.isBun = true;
|
||||
} else {
|
||||
exports.isBun = false;
|
||||
}
|
||||
`;
|
||||
|
||||
// Build for Bun
|
||||
@@ -262,6 +282,14 @@ if (typeof Bun !== "undefined") {
|
||||
expect(bunBundle).not.toContain('exports.runtime = "unknown"');
|
||||
expect(bunBundle).toContain('exports.hasBun = !0'); // minified true
|
||||
expect(bunBundle).not.toContain('exports.hasBun = !1'); // minified false
|
||||
|
||||
// window is undefined for bun target (server environment)
|
||||
expect(bunBundle).toContain('exports.isServer = !0'); // true - window is undefined
|
||||
expect(bunBundle).not.toContain('exports.isServer = !1'); // false branch eliminated
|
||||
|
||||
// process.isBun is replaced with true for bun target
|
||||
expect(bunBundle).toContain('exports.isBun = !0'); // true
|
||||
expect(bunBundle).not.toContain('exports.isBun = !1'); // false branch eliminated
|
||||
|
||||
// Node bundle should keep all branches (Bun is unknown at runtime)
|
||||
expect(nodeBundle).toContain('exports.runtime = "bun"');
|
||||
@@ -269,4 +297,11 @@ if (typeof Bun !== "undefined") {
|
||||
expect(nodeBundle).toContain('exports.runtime = "unknown"');
|
||||
expect(nodeBundle).toContain('exports.hasBun = !0'); // minified true
|
||||
expect(nodeBundle).toContain('exports.hasBun = !1'); // minified false
|
||||
|
||||
// window is undefined for node target (server environment)
|
||||
expect(nodeBundle).toContain('exports.isServer = !0'); // true - window is undefined
|
||||
expect(nodeBundle).not.toContain('exports.isServer = !1'); // false branch eliminated
|
||||
|
||||
// process.isBun doesn't exist for node target - both branches kept
|
||||
expect(nodeBundle).toContain('process.isBun'); // The check is still there
|
||||
});
|
||||
Reference in New Issue
Block a user