diff options
author | 2021-08-26 15:09:53 -0700 | |
---|---|---|
committer | 2021-08-26 15:09:53 -0700 | |
commit | a6bf54668acf6d0e099e1ffed4f2126887b5a5c8 (patch) | |
tree | 21d202e0840338b76e961208b37b6fc3a0a2ea6f /src | |
parent | 029ba1ea4439dff3943b053848901d0391912037 (diff) | |
download | bun-a6bf54668acf6d0e099e1ffed4f2126887b5a5c8.tar.gz bun-a6bf54668acf6d0e099e1ffed4f2126887b5a5c8.tar.zst bun-a6bf54668acf6d0e099e1ffed4f2126887b5a5c8.zip |
Bug fixes
Former-commit-id: 853b372665a3762b1eeeb2202e279895bce6f544
Diffstat (limited to 'src')
-rw-r--r-- | src/cli.zig | 8 | ||||
-rw-r--r-- | src/http.zig | 145 | ||||
-rw-r--r-- | src/http/mime_type.zig | 5 | ||||
-rw-r--r-- | src/options.zig | 104 |
4 files changed, 152 insertions, 110 deletions
diff --git a/src/cli.zig b/src/cli.zig index b1eb3fe52..2589fbcfc 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -394,8 +394,10 @@ pub const Arguments = struct { }; } - if (entry_points.len == 0 and opts.framework == null and opts.node_modules_bundle_path == null) { - return error.MissingEntryPoint; + if (cmd == .BunCommand or !FeatureFlags.dev_only) { + if (entry_points.len == 0 and opts.framework == null and opts.node_modules_bundle_path == null) { + return error.MissingEntryPoint; + } } opts.output_dir = output_dir; @@ -497,7 +499,7 @@ pub const Command = struct { log: *logger.Log, allocator: *std.mem.Allocator, - pub fn create(allocator: *std.mem.Allocator, log: *logger.Log, comptime command: Command.Tag) !Context { + pub fn create(allocator: *std.mem.Allocator, log: *logger.Log, comptime command: Command.Tag) anyerror!Context { return Command.Context{ .args = try Arguments.parse(allocator, command), .log = log, diff --git a/src/http.zig b/src/http.zig index 3e53b349b..fd23b349d 100644 --- a/src/http.zig +++ b/src/http.zig @@ -454,7 +454,6 @@ pub const RequestContext = struct { pub fn sendJSB(ctx: *RequestContext) !void { const node_modules_bundle = ctx.bundler.options.node_modules_bundle orelse unreachable; - defer ctx.done(); ctx.appendHeader("ETag", node_modules_bundle.bundle.etag); ctx.appendHeader("Content-Type", "text/javascript"); ctx.appendHeader("Cache-Control", "immutable, max-age=99999"); @@ -466,6 +465,8 @@ pub const RequestContext = struct { } } + defer ctx.done(); + const content_length = node_modules_bundle.container.code_length.? - node_modules_bundle.codeStartOffset(); try ctx.writeStatus(200); try ctx.prepareToSendBody(content_length, false); @@ -1158,7 +1159,7 @@ pub const RequestContext = struct { switch (build_result.value) { .fail => { - Output.errorLn( + Output.prettyErrorln( "Error: <b>{s}<r><b>", .{ file_path, @@ -1213,7 +1214,10 @@ pub const RequestContext = struct { } }, else => { - Output.prettyErrorln("<r>[Websocket]: Unknown cmd: <b>{d}<r>. This might be a version mismatch. Try updating your node_modules.jsb", .{@enumToInt(cmd.kind)}); + Output.prettyErrorln( + "<r>[Websocket]: Unknown cmd: <b>{d}<r>. This might be a version mismatch. Try updating your node_modules.bun", + .{@enumToInt(cmd.kind)}, + ); }, } }, @@ -1398,10 +1402,10 @@ pub const RequestContext = struct { } } + defer chunky.rctx.done(); try chunky.rctx.writeStatus(200); try chunky.rctx.prepareToSendBody(buf.len, false); try chunky.rctx.writeBodyBuf(buf); - chunky.rctx.done(); } pub fn flush( @@ -1858,7 +1862,15 @@ pub const Server = struct { try listener.listen(1280); const addr = try listener.getLocalAddress(); - Output.prettyln("<r>Started Bun at <b><cyan>http://{s}<r>", .{addr}); + // This is technically imprecise. + // However, we want to optimize for easy to copy paste + // Nobody should get weird CORS errors when you go to the printed url. + if (std.mem.readIntNative(u32, &addr.ipv4.host.octets) == 0 or std.mem.readIntNative(u128, &addr.ipv6.host.octets) == 0) { + Output.prettyln("<r>Started Bun at <b><cyan>http://localhost:{d}<r>", .{addr.ipv4.port}); + } else { + Output.prettyln("<r>Started Bun at <b><cyan>http://{s}<r>", .{addr}); + } + Output.flush(); // var listener_handle = try std.os.kqueue(); // var change_list = std.mem.zeroes([2]os.Kevent); @@ -1884,8 +1896,13 @@ pub const Server = struct { threadlocal var req_buf: [32_000]u8 = undefined; pub const ConnectionFeatures = struct { - public_folder: bool = false, + public_folder: PublicFolderPriority = PublicFolderPriority.none, filesystem_router: bool = false, + pub const PublicFolderPriority = enum { + none, + first, + last, + }; }; pub fn handleConnection(server: *Server, conn: *tcp.Connection, comptime features: ConnectionFeatures) void { @@ -2005,59 +2022,25 @@ pub const Server = struct { return; }; - if (comptime features.public_folder and features.filesystem_router) { - if (!finished) { - if (req_ctx.matchPublicFolder()) |result| { - finished = true; - req_ctx.renderServeResult(result) catch |err| { - Output.printErrorln("FAIL [{s}] - {s}: {s}", .{ @errorName(err), req.method, req.path }); - did_print = true; - return; - }; - } - } - - if (!finished) { - req_ctx.bundler.router.?.match(server, RequestContext, &req_ctx) catch |err| { - switch (err) { - error.ModuleNotFound => { - req_ctx.sendNotFound() catch {}; - }, - else => { - Output.printErrorln("FAIL [{s}] - {s}: {s}", .{ @errorName(err), req.method, req.path }); - did_print = true; - return; - }, + if (!finished) { + switch (comptime features.public_folder) { + .first => { + if (!finished) { + if (req_ctx.matchPublicFolder()) |result| { + finished = true; + req_ctx.renderServeResult(result) catch |err| { + Output.printErrorln("FAIL [{s}] - {s}: {s}", .{ @errorName(err), req.method, req.path }); + did_print = true; + return; + }; + } } - }; - } - } else if (comptime features.public_folder) { - if (!finished) { - if (req_ctx.matchPublicFolder()) |result| { - finished = true; - req_ctx.renderServeResult(result) catch |err| { - Output.printErrorln("FAIL [{s}] - {s}: {s}", .{ @errorName(err), req.method, req.path }); - did_print = true; - return; - }; - } + }, + else => {}, } + } - if (!finished) { - req_ctx.handleRequest() catch |err| { - switch (err) { - error.ModuleNotFound => { - req_ctx.sendNotFound() catch {}; - }, - else => { - Output.printErrorln("FAIL [{s}] - {s}: {s}", .{ @errorName(err), req.method, req.path }); - did_print = true; - return; - }, - } - }; - } - } else if (comptime features.filesystem_router) { + if (comptime features.filesystem_router) { if (!finished) { req_ctx.bundler.router.?.match(server, RequestContext, &req_ctx) catch |err| { switch (err) { @@ -2088,6 +2071,19 @@ pub const Server = struct { }; } } + + if (comptime features.public_folder == .last) { + if (!finished) { + if (req_ctx.matchPublicFolder()) |result| { + finished = true; + req_ctx.renderServeResult(result) catch |err| { + Output.printErrorln("FAIL [{s}] - {s}: {s}", .{ @errorName(err), req.method, req.path }); + did_print = true; + return; + }; + } + } + } } pub fn initWatcher(server: *Server) !void { @@ -2137,21 +2133,42 @@ pub const Server = struct { try server.initWatcher(); + const public_folder_is_top_level = server.bundler.options.routes.static_dir_enabled and strings.eql( + server.bundler.fs.top_level_dir, + server.bundler.options.routes.static_dir, + ); + if (server.bundler.router != null and server.bundler.options.routes.static_dir_enabled) { - try server.run( - ConnectionFeatures{ .public_folder = true, .filesystem_router = true }, - ); + if (public_folder_is_top_level) { + try server.run( + ConnectionFeatures{ .public_folder = .last, .filesystem_router = true }, + ); + } else { + try server.run( + ConnectionFeatures{ .public_folder = .first, .filesystem_router = true }, + ); + } } else if (server.bundler.router != null) { try server.run( - ConnectionFeatures{ .public_folder = false, .filesystem_router = true }, + ConnectionFeatures{ .filesystem_router = true }, ); } else if (server.bundler.options.routes.static_dir_enabled) { - try server.run( - ConnectionFeatures{ .public_folder = true, .filesystem_router = false }, - ); + if (public_folder_is_top_level) { + try server.run( + ConnectionFeatures{ + .public_folder = .first, + }, + ); + } else { + try server.run( + ConnectionFeatures{ + .public_folder = .last, + }, + ); + } } else { try server.run( - ConnectionFeatures{ .public_folder = false, .filesystem_router = false }, + ConnectionFeatures{ .filesystem_router = false }, ); } } diff --git a/src/http/mime_type.zig b/src/http/mime_type.zig index dc8c40cc2..55d7ec72b 100644 --- a/src/http/mime_type.zig +++ b/src/http/mime_type.zig @@ -30,7 +30,8 @@ pub const css = MimeType.init("text/css", .css); pub const javascript = MimeType.init("text/javascript;charset=utf-8", .javascript); pub const ico = MimeType.init("image/vnd.microsoft.icon", .image); pub const html = MimeType.init("text/html;charset=utf-8", .html); -pub const json = MimeType.init("application/json;charset=utf-8", .json); +// we transpile json to javascript so that it is importable without import assertions. +pub const json = MimeType.init(javascript.value, .json); fn init(comptime str: string, t: Category) MimeType { return MimeType{ @@ -42,7 +43,7 @@ fn init(comptime str: string, t: Category) MimeType { // TODO: improve this pub fn byLoader(loader: Loader, ext: string) MimeType { switch (loader) { - .tsx, .ts, .js, .jsx => { + .tsx, .ts, .js, .jsx, .json => { return javascript; }, .css => { diff --git a/src/options.zig b/src/options.zig index c3069c54e..1c22153bd 100644 --- a/src/options.zig +++ b/src/options.zig @@ -960,52 +960,74 @@ pub const BundleOptions = struct { opts.resolve_mode = .lazy; var dir_to_use: string = opts.routes.static_dir; - const static_dir_set = opts.routes.static_dir_enabled; - - var _dirs = [_]string{dir_to_use}; - opts.routes.static_dir = try fs.absAlloc(allocator, &_dirs); - opts.routes.static_dir_handle = std.fs.openDirAbsolute(opts.routes.static_dir, .{ .iterate = true }) catch |err| brk: { - var did_warn = false; - switch (err) { - error.FileNotFound => { - // Be nice. - // Check "static" since sometimes people use that instead. - // Don't switch to it, but just tell "hey try --public-dir=static" next time - if (!static_dir_set) { - _dirs[0] = "static"; - const check_static = try fs.absAlloc(allocator, &_dirs); - defer allocator.free(check_static); - - std.fs.accessAbsolute(check_static, .{}) catch { - Output.prettyErrorln("warn: \"{s}\" folder missing. If there are external assets used in your project, pass --public-dir=\"public-folder-name\"", .{_dirs[0]}); - did_warn = true; - }; - } + const static_dir_set = !opts.routes.static_dir_enabled; + var disabled_static = false; + + var chosen_dir = dir_to_use; + + if (!static_dir_set) { + chosen_dir = choice: { + if (fs.fs.readDirectory(fs.top_level_dir, null)) |dir_| { + const dir: *const Fs.FileSystem.RealFS.EntriesOption = dir_; + switch (dir.*) { + .entries => { + if (dir.entries.getComptimeQuery("public")) |q| { + if (q.entry.kind(&fs.fs) == .dir) { + break :choice "public"; + } + } + + if (dir.entries.getComptimeQuery("static")) |q| { + if (q.entry.kind(&fs.fs) == .dir) { + break :choice "static"; + } + } - if (!did_warn) { - Output.prettyErrorln("warn: \"{s}\" folder missing. If you want to use \"static\" as the public folder, pass --public-dir=\"static\".", .{_dirs[0]}); + break :choice "."; + }, + else => { + break :choice ""; + }, } - opts.routes.static_dir_enabled = false; - }, - error.AccessDenied => { - Output.prettyErrorln( - "error: access denied when trying to open dir: \"{s}\".\nPlease re-open Bun with access to this folder or pass a different folder via \"--public-dir\". Note: --public-dir is relative to --cwd (or the process' current working directory).\n\nThe public folder is where static assets such as images, fonts, and .html files go.", - .{opts.routes.static_dir}, - ); - std.process.exit(1); - }, - else => { - Output.prettyErrorln( - "error: \"{s}\" when accessing public folder: \"{s}\"", - .{ @errorName(err), opts.routes.static_dir }, - ); - std.process.exit(1); - }, + } else |err| { + break :choice ""; + } + }; + + if (chosen_dir.len == 0) { + disabled_static = true; + opts.routes.static_dir_enabled = false; } + } - break :brk null; - }; + if (!disabled_static) { + var _dirs = [_]string{chosen_dir}; + opts.routes.static_dir = try fs.absAlloc(allocator, &_dirs); + opts.routes.static_dir_handle = std.fs.openDirAbsolute(opts.routes.static_dir, .{ .iterate = true }) catch |err| brk: { + var did_warn = false; + switch (err) { + error.FileNotFound => { + opts.routes.static_dir_enabled = false; + }, + error.AccessDenied => { + Output.prettyErrorln( + "error: access denied when trying to open directory for static files: \"{s}\".\nPlease re-open Bun with access to this folder or pass a different folder via \"--public-dir\". Note: --public-dir is relative to --cwd (or the process' current working directory).\n\nThe public folder is where static assets such as images, fonts, and .html files go.", + .{opts.routes.static_dir}, + ); + std.process.exit(1); + }, + else => { + Output.prettyErrorln( + "error: \"{s}\" when accessing public folder: \"{s}\"", + .{ @errorName(err), opts.routes.static_dir }, + ); + std.process.exit(1); + }, + } + break :brk null; + }; + } // Windows has weird locking rules for file access. // so it's a bad idea to keep a file handle open for a long time on Windows. if (isWindows and opts.routes.static_dir_handle != null) { |