diff options
author | 2021-06-02 16:39:40 -0700 | |
---|---|---|
committer | 2021-06-02 16:39:40 -0700 | |
commit | da0bb118dc130c42606aa2688298d14060fc4354 (patch) | |
tree | 42a0cde898867175ed41339db2bb3c2d79d43709 /src | |
parent | ddd5ed1cc2e64f151864bd977cedcefa6929fb74 (diff) | |
download | bun-da0bb118dc130c42606aa2688298d14060fc4354.tar.gz bun-da0bb118dc130c42606aa2688298d14060fc4354.tar.zst bun-da0bb118dc130c42606aa2688298d14060fc4354.zip |
HTTP fixes + buffer stdout/in + a little HTTP caching
Former-commit-id: d49df1df573c40fbfa56c475098cc0da789aeffa
Diffstat (limited to 'src')
-rw-r--r-- | src/bundler.zig | 46 | ||||
-rw-r--r-- | src/cli.zig | 2 | ||||
-rw-r--r-- | src/global.zig | 3 | ||||
-rw-r--r-- | src/http.zig | 19 | ||||
-rw-r--r-- | src/js_lexer.zig | 116 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 10 | ||||
-rw-r--r-- | src/linker.zig | 61 | ||||
-rw-r--r-- | src/main.zig | 10 | ||||
-rw-r--r-- | src/options.zig | 16 | ||||
-rw-r--r-- | src/resolver/package_json.zig | 7 | ||||
-rw-r--r-- | src/resolver/resolver.zig | 27 | ||||
-rw-r--r-- | src/runtime.version | 1 | ||||
-rw-r--r-- | src/runtime.zig | 7 | ||||
-rw-r--r-- | src/timer.zig | 18 |
14 files changed, 235 insertions, 108 deletions
diff --git a/src/bundler.zig b/src/bundler.zig index b3ac6fdc1..d7abbd84c 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -25,10 +25,11 @@ const MimeType = @import("./http/mime_type.zig"); const resolve_path = @import("./resolver/resolve_path.zig"); const runtime = @import("./runtime.zig"); const Linker = linker.Linker; +const Timer = @import("./timer.zig"); pub const ServeResult = struct { value: Value, - + free: bool = true, mime_type: MimeType, // Either we: @@ -69,6 +70,7 @@ pub const Bundler = struct { elapsed: i128 = 0, needs_runtime: bool = false, linker: Linker, + timer: Timer = Timer{}, pub const RuntimeCode = @embedFile("./runtime.js"); @@ -137,9 +139,10 @@ pub const Bundler = struct { try bundler.linker.link(file_path, &result); - const output_file = try bundler.print( + var output_file = try bundler.print( result, ); + // output_file.version = if (resolve_result.is_from_node_modules) resolve_result.package_json_version else null; return output_file; } @@ -196,14 +199,15 @@ pub const Bundler = struct { ast: js_ast.Ast, }; - pub var tracing_start: i128 = if (enableTracing) 0 else undefined; + pub fn parse(bundler: *Bundler, path: Fs.Path, loader: options.Loader, dirname_fd: StoredFileDescriptorType) ?ParseResult { if (enableTracing) { - tracing_start = std.time.nanoTimestamp(); + bundler.timer.start(); } defer { if (enableTracing) { - bundler.elapsed += std.time.nanoTimestamp() - tracing_start; + bundler.timer.stop(); + bundler.elapsed += bundler.timer.elapsed; } } var result: ParseResult = undefined; @@ -269,8 +273,9 @@ pub const Bundler = struct { log: *logger.Log, allocator: *std.mem.Allocator, relative_path: string, - extension: string, + _extension: string, ) !ServeResult { + var extension = _extension; var original_resolver_logger = bundler.resolver.log; var original_bundler_logger = bundler.log; @@ -294,14 +299,15 @@ pub const Bundler = struct { var _file: ?std.fs.File = null; // Is it the index file? - if (relative_unrooted_path.len == 1 and relative_unrooted_path[0] == '.') { + if (relative_unrooted_path.len == 0) { // std.mem.copy(u8, &tmp_buildfile_buf, relative_unrooted_path); // std.mem.copy(u8, tmp_buildfile_buf[relative_unrooted_path.len..], "/" // Search for /index.html if (public_dir.openFile("index.html", .{})) |file| { - std.mem.copy(u8, relative_unrooted_path, "index.html"); - relative_unrooted_path = relative_unrooted_path[0.."index.html".len]; + var index_path = "index.html".*; + relative_unrooted_path = &(index_path); _file = file; + extension = "html"; } else |err| {} // Okay is it actually a full path? } else { @@ -319,6 +325,7 @@ pub const Bundler = struct { if (public_dir.openFile(tmp_buildfile_buf[0 .. relative_unrooted_path.len + ".html".len], .{})) |file| { _file = file; + extension = "html"; break; } else |err| {} @@ -337,6 +344,7 @@ pub const Bundler = struct { if (public_dir.openFile(_path, .{})) |file| { const __path = _path; relative_unrooted_path = __path; + extension = "html"; _file = file; break; } else |err| {} @@ -357,14 +365,32 @@ pub const Bundler = struct { } } + if (strings.eqlComptime(relative_path, "__runtime.js")) { + return ServeResult{ + .free = false, + .value = .{ .build = .{ .path = "__runtime.js", .contents = runtime.SourceContent } }, + .mime_type = MimeType.javascript, + }; + } + // We make some things faster in theory by using absolute paths instead of relative paths - const absolute_path = resolve_path.joinAbsStringBuf( + var absolute_path = resolve_path.joinAbsStringBuf( bundler.fs.top_level_dir, &tmp_buildfile_buf, &([_][]const u8{relative_path}), .auto, ); + defer { + js_ast.Expr.Data.Store.reset(); + js_ast.Stmt.Data.Store.reset(); + } + + // If the extension is .js, omit it. + // if (absolute_path.len > ".js".len and strings.eqlComptime(absolute_path[absolute_path.len - ".js".len ..], ".js")) { + // absolute_path = absolute_path[0 .. absolute_path.len - ".js".len]; + // } + const resolved = (try bundler.resolver.resolve(bundler.fs.top_level_dir, absolute_path, .entry_point)); const loader = bundler.options.loaders.get(resolved.path_pair.primary.name.ext) orelse .file; diff --git a/src/cli.zig b/src/cli.zig index 74ba7e252..0ab04eaa3 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -418,7 +418,7 @@ pub const Cli = struct { if (!did_write) { for (result.output_files) |file, i| { - try writer.writeAll(file.contents); + try stdout.unbuffered_writer.writeAll(file.contents); if (i > 0) { _ = try writer.write("\n\n"); } diff --git a/src/global.zig b/src/global.zig index 951b1f4cf..7ef18d25c 100644 --- a/src/global.zig +++ b/src/global.zig @@ -63,7 +63,8 @@ pub const Output = struct { if (isWasm) { return std.io.FixedBufferStream([]u8); } else { - return std.fs.File; + var stdin = std.io.getStdIn(); + return @TypeOf(std.io.bufferedWriter(stdin.writer())); } }; stream: StreamType, diff --git a/src/http.zig b/src/http.zig index 6d09c0961..6789b02c5 100644 --- a/src/http.zig +++ b/src/http.zig @@ -491,7 +491,23 @@ pub const RequestContext = struct { } }, .build => |output| { - defer ctx.bundler.allocator.free(output.contents); + defer { + if (result.free) { + ctx.bundler.allocator.free(output.contents); + } + } + + // The version query string is only included for: + // - The runtime + // - node_modules + // For the runtime, it's a hash of the file contents + // For node modules, it's just the package version from the package.json + // It's safe to assume node_modules are immutable. In practice, they aren't. + // However, a lot of other stuff breaks when node_modules change so it's fine + if (strings.contains(ctx.url.query_string, "v=")) { + ctx.appendHeader("Cache-Control", "public, immutable, max-age=31556952"); + } + if (FeatureFlags.strong_etags_for_built_files) { const strong_etag = std.hash.Wyhash.hash(1, output.contents); const etag_content_slice = std.fmt.bufPrintIntToSlice(strong_etag_buffer[0..49], strong_etag, 16, true, .{}); @@ -680,6 +696,7 @@ pub const Server = struct { .bundler = undefined, }; server.bundler = try Bundler.init(allocator, &server.log, options); + server.bundler.configureLinker(); try server.run(); } diff --git a/src/js_lexer.zig b/src/js_lexer.zig index fef12bf47..bc9ba69fd 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -20,6 +20,17 @@ pub const PropertyModifierKeyword = tables.PropertyModifierKeyword; pub const TypescriptStmtKeyword = tables.TypescriptStmtKeyword; pub const TypeScriptAccessibilityModifier = tables.TypeScriptAccessibilityModifier; +fn utf8ByteSequenceLength(first_byte: u8) u3 { + // The switch is optimized much better than a "smart" approach using @clz + return switch (first_byte) { + 0b0000_0000...0b0111_1111 => 1, + 0b1100_0000...0b1101_1111 => 2, + 0b1110_0000...0b1110_1111 => 3, + 0b1111_0000...0b1111_0111 => 4, + else => 0, + }; +} + fn notimpl() noreturn { Global.panic("not implemented yet!", .{}); } @@ -123,22 +134,22 @@ pub const Lexer = struct { return logger.usize2Loc(self.start); } - inline fn nextCodepointSlice(it: *LexerType) !?[]const u8 { + inline fn nextCodepointSlice(it: *LexerType) []const u8 { @setRuntimeSafety(false); - if (it.current >= it.source.contents.len) { - // without this line, strings cut off one before the last characte - it.end = it.current; - @setRuntimeSafety(false); + // if (it.current >= it.source.contents.len) { + // // without this line, strings cut off one before the last characte + // it.end = it.current; + // @setRuntimeSafety(false); - return null; - } + // return null; + // } - const cp_len = unicode.utf8ByteSequenceLength(it.source.contents[it.current]) catch return Error.UTF8Fail; + const cp_len = utf8ByteSequenceLength(it.source.contents[it.current]); it.end = it.current; it.current += cp_len; - return it.source.contents[it.current - cp_len .. it.current]; + return if (!(it.current > it.source.contents.len)) it.source.contents[it.current - cp_len .. it.current] else ""; } pub fn syntaxError(self: *LexerType) !void { @@ -192,27 +203,29 @@ pub const Lexer = struct { } inline fn nextCodepoint(it: *LexerType) !CodePoint { - const slice = (try it.nextCodepointSlice()) orelse return @as(CodePoint, -1); - - switch (slice.len) { - 1 => return @as(CodePoint, slice[0]), - 2 => return @as(CodePoint, unicode.utf8Decode2(slice) catch unreachable), - 3 => return @as(CodePoint, unicode.utf8Decode3(slice) catch unreachable), - 4 => return @as(CodePoint, unicode.utf8Decode4(slice) catch unreachable), + const slice = it.nextCodepointSlice(); + + return switch (slice.len) { + 0 => -1, + 1 => @as(CodePoint, slice[0]), + 2 => @as(CodePoint, unicode.utf8Decode2(slice) catch unreachable), + 3 => @as(CodePoint, unicode.utf8Decode3(slice) catch unreachable), + 4 => @as(CodePoint, unicode.utf8Decode4(slice) catch unreachable), else => unreachable, - } + }; } /// Look ahead at the next n codepoints without advancing the iterator. /// If fewer than n codepoints are available, then return the remainder of the string. - fn peek(it: *LexerType, n: usize) !string { + fn peek(it: *LexerType, n: usize) string { const original_i = it.current; defer it.current = original_i; var end_ix = original_i; var found: usize = 0; while (found < n) : (found += 1) { - const next_codepoint = (try it.nextCodepointSlice()) orelse return it.source.contents[original_i..]; + const next_codepoint = it.nextCodepointSlice(); + if (next_codepoint.len == 0) break; end_ix += next_codepoint.len; } @@ -963,8 +976,7 @@ pub const Lexer = struct { if (lexer.code_point == '\\') { @setRuntimeSafety(false); - const scan_result = try lexer.scanIdentifierWithEscapes(.private); - lexer.identifier = scan_result.contents; + lexer.identifier = (try lexer.scanIdentifierWithEscapes(.private)).contents; lexer.token = T.t_private_identifier; } else { @setRuntimeSafety(false); @@ -978,8 +990,7 @@ pub const Lexer = struct { try lexer.step(); } if (lexer.code_point == '\\') { - const scan_result = try lexer.scanIdentifierWithEscapes(.private); - lexer.identifier = scan_result.contents; + lexer.identifier = (try lexer.scanIdentifierWithEscapes(.private)).contents; lexer.token = T.t_private_identifier; } else { lexer.token = T.t_private_identifier; @@ -1379,7 +1390,7 @@ pub const Lexer = struct { }, // Handle legacy HTML-style comments '!' => { - if (strings.eqlComptime(try lexer.peek("--".len), "--")) { + if (strings.eqlComptime(lexer.peek("--".len), "--")) { try lexer.addUnsupportedSyntaxError("Legacy HTML comments not implemented yet!"); return; } @@ -1470,9 +1481,10 @@ pub const Lexer = struct { lexer.identifier = scan_result.contents; lexer.token = scan_result.token; } else { - const contents = lexer.raw(); - lexer.identifier = contents; - lexer.token = Keywords.get(contents) orelse T.t_identifier; + // this code is so hot that if you save lexer.raw() into a temporary variable + // it shows up in profiling + lexer.identifier = lexer.raw(); + lexer.token = Keywords.get(lexer.identifier) orelse T.t_identifier; } }, @@ -2534,43 +2546,23 @@ pub const Lexer = struct { }; pub fn isIdentifierStart(codepoint: CodePoint) bool { - switch (codepoint) { - 'a'...'z', 'A'...'Z', '_', '$' => { - return true; - }, - else => { - return false; - }, - } + @setRuntimeSafety(false); + return switch (codepoint) { + 'a'...'z', 'A'...'Z', '_', '$' => true, + else => false, + }; } pub fn isIdentifierContinue(codepoint: CodePoint) bool { @setRuntimeSafety(false); - switch (codepoint) { - '_', '$', '0'...'9', 'a'...'z', 'A'...'Z' => { - return true; - }, - -1 => { - return false; - }, - else => {}, - } - - // All ASCII identifier start code points are listed above - if (codepoint < 0x7F) { - return false; - } - - // ZWNJ and ZWJ are allowed in identifiers - if (codepoint == 0x200C or codepoint == 0x200D) { - return true; - } - - return false; + return switch (codepoint) { + 'a'...'z', 'A'...'Z', '_', '$', '0'...'9', 0x200C, 0x200D => true, + else => false, + }; } pub fn isWhitespace(codepoint: CodePoint) bool { - switch (codepoint) { + return switch (codepoint) { 0x000B, // line tabulation 0x0009, // character tabulation 0x000C, // form feed @@ -2593,13 +2585,9 @@ pub fn isWhitespace(codepoint: CodePoint) bool { 0x205F, // medium mathematical space 0x3000, // ideographic space 0xFEFF, // zero width non-breaking space - => { - return true; - }, - else => { - return false; - }, - } + => true, + else => false, + }; } pub fn isIdentifier(text: string) bool { diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index fcf3450e1..e69c55ea3 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -9838,10 +9838,12 @@ pub const P = struct { } if (p.options.jsx.development) { - // If we leave it as false, we get a warning about not providing a key - // It calls Object.freeze on the array though - // Which is wasteful! Object.freeze is slow. - args[3] = Expr{ .loc = expr.loc, .data = .{ .e_boolean = .{ .value = e_.children.len == 0 } } }; + // is the return type of the first child an array? + // It's dynamic + // Else, it's static + args[3] = Expr{ .loc = expr.loc, .data = .{ .e_boolean = .{ + .value = e_.children.len == 0 or e_.children.len > 1 or std.meta.activeTag(e_.children[0].data) != .e_array, + } } }; var source = p.allocator.alloc(G.Property, 2) catch unreachable; p.recordUsage(p.jsx_filename_ref); diff --git a/src/linker.zig b/src/linker.zig index 63ec7d72b..f9ea44481 100644 --- a/src/linker.zig +++ b/src/linker.zig @@ -90,6 +90,7 @@ pub const Linker = struct { import_record.path = try linker.generateImportPath( source_dir, linker.runtime_source_path, + Runtime.version(), ); result.ast.runtime_import_record_id = @truncate(u32, record_index); result.ast.needs_runtime = true; @@ -124,8 +125,6 @@ pub const Linker = struct { import_record.wrap_with_to_module = true; result.ast.needs_runtime = true; } - - Output.println("{s} ({s}): CommonJS? {d}", .{ import_record.path.text, @tagName(resolved_import.module_type), @boolToInt(resolved_import.shouldAssumeCommonJS(import_record)) }); } else |err| { switch (err) { error.ModuleNotFound => { @@ -179,6 +178,7 @@ pub const Linker = struct { .path = try linker.generateImportPath( source_dir, linker.runtime_source_path, + Runtime.version(), ), .range = logger.Range{ .loc = logger.Loc{ .start = 0 }, .len = 0 }, }; @@ -191,7 +191,7 @@ pub const Linker = struct { threadlocal var relative_path_allocator_buf: [4096]u8 = undefined; threadlocal var relative_path_allocator_buf_loaded: bool = false; - pub fn generateImportPath(linker: *Linker, source_dir: string, source_path: string) !Fs.Path { + pub fn generateImportPath(linker: *Linker, source_dir: string, source_path: string, package_version: ?string) !Fs.Path { if (!relative_path_allocator_buf_loaded) { relative_path_allocator_buf_loaded = true; relative_path_allocator = std.heap.FixedBufferAllocator.init(&relative_path_allocator_buf); @@ -202,8 +202,10 @@ pub const Linker = struct { var pathname = Fs.PathName.init(pretty); var absolute_pathname = Fs.PathName.init(source_path); - if (linker.options.out_extensions.get(absolute_pathname.ext)) |ext| { - absolute_pathname.ext = ext; + if (!linker.options.preserve_extensions) { + if (linker.options.out_extensions.get(absolute_pathname.ext)) |ext| { + absolute_pathname.ext = ext; + } } switch (linker.options.import_path_format) { @@ -222,19 +224,36 @@ pub const Linker = struct { base = base[0..dot]; } - const absolute_url = try relative_paths_list.append( - try std.fmt.allocPrint( - &relative_path_allocator.allocator, - "{s}{s}{s}", - .{ - linker.options.public_url, - base, - absolute_pathname.ext, - }, - ), - ); - - return Fs.Path.initWithPretty(absolute_url, absolute_url); + if (linker.options.append_package_version_in_query_string and package_version != null) { + const absolute_url = try relative_paths_list.append( + try std.fmt.allocPrint( + &relative_path_allocator.allocator, + "{s}{s}{s}?v={s}", + .{ + linker.options.public_url, + base, + absolute_pathname.ext, + package_version.?, + }, + ), + ); + + return Fs.Path.initWithPretty(absolute_url, absolute_url); + } else { + const absolute_url = try relative_paths_list.append( + try std.fmt.allocPrint( + &relative_path_allocator.allocator, + "{s}{s}{s}", + .{ + linker.options.public_url, + base, + absolute_pathname.ext, + }, + ), + ); + + return Fs.Path.initWithPretty(absolute_url, absolute_url); + } }, else => unreachable, @@ -253,7 +272,11 @@ pub const Linker = struct { try linker.enqueueResolveResult(resolve_result); } - import_record.path = try linker.generateImportPath(source_dir, resolve_result.path_pair.primary.text); + import_record.path = try linker.generateImportPath( + source_dir, + resolve_result.path_pair.primary.text, + resolve_result.package_json_version, + ); } pub fn resolveResultHashKey(linker: *Linker, resolve_result: *const Resolver.Resolver.Result) string { diff --git a/src/main.zig b/src/main.zig index 7c6aafaef..d212bf3a7 100644 --- a/src/main.zig +++ b/src/main.zig @@ -30,10 +30,14 @@ pub fn main() anyerror!void { // var root_alloc = std.heap.ArenaAllocator.init(std.heap.raw_c_allocator); // var root_alloc_ = &root_alloc.allocator; try alloc.setup(std.heap.c_allocator); - var stdout: std.fs.File = std.io.getStdOut(); - var stderr: std.fs.File = std.io.getStdErr(); + var stdout_file = std.io.getStdIn(); + var stdout = std.io.bufferedWriter(stdout_file.writer()); + var stderr_file = std.io.getStdErr(); + var stderr = std.io.bufferedWriter(stderr_file.writer()); var output_source = Output.Source.init(stdout, stderr); + defer stdout.flush() catch {}; + defer stderr.flush() catch {}; Output.Source.set(&output_source); - try cli.Cli.start(std.heap.c_allocator, stdout, stderr, MainPanicHandler); + try cli.Cli.start(std.heap.c_allocator, &stdout, &stderr, MainPanicHandler); } diff --git a/src/options.zig b/src/options.zig index 066e22670..17cc147a1 100644 --- a/src/options.zig +++ b/src/options.zig @@ -453,6 +453,14 @@ const TypeScript = struct { parse: bool = false, }; +pub const Timings = struct { + resolver: i128 = 0, + parse: i128 = 0, + print: i128 = 0, + http: i128 = 0, + read_file: i128 = 0, +}; + pub const BundleOptions = struct { footer: string = "", banner: string = "", @@ -469,6 +477,11 @@ pub const BundleOptions = struct { public_dir_handle: ?std.fs.Dir = null, write: bool = false, preserve_symlinks: bool = false, + preserve_extensions: bool = false, + timings: Timings = Timings{}, + + append_package_version_in_query_string: bool = false, + resolve_mode: api.Api.ResolveMode, tsconfig_override: ?string = null, platform: Platform = Platform.browser, @@ -575,6 +588,8 @@ pub const BundleOptions = struct { opts.out_extensions = opts.platform.outExtensions(allocator); if (transform.serve orelse false) { + opts.preserve_extensions = true; + opts.append_package_version_in_query_string = true; opts.resolve_mode = .lazy; var _dirs = [_]string{transform.public_dir orelse opts.public_dir}; opts.public_dir = try fs.absAlloc(allocator, &_dirs); @@ -687,6 +702,7 @@ pub const TransformOptions = struct { pub const OutputFile = struct { path: string, + version: ?string = null, contents: string, }; diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index 303ffc2d4..21f4c0906 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -16,6 +16,7 @@ pub const PackageJSON = struct { source: logger.Source, main_fields: MainFieldMap, module_type: options.ModuleType, + version: string = "", // Present if the "browser" field is present. This field is intended to be // used by bundlers and lets you redirect the paths of certain 3rd-party @@ -81,6 +82,12 @@ pub const PackageJSON = struct { .main_fields = MainFieldMap.init(r.allocator), }; + if (json.asProperty("version")) |version_json| { + if (version_json.expr.asString(r.allocator)) |version_str| { + package_json.version = r.allocator.dupe(u8, version_str) catch unreachable; + } + } + if (json.asProperty("type")) |type_json| { if (type_json.expr.asString(r.allocator)) |type_str| { switch (options.ModuleType.List.get(type_str) orelse options.ModuleType.unknown) { diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index f5ead98a0..edf1bbb6c 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -239,6 +239,8 @@ pub const Resolver = struct { jsx: options.JSX.Pragma = options.JSX.Pragma{}, + package_json_version: ?string = null, + is_external: bool = false, // This is true when the package was loaded from within the node_modules directory. @@ -539,6 +541,7 @@ pub const Resolver = struct { .is_from_node_modules = _result.is_node_module, .module_type = pkg.module_type, .dirname_fd = _result.dirname_fd, + .package_json_version = pkg.version, }; check_relative = false; check_package = false; @@ -556,6 +559,7 @@ pub const Resolver = struct { .diff_case = res.diff_case, .is_from_node_modules = res.is_node_module, .dirname_fd = res.dirname_fd, + .package_json_version = res.package_json_version, }; } else if (!check_package) { return null; @@ -604,6 +608,7 @@ pub const Resolver = struct { .dirname_fd = node_module.dirname_fd, .diff_case = node_module.diff_case, .is_from_node_modules = true, + .package_json_version = package_json.version, }; } } else { @@ -625,6 +630,7 @@ pub const Resolver = struct { .diff_case = res.diff_case, .is_from_node_modules = res.is_node_module, .dirname_fd = res.dirname_fd, + .package_json_version = res.package_json_version, }; } else { // Note: node's "self references" are not currently supported @@ -640,6 +646,7 @@ pub const Resolver = struct { const pkg_json = dir_info.package_json orelse continue; const rel_path = r.fs.relative(pkg_json.source.key_path.text, path.text); result.module_type = pkg_json.module_type; + result.package_json_version = if (result.package_json_version == null) pkg_json.version else result.package_json_version; if (r.checkBrowserMap(pkg_json, rel_path)) |remapped| { if (remapped.len == 0) { path.is_disabled = true; @@ -1048,6 +1055,7 @@ pub const Resolver = struct { dirname_fd: StoredFileDescriptorType = 0, file_fd: StoredFileDescriptorType = 0, is_node_module: bool = false, + package_json_version: ?string = null, diff_case: ?Fs.FileSystem.Entry.Lookup.DifferentCase = null, }; @@ -1271,6 +1279,7 @@ pub const Resolver = struct { .path_pair = PathPair{ .primary = _path, }, + .package_json_version = browser_json.version, }; } @@ -1342,6 +1351,7 @@ pub const Resolver = struct { .path_pair = PathPair{ .primary = _path, }, + .package_json_version = browser_json.version, }; } @@ -1392,9 +1402,11 @@ pub const Resolver = struct { } const dir_info = (r.dirInfoCached(path) catch null) orelse return null; + var package_json_version: ?string = null; // Try using the main field(s) from "package.json" if (dir_info.package_json) |pkg_json| { + package_json_version = pkg_json.version; if (pkg_json.main_fields.count() > 0) { const main_field_values = pkg_json.main_fields; const main_field_keys = r.opts.main_fields; @@ -1455,6 +1467,7 @@ pub const Resolver = struct { }, .diff_case = auto_main_result.diff_case, .dirname_fd = auto_main_result.dirname_fd, + .package_json_version = pkg_json.version, }; } else { if (r.debug_logs) |*debug| { @@ -1464,8 +1477,9 @@ pub const Resolver = struct { pkg_json.source.key_path.text, }) catch {}; } - - return auto_main_result; + var _auto_main_result = auto_main_result; + _auto_main_result.package_json_version = pkg_json.version; + return _auto_main_result; } } } @@ -1474,7 +1488,14 @@ pub const Resolver = struct { } // Look for an "index" file with known extensions - return r.loadAsIndexWithBrowserRemapping(dir_info, path, extension_order); + if (r.loadAsIndexWithBrowserRemapping(dir_info, path, extension_order)) |*res| { + if (res.package_json_version == null and package_json_version != null) { + res.package_json_version = package_json_version; + } + return res.*; + } + + return null; } pub fn loadAsFile(r: *Resolver, path: string, extension_order: []const string) ?LoadResult { diff --git a/src/runtime.version b/src/runtime.version new file mode 100644 index 000000000..9a0793a08 --- /dev/null +++ b/src/runtime.version @@ -0,0 +1 @@ +6c20b700cd52b930
\ No newline at end of file diff --git a/src/runtime.zig b/src/runtime.zig index e378395ab..8f97718d8 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -1,10 +1,13 @@ const options = @import("./options.zig"); usingnamespace @import("ast/base.zig"); usingnamespace @import("global.zig"); - +const std = @import("std"); pub const SourceContent = @embedFile("./runtime.js"); - pub const Runtime = struct { + pub var version_hash = @embedFile("./runtime.version"); + pub fn version() string { + return version_hash; + } pub const Features = packed struct { react_fast_refresh: bool = false, hot_module_reloading: bool = false, diff --git a/src/timer.zig b/src/timer.zig new file mode 100644 index 000000000..cf56cc6ec --- /dev/null +++ b/src/timer.zig @@ -0,0 +1,18 @@ +const std = @import("std"); + +const Timer = @This(); + +begin: i128 = 0, +elapsed: i128 = 0, + +pub fn start(timer: *Timer) void { + timer.begin = std.time.nanoTimestamp(); +} + +pub fn stop(timer: *Timer) void { + timer.elapsed = std.time.nanoTimestamp() - timer.begin; +} + +pub fn seconds(timer: *const Timer) f64 { + return @intToFloat(f64, timer.elapsed) / std.time.ns_per_s; +} |