diff options
author | 2021-08-12 02:00:25 -0700 | |
---|---|---|
committer | 2021-08-12 02:00:25 -0700 | |
commit | 4d61ce4dd7d0e83e5ef71048874b86a8c9fdd4af (patch) | |
tree | affeb9207efc63e4915e85b78f6ce99d7b6486ad /src | |
parent | 3becf2d8018d92bd7eea389a9954020730cd8cac (diff) | |
download | bun-4d61ce4dd7d0e83e5ef71048874b86a8c9fdd4af.tar.gz bun-4d61ce4dd7d0e83e5ef71048874b86a8c9fdd4af.tar.zst bun-4d61ce4dd7d0e83e5ef71048874b86a8c9fdd4af.zip |
FIx .jsb when bundling packages that have multiple nested package.json
Former-commit-id: 1567dafa8c7bbe97c34e42c86995bd193eeeb6d5
Diffstat (limited to 'src')
-rw-r--r-- | src/bundler.zig | 128 | ||||
-rw-r--r-- | src/fs.zig | 2 | ||||
-rw-r--r-- | src/resolver/resolver.zig | 14 |
3 files changed, 57 insertions, 87 deletions
diff --git a/src/bundler.zig b/src/bundler.zig index f7167d170..5d1a91370 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -794,6 +794,30 @@ pub fn NewBundler(cache_files: bool) type { generator.tmpfile_byte_offset += @truncate(u32, bytes.len); } + const BundledModuleData = struct { + import_path: string, + package_path: string, + package: *const PackageJSON, + module_id: u32, + + pub fn get(this: *GenerateNodeModuleBundle, resolve_result: *const _resolver.Result) ?BundledModuleData { + const package_json: *const PackageJSON = this.bundler.resolver.rootNodeModulePackageJSON(resolve_result) orelse return null; + const package_base_path = package_json.source.path.name.dirWithTrailingSlash(); + const import_path = resolve_result.path_pair.primary.text[package_base_path.len..]; + const package_path = resolve_result.path_pair.primary.text[package_base_path.len - package_json.name.len - 1 ..]; + var hasher = std.hash.Wyhash.init(0); + hasher.update(import_path); + hasher.update(std.mem.asBytes(&package_json.hash)); + + return BundledModuleData{ + .import_path = import_path, + .package_path = package_path, + .package = package_json, + .module_id = @truncate(u32, hasher.final()), + }; + } + }; + fn processImportRecord(this: *GenerateNodeModuleBundle, import_record: ImportRecord) !void {} const node_module_root_string = std.fs.path.sep_str ++ "node_modules" ++ std.fs.path.sep_str; threadlocal var package_key_buf: [512]u8 = undefined; @@ -810,6 +834,8 @@ pub fn NewBundler(cache_files: bool) type { var file_path = resolve.path_pair.primary; var hasher = std.hash.Wyhash.init(0); + var module_data: BundledModuleData = undefined; + // If we're in a node_module, build that almost normally if (is_from_node_modules) { switch (loader) { @@ -859,46 +885,15 @@ pub fn NewBundler(cache_files: bool) type { const absolute_path = resolved_import.path_pair.primary.text; const get_or_put_result = try this.resolved_paths.getOrPut(absolute_path); - const package_json: *const PackageJSON = (resolved_import.package_json orelse (this.bundler.resolver.packageJSONForResolvedNodeModule(resolved_import) orelse { - this.log.addWarningFmt( - &source, - import_record.range.loc, - this.allocator, - "Failed to find package.json for \"{s}\". This will be unresolved and might break at runtime. If it's external, you could add it to the external list.", - .{ - resolved_import.path_pair.primary.text, - }, - ) catch {}; - continue; - })); - - const package_relative_path = bundler.fs.relative( - package_json.source.path.name.dirWithTrailingSlash(), - resolved_import.path_pair.primary.text, - ); - - // trim node_modules/${package.name}/ from the string to save space - // This reduces metadata size by about 30% for a large-ish file - // A future optimization here could be to reuse the string from the original path - import_record.path = Fs.Path.init( - package_relative_path, - ); - - if (get_or_put_result.found_existing) { - import_record.module_id = get_or_put_result.value_ptr.*; - import_record.is_bundled = true; - continue; - } - - hasher = std.hash.Wyhash.init(0); - hasher.update(import_record.path.text); - hasher.update(std.mem.asBytes(&package_json.hash)); - - import_record.module_id = @truncate(u32, hasher.final()); - get_or_put_result.value_ptr.* = import_record.module_id; + module_data = BundledModuleData.get(this, resolved_import) orelse continue; + import_record.module_id = module_data.module_id; import_record.is_bundled = true; + import_record.path = Fs.Path.init(module_data.import_path); + get_or_put_result.value_ptr.* = import_record.module_id; - try this.resolve_queue.writeItem(_resolved_import.*); + if (!get_or_put_result.found_existing) { + try this.resolve_queue.writeItem(_resolved_import.*); + } } else |err| { if (comptime isDebug) { Output.prettyErrorln("\n<r><red>{s}<r> on resolving \"{s}\" from \"{s}\"", .{ @@ -949,22 +944,10 @@ pub fn NewBundler(cache_files: bool) type { } } - 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 = 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; - } - } + module_data = BundledModuleData.get(this, &_resolve) orelse return error.ResolveError; + const module_id = module_data.module_id; + const package = module_data.package; + const package_relative_path = module_data.import_path; // const load_from_symbol_ref = ast.runtime_imports.$$r.?; // const reexport_ref = ast.runtime_imports.__reExport.?; @@ -983,7 +966,7 @@ pub fn NewBundler(cache_files: bool) type { var register_args: [3]Expr = undefined; var package_json_string = E.String{ .utf8 = package.name }; - var module_path_string = E.String{ .utf8 = package_relative_path }; + var module_path_string = E.String{ .utf8 = module_data.import_path }; var target_identifier = E.Identifier{ .ref = register_ref }; var cjs_args: [2]js_ast.G.Arg = undefined; var module_binding = js_ast.B.Identifier{ .ref = ast.module_ref.? }; @@ -1048,10 +1031,6 @@ pub fn NewBundler(cache_files: bool) type { var writer = js_printer.NewFileWriter(this.tmpfile); var symbols: [][]js_ast.Symbol = &([_][]js_ast.Symbol{ast.symbols}); - hasher = std.hash.Wyhash.init(0); - hasher.update(package_relative_path); - hasher.update(std.mem.asBytes(&package.hash)[0..4]); - const module_id = @truncate(u32, hasher.final()); const code_offset = @truncate(u32, try this.tmpfile.getPos()); const written = @truncate( @@ -1170,33 +1149,10 @@ pub fn NewBundler(cache_files: bool) type { // Always enqueue unwalked import paths, but if it's not a node_module, we don't care about the hash try this.resolve_queue.writeItem(_resolved_import.*); - const package_json: *const PackageJSON = (resolved_import.package_json orelse (this.bundler.resolver.packageJSONForResolvedNodeModule(resolved_import) orelse { - this.log.addWarningFmt( - &source, - import_record.range.loc, - this.allocator, - "Failed to find package.json for \"{s}\". This will be unresolved and might break at runtime. If it's external, you could add it to the external list.", - .{ - resolved_import.path_pair.primary.text, - }, - ) catch {}; - continue; - })); - - // It should be the first index, not the last to support bundling multiple of the same package - // This string is printed in the summary. - - const package_relative_path = bundler.fs.relative( - package_json.source.path.name.dirWithTrailingSlash(), - resolved_import.path_pair.primary.text, - ); - - import_record.path = Fs.Path.init(package_relative_path); - - hasher = std.hash.Wyhash.init(0); - hasher.update(import_record.path.text); - hasher.update(std.mem.asBytes(&package_json.hash)); - get_or_put_result.value_ptr.* = @truncate(u32, hasher.final()); + if (BundledModuleData.get(this, resolved_import)) |module| { + import_record.path = Fs.Path.init(module.import_path); + get_or_put_result.value_ptr.* = module.module_id; + } } else |err| { switch (err) { error.ModuleNotFound => { diff --git a/src/fs.zig b/src/fs.zig index 19fdef3db..6a6656fa7 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -984,7 +984,7 @@ pub const Path = struct { name: PathName, is_disabled: bool = false, - const PackageRelative = struct { + pub const PackageRelative = struct { path: string, name: string, is_parent_package: bool = false, diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index 7dc07a5b1..0c97ea6c8 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -827,6 +827,20 @@ pub fn NewResolver(cache_files: bool) type { unreachable; } + const node_module_root_string = std.fs.path.sep_str ++ "node_modules" ++ std.fs.path.sep_str; + + pub fn rootNodeModulePackageJSON( + r: *ThisResolver, + result: *const Result, + ) ?*const PackageJSON { + const absolute = result.path_pair.primary.text; + var end = strings.lastIndexOf(absolute, node_module_root_string) orelse return null; + end += node_module_root_string.len; + end += strings.indexOfChar(absolute[end..], std.fs.path.sep) orelse return null; + + const dir_info = (r.dirInfoCached(absolute[0 .. end + 1]) catch null) orelse return null; + return dir_info.package_json; + } pub fn loadNodeModules(r: *ThisResolver, import_path: string, kind: ast.ImportKind, _dir_info: *DirInfo) ?MatchResult { var res = _loadNodeModules(r, import_path, kind, _dir_info) orelse return null; |