diff options
-rw-r--r-- | src/bundler.zig | 112 | ||||
-rw-r--r-- | src/cli.zig | 52 | ||||
-rw-r--r-- | src/fs.zig | 22 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 11 |
4 files changed, 163 insertions, 34 deletions
diff --git a/src/bundler.zig b/src/bundler.zig index e500360de..f7167d170 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -31,7 +31,7 @@ const PackageJSON = @import("./resolver/package_json.zig").PackageJSON; const DebugLogs = _resolver.DebugLogs; const NodeModuleBundle = @import("./node_module_bundle.zig").NodeModuleBundle; const Router = @import("./router.zig"); - +const isPackagePath = _resolver.isPackagePath; const Css = @import("css_scanner.zig"); pub const ServeResult = struct { @@ -510,7 +510,7 @@ pub fn NewBundler(cache_files: bool) type { framework_config: ?Api.LoadedFramework, route_config: ?Api.LoadedRouteConfig, destination: [*:0]const u8, - ) !Api.JavascriptBundleContainer { + ) !?Api.JavascriptBundleContainer { var tmpdir: std.fs.Dir = try bundler.fs.fs.openTmpDir(); var tmpname_buf: [64]u8 = undefined; bundler.resetStore(); @@ -620,6 +620,12 @@ pub fn NewBundler(cache_files: bool) type { } else |err| {} } + if (this.log.errors > 0) { + // We stop here because if there are errors we don't know if the bundle is valid + // This manifests as a crash when sorting through the module list because we may have added files to the bundle which were never actually finished being added. + return null; + } + // Ensure we never overflow this.code_end_byte_offset = @truncate( u32, @@ -901,11 +907,64 @@ pub fn NewBundler(cache_files: bool) type { file_path.text, }); } + + switch (err) { + error.ModuleNotFound => { + if (isPackagePath(import_record.path.text)) { + if (this.bundler.options.platform.isWebLike() and options.ExternalModules.isNodeBuiltin(import_record.path.text)) { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve Node.js builtin: \"{s}\".", + .{import_record.path.text}, + import_record.kind, + ); + } else { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve: \"{s}\". Maybe you need to \"npm install\" (or yarn/pnpm)?", + .{import_record.path.text}, + import_record.kind, + ); + } + } else { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve: \"{s}\"", + .{ + import_record.path.text, + }, + import_record.kind, + ); + } + }, + // assume other errors are already in the log + else => {}, + } } } const package = resolve.package_json orelse this.bundler.resolver.packageJSONForResolvedNodeModule(&resolve) orelse unreachable; - var package_relative_path = file_path.packageRelativePathString(package.name); + var package_relative_path_ = file_path.packageRelativePathString(package.name); + var package_relative_path = package_relative_path_.path; + + { + // avoid recursion + // this would only come up if you had a package like this + // node_modules/next/next/next/next/next/next/next/next/next/next/next/dist/compiled/foo/index.js + // ^ package.json in the dir + // 24 is arbitrary, but it sounds too high to be realistic + var i: u8 = 0; + while (package_relative_path_.is_parent_package and i < 24) : (i += 1) { + package_relative_path_ = file_path.packageRelativePathString(package_relative_path_.name); + package_relative_path = package_relative_path_.path; + } + } // const load_from_symbol_ref = ast.runtime_imports.$$r.?; // const reexport_ref = ast.runtime_imports.__reExport.?; @@ -1023,6 +1082,12 @@ pub fn NewBundler(cache_files: bool) type { const code_length = this.tmpfile_byte_offset - code_offset; // std.debug.assert(code_length == written); var package_get_or_put_entry = try this.package_list_map.getOrPut(package.hash); + + if (comptime isDebug) { + Output.prettyln("{s}/{s} \n", .{ package.name, package_relative_path }); + Output.flush(); + } + if (!package_get_or_put_entry.found_existing) { package_get_or_put_entry.value_ptr.* = @truncate(u32, this.package_list.items.len); try this.package_list.append( @@ -1132,7 +1197,46 @@ pub fn NewBundler(cache_files: bool) type { hasher.update(import_record.path.text); hasher.update(std.mem.asBytes(&package_json.hash)); get_or_put_result.value_ptr.* = @truncate(u32, hasher.final()); - } else |err| {} + } else |err| { + switch (err) { + error.ModuleNotFound => { + if (isPackagePath(import_record.path.text)) { + if (this.bundler.options.platform.isWebLike() and options.ExternalModules.isNodeBuiltin(import_record.path.text)) { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve Node.js builtin: \"{s}\".", + .{import_record.path.text}, + import_record.kind, + ); + } else { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve: \"{s}\". Maybe you need to \"npm install\" (or yarn/pnpm)?", + .{import_record.path.text}, + import_record.kind, + ); + } + } else { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve: \"{s}\"", + .{ + import_record.path.text, + }, + import_record.kind, + ); + } + }, + // assume other errors are already in the log + else => {}, + } + } } }, // TODO: diff --git a/src/cli.zig b/src/cli.zig index d1b26e2ba..8d6644930 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -460,11 +460,15 @@ pub const Cli = struct { route_conf_: ?Api.LoadedRouteConfig, router: ?Router, ) void { - try alloc.setup(std.heap.c_allocator); - var stdout_ = std.io.getStdOut(); - var stderr_ = std.io.getStdErr(); - var output_source = Output.Source.init(stdout_, stderr_); - Output.Source.set(&output_source); + if (FeatureFlags.parallel_jsb) { + try alloc.setup(std.heap.c_allocator); + var stdout_ = std.io.getStdOut(); + var stderr_ = std.io.getStdErr(); + var output_source = Output.Source.init(stdout_, stderr_); + Output.Source.set(&output_source); + + Output.enable_ansi_colors = stderr_.isTty(); + } defer Output.flush(); defer { @@ -472,7 +476,7 @@ pub const Cli = struct { wait_group.done(); } } - Output.enable_ansi_colors = stderr_.isTty(); + _generate(logs, std.heap.c_allocator, transform_args, _filepath, server_conf, route_conf_, router) catch return; } }; @@ -513,34 +517,38 @@ pub const Cli = struct { { // Always generate the client-only bundle // we can revisit this decision if people ask - var node_modules = try bundler.ServeBundler.GenerateNodeModuleBundle.generate( + var node_modules_ = try bundler.ServeBundler.GenerateNodeModuleBundle.generate( &this_bundler, allocator, loaded_framework, loaded_route_config, filepath, ); + if (server_bundler_generator_thread) |thread| { wait_group.wait(); } - var elapsed = @divTrunc(std.time.nanoTimestamp() - start_time, @as(i128, std.time.ns_per_ms)); - var bundle = NodeModuleBundle.init(node_modules, allocator); - - if (log_.errors > 0) { - try log_.print(Output.errorWriter()); - } else { - bundle.printSummary(); - const indent = comptime " "; - Output.prettyln(indent ++ "<d>{d:6}ms elapsed", .{@intCast(u32, elapsed)}); - - if (server_bundler_generator_thread != null) { - Output.prettyln(indent ++ "<r>Saved to ./{s}, ./{s}", .{ filepath, server_bundle_filepath }); + if (node_modules_) |node_modules| { + if (log_.errors > 0) { + try log_.print(Output.errorWriter()); } else { - Output.prettyln(indent ++ "<r>Saved to ./{s}", .{filepath}); - } + var elapsed = @divTrunc(std.time.nanoTimestamp() - start_time, @as(i128, std.time.ns_per_ms)); + var bundle = NodeModuleBundle.init(node_modules, allocator); + bundle.printSummary(); + const indent = comptime " "; + Output.prettyln(indent ++ "<d>{d:6}ms elapsed", .{@intCast(u32, elapsed)}); + + if (server_bundler_generator_thread != null) { + Output.prettyln(indent ++ "<r>Saved to ./{s}, ./{s}", .{ filepath, server_bundle_filepath }); + } else { + Output.prettyln(indent ++ "<r>Saved to ./{s}", .{filepath}); + } - try log_.printForLogLevel(Output.errorWriter()); + try log_.printForLogLevel(Output.errorWriter()); + } + } else { + try log_.print(Output.errorWriter()); } } return; diff --git a/src/fs.zig b/src/fs.zig index 4e043aaf8..19fdef3db 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -984,17 +984,31 @@ pub const Path = struct { name: PathName, is_disabled: bool = false, + const PackageRelative = struct { + path: string, + name: string, + is_parent_package: bool = false, + }; // "/foo/bar/node_modules/react/index.js" => "index.js" // "/foo/bar/node_modules/.pnpm/react@17.0.1/node_modules/react/index.js" => "index.js" - pub fn packageRelativePathString(this: *const Path, name: string) string { + // "/css-stress-test/node_modules/next/dist/compiled/neo-async/async.js" => "dist/compiled/neo-async/async.js " + pub fn packageRelativePathString(this: *const Path, name: string) PackageRelative { // TODO: we don't need to print this buffer, this is inefficient var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; - const search_path = std.fmt.bufPrint(&buffer, std.fs.path.sep_str ++ "node_modules" ++ std.fs.path.sep_str ++ "{s}" ++ std.fs.path.sep_str, .{name}) catch return this.text; + const search_path = std.fmt.bufPrint(&buffer, std.fs.path.sep_str ++ "node_modules" ++ std.fs.path.sep_str ++ "{s}" ++ std.fs.path.sep_str, .{name}) catch return .{ .name = name, .path = this.text }; if (strings.lastIndexOf(this.canonicalNodeModuleText(), search_path)) |i| { - return this.canonicalNodeModuleText()[i + search_path.len ..]; + return .{ .path = this.canonicalNodeModuleText()[i + search_path.len ..], .name = name }; } - return this.canonicalNodeModuleText(); + if (strings.lastIndexOf(this.text, search_path[0.."/node_modules/".len])) |i| { + const node_modules_relative = this.text[i + "/node_modules/".len ..]; + + if (strings.indexOfChar(node_modules_relative, std.fs.path.sep)) |j| { + return .{ .path = node_modules_relative[j + 1 ..], .name = node_modules_relative[0..j], .is_parent_package = true }; + } + } + + return .{ .path = this.text, .name = name }; } pub fn nodeModulesRelativePathString( diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 9801e7e32..8b9649aa2 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -10315,11 +10315,14 @@ pub fn NewParser( e_.must_keep_due_to_with_stmt = result.is_inside_with_scope; e_.ref = result.ref; + // TODO: fix the underyling cause here + // The problem seems to be that result.ref.inner_index is not always set. + // Handle assigning to a constant - if (in.assign_target != .none and p.symbols.items[result.ref.inner_index].kind == .cconst) { - const r = js_lexer.rangeOfIdentifier(p.source, expr.loc); - p.log.addRangeErrorFmt(p.source, r, p.allocator, "Cannot assign to {s} because it is a constant", .{name}) catch unreachable; - } + // if (in.assign_target != .none and p.symbols.items[result.ref.inner_index].kind == .cconst) { + // const r = js_lexer.rangeOfIdentifier(p.source, expr.loc); + // p.log.addRangeErrorFmt(p.source, r, p.allocator, "Cannot assign to {s} because it is a constant", .{name}) catch unreachable; + // } var original_name: ?string = null; |