diff --git a/packages/bun-internal-test/src/runner.node.mjs b/packages/bun-internal-test/src/runner.node.mjs index 8b7796af17c026..d47254a0c9a7c3 100644 --- a/packages/bun-internal-test/src/runner.node.mjs +++ b/packages/bun-internal-test/src/runner.node.mjs @@ -558,7 +558,7 @@ function emojiTag(tag) { emojiText += ""; } - if (tag.includes("x86") || tag.includes("_64") || tag.includes("amd64")) { + if (tag.includes("x86") || tag.includes("x64") || tag.includes("_64") || tag.includes("amd64")) { if (!tag.includes("linux")) { emojiText += "💻"; } else { diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index e3fb47ef3b5180..2d297b1370a32e 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -11104,7 +11104,7 @@ pub const Chunk = struct { .chunk, .asset => { const index = piece.index.index; const file_path = switch (piece.index.kind) { - .asset => graph.additional_output_files.items[additional_files[index].last().?.output_file].src_path.text, + .asset => graph.additional_output_files.items[additional_files[index].last().?.output_file].dest_path, .chunk => chunks[index].final_rel_path, else => unreachable, }; @@ -11155,7 +11155,7 @@ pub const Chunk = struct { .asset => { shift.before.advance(unique_key_for_additional_files[index]); const file = graph.additional_output_files.items[additional_files[index].last().?.output_file]; - break :brk file.src_path.text; + break :brk file.dest_path; }, .chunk => { const piece_chunk = chunks[index]; @@ -11589,7 +11589,7 @@ fn cheapPrefixNormalizer(prefix: []const u8, suffix: []const u8) [2]string { if (strings.endsWithChar(prefix, '/')) { if (strings.startsWithChar(suffix, '/')) { return .{ - prefix[0 .. prefix.len - 1], + prefix[0..prefix.len], suffix[1..suffix.len], }; } diff --git a/src/cli/build_command.zig b/src/cli/build_command.zig index d1c058b1a5e87e..0c696f714b9971 100644 --- a/src/cli/build_command.zig +++ b/src/cli/build_command.zig @@ -35,6 +35,21 @@ const BundleV2 = @import("../bundler/bundle_v2.zig").BundleV2; var estimated_input_lines_of_code_: usize = undefined; pub const BuildCommand = struct { + const compile_define_keys = &.{ + "process.platform", + "process.arch", + }; + + const compile_define_values = &.{ + "\"" ++ Environment.os.nameString() ++ "\"", + + switch (@import("builtin").target.cpu.arch) { + .x86_64 => "\"x64\"", + .aarch64 => "\"arm64\"", + else => @compileError("TODO"), + }, + }; + pub fn exec( ctx: Command.Context, ) !void { @@ -47,6 +62,25 @@ pub const BuildCommand = struct { ctx.args.target = .bun; } + if (ctx.bundler_options.compile) { + if (ctx.args.define == null) { + ctx.args.define = .{ + .keys = compile_define_keys, + .values = compile_define_values, + }; + } else if (ctx.args.define) |*define| { + var keys = try std.ArrayList(string).initCapacity(bun.default_allocator, compile_define_keys.len + define.keys.len); + keys.appendSliceAssumeCapacity(compile_define_keys); + keys.appendSliceAssumeCapacity(define.keys); + var values = try std.ArrayList(string).initCapacity(bun.default_allocator, compile_define_values.len + define.values.len); + values.appendSliceAssumeCapacity(compile_define_values); + values.appendSliceAssumeCapacity(define.values); + + define.keys = keys.items; + define.values = values.items; + } + } + var this_bundler = try bundler.Bundler.init(allocator, log, ctx.args, null); this_bundler.options.source_map = options.SourceMapOption.fromApi(ctx.args.source_map); diff --git a/src/js_ast.zig b/src/js_ast.zig index 227278b62bbf89..d0ad8ff66e2fa4 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -567,21 +567,30 @@ pub const SlotCounts = struct { } }; +const char_freq_count = 64; pub const CharAndCount = struct { char: u8 = 0, count: i32 = 0, index: usize = 0, - pub const Array = [64]CharAndCount; + pub const Array = [char_freq_count]CharAndCount; pub fn lessThan(_: void, a: CharAndCount, b: CharAndCount) bool { - return a.count > b.count or (a.count == b.count and a.index < b.index); + if (a.count != b.count) { + return a.count > b.count; + } + + if (a.index != b.index) { + return a.index < b.index; + } + + return a.char < b.char; } }; pub const CharFreq = struct { - const Vector = @Vector(64, i32); - const Buffer = [64]i32; + const Vector = @Vector(char_freq_count, i32); + const Buffer = [char_freq_count]i32; freqs: Buffer align(1) = undefined, @@ -601,7 +610,7 @@ pub const CharFreq = struct { // https://zig.godbolt.org/z/P5dPojWGK var freqs = out.*; defer out.* = freqs; - var deltas: [255]i32 = [_]i32{0} ** 255; + var deltas: [256]i32 = [_]i32{0} ** 256; var remain = text; bun.assert(remain.len >= scan_big_chunk_size); @@ -613,8 +622,7 @@ pub const CharFreq = struct { while (unrolled_ptr != remain_end) : (unrolled_ptr += scan_big_chunk_size) { const chunk = unrolled_ptr[0..scan_big_chunk_size].*; - comptime var i: usize = 0; - inline while (i < scan_big_chunk_size) : (i += scan_big_chunk_size) { + inline for (0..scan_big_chunk_size) |i| { deltas[@as(usize, chunk[i])] += delta; } } @@ -631,7 +639,7 @@ pub const CharFreq = struct { } fn scanSmall(out: *align(1) Buffer, text: string, delta: i32) void { - var freqs: [64]i32 = out.*; + var freqs: [char_freq_count]i32 = out.*; defer out.* = freqs; for (text) |c| { @@ -649,30 +657,29 @@ pub const CharFreq = struct { pub fn include(this: *CharFreq, other: CharFreq) void { // https://zig.godbolt.org/z/Mq8eK6K9s - var left: @Vector(64, i32) = this.freqs; - defer this.freqs = left; - const right: @Vector(64, i32) = other.freqs; + const left: @Vector(char_freq_count, i32) = this.freqs; + const right: @Vector(char_freq_count, i32) = other.freqs; - left += right; + this.freqs = left + right; } pub fn compile(this: *const CharFreq, allocator: std.mem.Allocator) NameMinifier { - var array: CharAndCount.Array = brk: { + const array: CharAndCount.Array = brk: { var _array: CharAndCount.Array = undefined; - const freqs = this.freqs; - for (&_array, NameMinifier.default_tail, &freqs, 0..) |*dest, char, freq, i| { + for (&_array, NameMinifier.default_tail, this.freqs, 0..) |*dest, char, freq, i| { dest.* = CharAndCount{ .char = char, .index = i, .count = freq, }; } + + std.sort.pdq(CharAndCount, &_array, {}, CharAndCount.lessThan); + break :brk _array; }; - std.sort.pdq(CharAndCount, &array, {}, CharAndCount.lessThan); - var minifier = NameMinifier.init(allocator); minifier.head.ensureTotalCapacityPrecise(NameMinifier.default_head.len) catch unreachable; minifier.tail.ensureTotalCapacityPrecise(NameMinifier.default_tail.len) catch unreachable; @@ -711,9 +718,9 @@ pub const NameMinifier = struct { while (i > 0) { i -= 1; - j = @as(usize, @intCast(@mod(i, 64))); + j = @as(usize, @intCast(@mod(i, char_freq_count))); try name.appendSlice(this.tail.items[j .. j + 1]); - i = @divFloor(i, 64); + i = @divFloor(i, char_freq_count); } } @@ -726,9 +733,9 @@ pub const NameMinifier = struct { while (i > 0) { i -= 1; - j = @as(usize, @intCast(@mod(i, 64))); + j = @as(usize, @intCast(@mod(i, char_freq_count))); try name.appendSlice(default_tail[j .. j + 1]); - i = @divFloor(i, 64); + i = @divFloor(i, char_freq_count); } return name.items; diff --git a/src/js_parser.zig b/src/js_parser.zig index 3ff5cb1992e237..af154af1d32af9 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -22970,6 +22970,7 @@ fn NewParser_( // Only enable during bundling .commonjs_named_exports_deoptimized = !opts.bundle, }; + this.lexer.track_comments = opts.features.minify_identifiers; this.unwrap_all_requires = brk: { if (opts.bundle) { diff --git a/test/bundler/bundler_compile.test.ts b/test/bundler/bundler_compile.test.ts index 1fdada5873270b..842a7a8609e95e 100644 --- a/test/bundler/bundler_compile.test.ts +++ b/test/bundler/bundler_compile.test.ts @@ -2,6 +2,7 @@ import assert from "assert"; import dedent from "dedent"; import { ESBUILD, itBundled, testForFile } from "./expectBundled"; import { Database } from "bun:sqlite"; +import { fillRepeating } from "harness"; var { describe, test, expect } = testForFile(import.meta.path); describe("bundler", () => { @@ -186,6 +187,60 @@ describe("bundler", () => { }, compile: true, }); + for (const minify of [true, false] as const) { + itBundled("compile/platform-specific-binary" + (minify ? "-minify" : ""), { + minifySyntax: minify, + target: "bun", + compile: true, + files: { + "/entry.ts": /* js */ ` + await import(\`./platform.\${process.platform}.\${process.arch}.js\`); + `, + [`/platform.${process.platform}.${process.arch}.js`]: `console.log("${process.platform}", "${process.arch}");`, + }, + run: { stdout: `${process.platform} ${process.arch}` }, + }); + for (const sourceMap of ["external", "inline", "none"] as const) { + // https://github.com/oven-sh/bun/issues/10344 + itBundled("compile/10344+sourcemap=" + sourceMap + (minify ? "+minify" : ""), { + minifyIdentifiers: minify, + minifySyntax: minify, + minifyWhitespace: minify, + target: "bun", + sourceMap, + compile: true, + files: { + "/entry.ts": /* js */ ` + import big from './generated.big.binary' with {type: "file"}; + import small from './generated.small.binary' with {type: "file"}; + import fs from 'fs'; + fs.readFileSync(big).toString("hex"); + await Bun.file(big).arrayBuffer(); + fs.readFileSync(small).toString("hex"); + await Bun.file(small).arrayBuffer(); + console.log("PASS"); + `, + "/generated.big.binary": (() => { + // make sure the size is not divisible by 32 + const buffer = new Uint8ClampedArray(4096 + (32 - 2)); + for (let i = 0; i < buffer.length; i++) { + buffer[i] = i; + } + return buffer; + })(), + "/generated.small.binary": (() => { + // make sure the size is less than 32 + const buffer = new Uint8ClampedArray(31); + for (let i = 0; i < buffer.length; i++) { + buffer[i] = i; + } + return buffer; + })(), + }, + run: { stdout: "PASS" }, + }); + } + } itBundled("compile/EmbeddedSqlite", { compile: true, files: { diff --git a/test/bundler/esbuild/splitting.test.ts b/test/bundler/esbuild/splitting.test.ts index fbf5634fe78e92..69cdf712b26c23 100644 --- a/test/bundler/esbuild/splitting.test.ts +++ b/test/bundler/esbuild/splitting.test.ts @@ -541,14 +541,13 @@ describe("bundler", () => { }, }); itBundled("splitting/PublicPathEntryName", { - todo: true, files: { "/a.js": `import("./b")`, "/b.js": `console.log('b')`, }, outdir: "/out", splitting: true, - publicPath: "/www", + publicPath: "/www/", onAfterBundle(api) { const t = new Bun.Transpiler(); const imports = t.scanImports(api.readFile("/out/a.js")); diff --git a/test/harness.ts b/test/harness.ts index a9d6276509785e..2d00ec8d631f01 100644 --- a/test/harness.ts +++ b/test/harness.ts @@ -20,8 +20,8 @@ export const bunEnv: NodeJS.ProcessEnv = { TZ: "Etc/UTC", CI: "1", BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0", - BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: '1', - BUN_GARBAGE_COLLECTOR_LEVEL: process.env.BUN_GARBAGE_COLLECTOR_LEVEL || '0', + BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "1", + BUN_GARBAGE_COLLECTOR_LEVEL: process.env.BUN_GARBAGE_COLLECTOR_LEVEL || "0", }; if (isWindows) {