diff options
author | 2021-09-23 19:20:07 -0700 | |
---|---|---|
committer | 2021-09-23 19:20:07 -0700 | |
commit | 58e88c4aed433c0570947d51a7525e69e44f0247 (patch) | |
tree | 7e2c1365a1f8fee1761e6dfe7c97172c5a5a4a05 | |
parent | 843391934202dbfc6113a985dd5b127db5850ca5 (diff) | |
download | bun-58e88c4aed433c0570947d51a7525e69e44f0247.tar.gz bun-58e88c4aed433c0570947d51a7525e69e44f0247.tar.zst bun-58e88c4aed433c0570947d51a7525e69e44f0247.zip |
When bundling, parse the JSON to verify correctness, but print it as a string for better runtime performance
-rw-r--r-- | src/bundler.zig | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/src/bundler.zig b/src/bundler.zig index 0379dc73a..2240d9115 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -1302,7 +1302,9 @@ pub fn NewBundler(cache_files: bool) type { js_ast.Symbol{ .original_name = "exports" }, js_ast.Symbol{ .original_name = "module" }, js_ast.Symbol{ .original_name = "CONGRATS_YOU_FOUND_A_BUG" }, + js_ast.Symbol{ .original_name = "$$bun_runtime_json_parse" }, }; + const json_parse_string = "parse"; var json_ast_symbols_list = std.mem.span(&json_ast_symbols); threadlocal var override_file_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; @@ -1356,6 +1358,10 @@ pub fn NewBundler(cache_files: bool) type { }, ); } + threadlocal var json_e_string: js_ast.E.String = undefined; + threadlocal var json_e_call: js_ast.E.Call = undefined; + threadlocal var json_e_identifier: js_ast.E.Identifier = undefined; + threadlocal var json_call_args: [1]js_ast.Expr = undefined; pub fn processFile(this: *GenerateNodeModuleBundle, worker: *ThreadPool.Worker, _resolve: _resolver.Result) !void { const resolve = _resolve; if (resolve.is_external) return; @@ -1588,8 +1594,24 @@ pub fn NewBundler(cache_files: bool) type { } }, .json => { - var expr = json_parser.ParseJSON(&source, worker.data.log, worker.allocator) catch return; - if (expr.data != .e_missing) { + // parse the JSON _only_ to catch errors at build time. + const parsed_expr = json_parser.ParseJSON(&source, worker.data.log, worker.allocator) catch return; + + if (parsed_expr.data != .e_missing) { + + // Then, we store it as a UTF8 string at runtime + // This is because JavaScript engines are much faster at parsing JSON strings than object literals + json_e_string = js_ast.E.String{ .utf8 = source.contents, .prefer_template = true }; + var json_string_expr = js_ast.Expr{ .data = .{ .e_string = &json_e_string }, .loc = logger.Loc{ .start = 0 } }; + json_call_args[0] = json_string_expr; + json_e_identifier = js_ast.E.Identifier{ .ref = Ref{ .source_index = 0, .inner_index = @intCast(Ref.Int, json_ast_symbols_list.len - 1) } }; + + json_e_call = js_ast.E.Call{ + .target = js_ast.Expr{ .data = .{ .e_identifier = &json_e_identifier }, .loc = logger.Loc{ .start = 0 } }, + .args = std.mem.span(&json_call_args), + }; + const expr = js_ast.Expr{ .data = .{ .e_call = &json_e_call }, .loc = logger.Loc{ .start = 0 } }; + var stmt = js_ast.Stmt.alloc(worker.allocator, js_ast.S.ExportDefault, js_ast.S.ExportDefault{ .value = js_ast.StmtOrExpr{ .expr = expr }, .default_name = js_ast.LocRef{ .loc = logger.Loc{}, .ref = Ref{} }, |