diff options
author | 2021-08-25 17:56:06 -0700 | |
---|---|---|
committer | 2021-08-25 17:56:06 -0700 | |
commit | 454160646923e98f00e53df025e324d3d2c585d0 (patch) | |
tree | 731c5243ac48077ffa1f974dcf46f3bc176792b6 | |
parent | 039bf6ecdb0be85ca78045b647de01bd176823c6 (diff) | |
download | bun-454160646923e98f00e53df025e324d3d2c585d0.tar.gz bun-454160646923e98f00e53df025e324d3d2c585d0.tar.zst bun-454160646923e98f00e53df025e324d3d2c585d0.zip |
latest
Former-commit-id: f5600d123d3710e7ea80ff2b7c66d13382462420
33 files changed, 2867 insertions, 553 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index dd4349d2c..763640c48 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -157,12 +157,12 @@ "program": "${workspaceFolder}/build/debug/macos-x86_64/bun", "args": [ "bun", - "./index.js", + // "./index.js", "--origin=http://localhost:9000/", - // "--use=./bun-framework-next", + "--use=./bun-framework-next", "--platform=browser" ], - "cwd": "${workspaceFolder}/examples/lotta-modules/", + "cwd": "${workspaceFolder}/examples/hello-next/", "console": "internalConsole" }, { @@ -76,7 +76,9 @@ BUN_LLD_FLAGS := $(OBJ_FILES) \ src/deps/picohttpparser.o \ $(CLANG_FLAGS) \ -fpie \ - + +mimalloc: + cd src/deps/mimalloc; cmake .; make; bun-link-lld-debug: clang++ $(BUN_LLD_FLAGS) \ @@ -102,6 +102,41 @@ bun build ./routes --outdir=./out Unlike many other bundlers, `Bun` only bundles `node_modules`. This is great for development, where most people add/update packages much less frequently than app code (which is also great for caching in browsers). To make that distinction clear, the filename defaults to `node_modules.bun`. We recommend storing `node_modules.bun` in your git repository. Since it's a binary file, it shouldn't clutter your git history and it will make your entire frontend development team move faster if they don't have to re-bundle dependencies. +# Building from source + +Estimated: 30-60 minutes :( + +You'll want to start downloading two things at once: + +```bash +git clone https://github.com/jarred-sumner/zig && git checkout jarred/zig-sloppy-with-small-structs +``` + +```bash +git submodule update --init --recursive --progress --depth=1 +``` + +Next, compile Zig. + +On a Mac, that looks like this: + +```bash +cmake . -DCMAKE_PREFIX_PATH=$(brew --prefix llvm) -DZIG_STATIC_LLVM=ON -DCMAKE_BUILD_TYPE=Release && make -j 16 +``` + +Note that `brew install zig` won't work. Bun uses a build of Zig with a couple patches. + +You'll want to make sure `zig` is in `$PATH`. The `zig` binary wil be in the same folder as the newly-cloned `zig` repo. If you use fish, you can run `fish_add_path (pwd)`. + +Now go back to the folder with `Bun`'s repository. + +Run: + +``` +zig build headers +zig build +``` + # Credits - While written in Zig instead of Go, Bun's JS transpiler & CSS lexer source code is based off of @evanw's esbuild project. @evanw did a fantastic job with esbuild. @@ -126,6 +126,7 @@ pub fn build(b: *std.build.Builder) void { javascript.setMainPkgPath(b.pathFromRoot(".")); typings_exe.setMainPkgPath(b.pathFromRoot(".")); exe.setMainPkgPath(b.pathFromRoot(".")); + // exe.want_lto = true; if (!target.getCpuArch().isWasm()) { b.default_step.dependOn(&exe.step); @@ -189,6 +190,8 @@ pub fn build(b: *std.build.Builder) void { b.default_step.dependOn(&exe.step); var steps = [_]*std.build.LibExeObjStep{ exe, javascript, typings_exe, headers_exec }; + // const single_threaded = b.option(bool, "single-threaded", "Build single-threaded") orelse false; + for (steps) |step, i| { step.linkLibC(); step.linkLibCpp(); @@ -201,6 +204,12 @@ pub fn build(b: *std.build.Builder) void { step.addObjectFile("src/deps/libWTF.a"); step.addObjectFile("src/deps/libbmalloc.a"); + step.addObjectFile("src/deps/mimalloc/libmimalloc.a"); + step.addLibPath("src/deps/mimalloc"); + step.addIncludeDir("src/deps/mimalloc"); + + // step.single_threaded = single_threaded; + // We must link ICU statically step.addObjectFile("/usr/local/opt/icu4c/lib/libicudata.a"); step.addObjectFile("/usr/local/opt/icu4c/lib/libicui18n.a"); diff --git a/examples/css-stress-test/pages/_app.tsx b/examples/css-stress-test/pages/_app.tsx index 43d6a776a..47b7ffa56 100644 --- a/examples/css-stress-test/pages/_app.tsx +++ b/examples/css-stress-test/pages/_app.tsx @@ -1,4 +1,4 @@ -import "../src/index.css"; +// import "../src/index.css"; import App from "next/app"; diff --git a/examples/hello-next/babel.js.REMOVED.git-id b/examples/hello-next/babel.js.REMOVED.git-id new file mode 100644 index 000000000..c6e41fc71 --- /dev/null +++ b/examples/hello-next/babel.js.REMOVED.git-id @@ -0,0 +1 @@ +e2e5ce1979cde7a27f105fc408e375bbc6a9d78d
\ No newline at end of file diff --git a/examples/hello-next/bun-framework-next/package.json b/examples/hello-next/bun-framework-next/package.json index 9f12a57a3..fbe7a1d60 100644 --- a/examples/hello-next/bun-framework-next/package.json +++ b/examples/hello-next/bun-framework-next/package.json @@ -1,8 +1,7 @@ { "name": "bun-framework-next", - "version": "0.0.0-8", + "version": "0.0.0-9", "description": "", - "main": "package.json", "framework": { "static": "public", "assetPrefix": "_next/", diff --git a/examples/hello-next/bun-mimalloc.REMOVED.git-id b/examples/hello-next/bun-mimalloc.REMOVED.git-id new file mode 100644 index 000000000..d81da2b9a --- /dev/null +++ b/examples/hello-next/bun-mimalloc.REMOVED.git-id @@ -0,0 +1 @@ +1cfda0305a0e23d0aaf4459029f0b97424d0f22d
\ No newline at end of file diff --git a/examples/hello-next/components/subtitle.tsx b/examples/hello-next/components/subtitle.tsx index 347d97a4d..1fda3db60 100644 --- a/examples/hello-next/components/subtitle.tsx +++ b/examples/hello-next/components/subtitle.tsx @@ -1,3 +1,4 @@ + export default function Hey() { return <div>!!yep</div>; } diff --git a/examples/hello-next/next.config.js b/examples/hello-next/next.config.js index 0d6071006..c161436ab 100644 --- a/examples/hello-next/next.config.js +++ b/examples/hello-next/next.config.js @@ -1,3 +1,10 @@ module.exports = { reactStrictMode: true, -} + typescript: { + // !! WARN !! + // Dangerously allow production builds to successfully complete even if + // your project has type errors. + // !! WARN !! + ignoreBuildErrors: true, + }, +}; diff --git a/examples/hello-next/package.json b/examples/hello-next/package.json index fd803c98a..77ce7b80e 100644 --- a/examples/hello-next/package.json +++ b/examples/hello-next/package.json @@ -5,9 +5,15 @@ "license": "MIT", "dependencies": { "next": "^11.1.0", + "parcel": "2.0.0-rc.0", "path": "^0.12.7", "react": "^17.0.2", "react-dom": "^17.0.2", "whatwg-url": "^9.1.0" + }, + "devDependencies": { + "@babel/standalone": "^7.15.3", + "@types/react": "^17.0.19", + "typescript": "^4.3.5" } } diff --git a/examples/hello-next/pages/index.tsx b/examples/hello-next/pages/index.tsx index b87c67a84..dab661672 100644 --- a/examples/hello-next/pages/index.tsx +++ b/examples/hello-next/pages/index.tsx @@ -3,11 +3,12 @@ import Image from "next/image"; import styles from "../styles/Home.module.css"; import Link from "next/link"; import { useRouter } from "next/router"; - import Title from "../components/Title"; +import React from "react"; export default function Home() { const router = useRouter(); + return ( <div className={styles.container}> <Head> @@ -20,7 +21,7 @@ export default function Home() { <main className={styles.main}> <h1 className={styles.title}> - Welcome to <a href="https://nextjs.org">Next.js!</a> + asdasdasd to <a href="https://nextjs.org">Next.js!</a> </h1> <p className={styles.description}> diff --git a/examples/hello-next/styles/2.css b/examples/hello-next/styles/2.css new file mode 100644 index 000000000..1e30d2166 --- /dev/null +++ b/examples/hello-next/styles/2.css @@ -0,0 +1,3 @@ +* { + background-color: red; +} diff --git a/examples/hello-next/styles/Home.module.css b/examples/hello-next/styles/Home.module.css index 35454bb74..167d5f75b 100644 --- a/examples/hello-next/styles/Home.module.css +++ b/examples/hello-next/styles/Home.module.css @@ -1,3 +1,4 @@ +@import url("./2.css"); .container { min-height: 100vh; padding: 0 0.5rem; @@ -7,7 +8,6 @@ align-items: center; height: 100vh; } - .main { padding: 5rem 0; flex: 1; diff --git a/examples/hello-next/tsconfig.json b/examples/hello-next/tsconfig.json index 679268d71..b423bb201 100644 --- a/examples/hello-next/tsconfig.json +++ b/examples/hello-next/tsconfig.json @@ -18,6 +18,6 @@ "path": ["node_modules/path-browserify"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/index.tsx"], "exclude": ["node_modules"] } diff --git a/examples/lotta-modules/index.js b/examples/lotta-modules/index.js index 12c99a7a7..4968cac4b 100644 --- a/examples/lotta-modules/index.js +++ b/examples/lotta-modules/index.js @@ -1,7 +1,7 @@ import "lodash/_DataView.js"; import "lodash/_Hash.js"; import "lodash/_LazyWrapper.js"; -import "lodash/_ListCache.js"; +import "lodash/_ListCache"; import "lodash/_LodashWrapper.js"; import "lodash/_Map.js"; import "lodash/_MapCache.js"; @@ -631,8 +631,11 @@ import "lodash/xorWith.js"; import "lodash/zip.js"; import "lodash/zipObject.js"; import "lodash/zipObjectDeep.js"; -import "lodash/zipWith.js"; +import "lodash/_setToString"; import "lodash"; +import "lodash/lodash"; import "underscore"; -import "three.js"; +import "three"; + +// import "@babel/standalone/babel.js"; diff --git a/examples/lotta-modules/package.json b/examples/lotta-modules/package.json index 6168008db..6688548da 100644 --- a/examples/lotta-modules/package.json +++ b/examples/lotta-modules/package.json @@ -4,6 +4,7 @@ "main": "index.js", "license": "MIT", "dependencies": { + "@babel/standalone": "^7.15.3", "lodash": "^4.17.21", "three.js": "^0.77.1", "underscore": "^1.13.1" diff --git a/src/api/demo/pages/index.tsx b/src/api/demo/pages/index.tsx index 6f09d0d52..4d60b4084 100644 --- a/src/api/demo/pages/index.tsx +++ b/src/api/demo/pages/index.tsx @@ -1,6 +1,6 @@ import Head from "next/head"; import Image from "next/image"; -// import styles from "../styles/Home.module.css"; +import styles from "../styles/Home.module.css"; import "../lib/api.ts"; export default function Home() { diff --git a/src/bun_queue.zig b/src/bun_queue.zig new file mode 100644 index 000000000..4c289d511 --- /dev/null +++ b/src/bun_queue.zig @@ -0,0 +1,845 @@ +const std = @import("std"); +const Mutex = @import("./lock.zig").Mutex; +const Channel = @import("./sync.zig").Channel; +const WaitGroup = @import("./sync.zig").WaitGroup; +usingnamespace @import("./global.zig"); +const Wyhash = std.hash.Wyhash; +const assert = std.debug.assert; + +const VerboseQueue = false; + +pub fn NewBlockQueue(comptime Value: type, comptime block_size: comptime_int, comptime block_count: usize) type { + return struct { + const BlockQueue = @This(); + const Block = [block_size]Value; + + blocks: [block_count]*Block = undefined, + overflow: std.ArrayList(*Block) = undefined, + first: Block = undefined, + len: std.atomic.Atomic(i32) = std.atomic.Atomic(i32).init(0), + allocated_blocks: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), + + write_lock: bool = false, + overflow_write_lock: bool = false, + overflow_readers: std.atomic.Atomic(u8) = std.atomic.Atomic(u8).init(0), + allocator: *std.mem.Allocator, + empty_queue: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(1), + rand: std.rand.DefaultPrng = std.rand.DefaultPrng.init(100), + + pub fn new(this: *BlockQueue, allocator: *std.mem.Allocator) void { + this.* = BlockQueue{ + .allocator = allocator, + .overflow = std.ArrayList(*Block).init(allocator), + .len = std.atomic.Atomic(i32).init(0), + }; + this.blocks[0] = &this.first; + this.allocator = allocator; + } + + pub fn get(this: *BlockQueue) ?Value { + if (this.len.fetchMax(-1, .SeqCst) <= 0) return null; + + while (@atomicRmw(bool, &this.write_lock, .Xchg, true, .SeqCst)) { + const end = this.rand.random.uintAtMost(u8, 64); + var i: u8 = 0; + while (i < end) : (i += 1) {} + std.atomic.spinLoopHint(); + } + defer assert(@atomicRmw(bool, &this.write_lock, .Xchg, false, .SeqCst)); + + if (this.len.fetchMax(-1, .SeqCst) <= 0) return null; + const current_len_ = this.len.fetchSub(1, .SeqCst); + if (current_len_ <= 0) return null; + + const current_len = @intCast(u32, current_len_); + if (current_len == 0) { + return null; + } + + const current_block = @floatToInt(u32, std.math.floor(@intToFloat(f32, (current_len - 1) / block_size))); + const index = (current_len - 1) % block_size; + + if (comptime VerboseQueue) std.debug.print("[GET] {d}, {d}\n", .{ current_block, index }); + + switch (current_block) { + 0 => { + return this.first[index]; + }, + 1...block_count => { + const ptr = @atomicLoad(*Block, &this.blocks[current_block], .SeqCst); + return ptr[index]; + }, + else => { + const is_overflowing = current_block > block_count; + + unreachable; + }, + } + } + + pub fn enqueue(this: *BlockQueue, value: Value) !void { + while (@atomicRmw(bool, &this.write_lock, .Xchg, true, .SeqCst)) { + const end = this.rand.random.uintAtMost(u8, 32); + var i: u8 = 0; + while (i < end) : (i += 1) {} + std.atomic.spinLoopHint(); + } + defer assert(@atomicRmw(bool, &this.write_lock, .Xchg, false, .SeqCst)); + defer { + const old = this.empty_queue.swap(0, .SeqCst); + if (old == 1) std.Thread.Futex.wake(&this.empty_queue, std.math.maxInt(u32)); + } + + const current_len = @intCast(u32, std.math.max(this.len.fetchAdd(1, .SeqCst), 0)); + const next_len = current_len + 1; + + const current_block = @floatToInt(u32, std.math.floor(@intToFloat(f32, current_len) / block_size)); + const next_block = @floatToInt(u32, std.math.floor(@intToFloat(f32, next_len) / block_size)); + const index = (current_len % block_size); + const next_index = (next_len % block_size); + + if (comptime VerboseQueue) std.debug.print("\n[PUT] {d}, {d} - {d} \n", .{ current_block, index, current_len }); + + const allocated_block = this.allocated_blocks.load(.SeqCst); + const needs_new_block = next_index == 0; + const needs_to_allocate_block = needs_new_block and allocated_block < next_block; + const overflowing = current_block >= block_count; + + if (needs_to_allocate_block) { + defer { + _ = this.allocated_blocks.fetchAdd(1, .SeqCst); + } + var new_list = try this.allocator.create(Block); + if (next_block >= block_count) { + const needs_lock = this.overflow.items.len + 1 >= this.overflow.capacity; + if (needs_lock) { + while (this.overflow_readers.load(.SeqCst) > 0) { + std.atomic.spinLoopHint(); + } + @atomicStore(bool, &this.overflow_write_lock, true, .SeqCst); + } + defer { + if (needs_lock) { + @atomicStore(bool, &this.overflow_write_lock, false, .SeqCst); + } + } + try this.overflow.append(new_list); + } else { + @atomicStore(*Block, &this.blocks[next_block], new_list, .SeqCst); + } + } + + var block_ptr = if (!overflowing) + @atomicLoad(*Block, &this.blocks[current_block], .SeqCst) + else + @atomicLoad(*Block, &this.overflow.items[current_block - block_count], .SeqCst); + + block_ptr[index] = value; + if (current_len < 10) std.Thread.Futex.wake(@ptrCast(*const std.atomic.Atomic(u32), &this.len), std.math.maxInt(u32)); + } + }; +} + +pub fn NewBunQueue(comptime Value: type) type { + return struct { + const KeyType = u32; + const BunQueue = @This(); + const Queue = NewBlockQueue(Value, 64, 48); + // pub const Fifo = NewFifo(Value); + + allocator: *std.mem.Allocator, + queue: Queue, + keys: Keys, + count: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), + + pub fn init(allocator: *std.mem.Allocator) !*BunQueue { + var bun = try allocator.create(BunQueue); + bun.* = BunQueue{ + .allocator = allocator, + .queue = undefined, + .keys = Keys{ + .offset = AtomicOffset.init(Offset.bits(.{ .used = 0, .len = 0 })), + .block_overflow = Keys.OverflowList.init(allocator), + }, + }; + bun.queue.new(allocator); + + bun.keys.blocks[0] = &bun.keys.first_key_list; + return bun; + } + + pub const Keys = struct { + pub const OverflowList = std.ArrayList([*]KeyType); + // Half a page of memory + + blocks: [overflow_size][*]KeyType = undefined, + offset: AtomicOffset, + block_overflow: OverflowList, + block_overflow_lock: bool = false, + first_key_list: [block_size]KeyType = undefined, + mutex: Mutex = Mutex{}, + write_lock: bool = false, + append_readers: u8 = 0, + append_lock: bool = false, + pending_write: KeyType = 0, + }; + + pub const Offset = packed struct { + used: u16, + len: u16, + + pub const Int = std.meta.Int(.unsigned, @bitSizeOf(@This())); + + pub inline fn bits(this: Offset) Int { + return @bitCast(Int, this); + } + }; + + pub const block_size = 2048 / @sizeOf(KeyType); + pub const overflow_size = 32; + + // In one atomic load/store, get the length and offset of the keys + pub const AtomicOffset = std.atomic.Atomic(Offset.Int); + + fn pushList(this: *BunQueue, used: u16) !void { + + // this.keys.mutex.acquire(); + // defer this.keys.mutex.release(); + + var block = try this.allocator.alloc(KeyType, block_size); + + if (used < overflow_size) { + @atomicStore([*]KeyType, &this.keys.blocks[used], block.ptr, .Release); + } else { + const needs_lock = this.keys.block_overflow.items.len + 1 >= this.keys.block_overflow.capacity; + if (needs_lock) { + while (@atomicLoad(u8, &this.keys.append_readers, .SeqCst) > 0) { + std.atomic.spinLoopHint(); + } + @atomicStore(bool, &this.keys.append_lock, true, .SeqCst); + } + defer { + if (needs_lock) @atomicStore(bool, &this.keys.append_lock, false, .SeqCst); + } + try this.keys.block_overflow.append(block.ptr); + } + } + + inline fn contains(this: *BunQueue, key: KeyType) bool { + @fence(.Acquire); + if (@atomicLoad(KeyType, &this.keys.pending_write, .SeqCst) == key) return true; + // this.keys.mutex.tryAcquire() + + var offset = this.getOffset(); + std.debug.assert(&this.keys.first_key_list == this.keys.blocks[0]); + + // Heuristic #1: the first files you import are probably the most common in your app + // e.g. "react" + if (offset.used != 0) { + for (this.keys.first_key_list) |_key| { + if (key == _key) return true; + } + } + + if (offset.used < overflow_size) { + // Heuristic #2: you import files near each other + const block_ptr = @atomicLoad([*]KeyType, &this.keys.blocks[offset.used], .SeqCst); + for (block_ptr[0..offset.len]) |_key| { + if (key == _key) return true; + } + } else { + while (@atomicLoad(bool, &this.keys.append_lock, .SeqCst)) { + std.atomic.spinLoopHint(); + } + _ = @atomicRmw(u8, &this.keys.append_readers, .Add, 1, .SeqCst); + defer { + _ = @atomicRmw(u8, &this.keys.append_readers, .Sub, 1, .SeqCst); + } + const latest = @atomicLoad([*]KeyType, &this.keys.block_overflow.items[offset.used - overflow_size], .SeqCst); + + for (latest[0..offset.len]) |_key| { + if (key == _key) return true; + } + } + + if (offset.used > 0) { + var j: usize = 1; + while (j < std.math.min(overflow_size, offset.used)) : (j += 1) { + const block_ptr = @atomicLoad([*]KeyType, &this.keys.blocks[j], .SeqCst); + for (block_ptr[0..block_size]) |_key| { + if (key == _key) return true; + } + } + + if (offset.used > overflow_size) { + var end = offset.used - overflow_size; + j = 0; + while (j < end) : (j += 1) { + while (@atomicLoad(bool, &this.keys.append_lock, .SeqCst)) { + std.atomic.spinLoopHint(); + } + + _ = @atomicRmw(u8, &this.keys.append_readers, .Add, 1, .SeqCst); + defer { + _ = @atomicRmw(u8, &this.keys.append_readers, .Sub, 1, .SeqCst); + } + + const block = @atomicLoad([*]KeyType, &this.keys.block_overflow.items[j], .SeqCst); + for (block[0..block_size]) |_key| { + if (key == _key) return true; + } + } + } + } + + return @atomicLoad(KeyType, &this.keys.pending_write, .Acquire) == key; + } + + pub inline fn getOffset(this: *BunQueue) Offset { + return @bitCast(Offset, this.keys.offset.load(std.atomic.Ordering.Acquire)); + } + + pub fn hasItem(this: *BunQueue, key: KeyType) bool { + @fence(.SeqCst); + + if (this.contains(key)) return true; + while (@atomicRmw(bool, &this.keys.write_lock, .Xchg, true, .SeqCst)) { + std.atomic.spinLoopHint(); + } + defer assert(@atomicRmw(bool, &this.keys.write_lock, .Xchg, false, .SeqCst)); + + if (@atomicRmw(KeyType, &this.keys.pending_write, .Xchg, key, .SeqCst) == key) return true; + + const offset = this.getOffset(); + + const new_len = (offset.len + 1) % block_size; + const is_new_list = new_len == 0; + const new_offset = Offset{ .used = @intCast(u16, @boolToInt(is_new_list)) + offset.used, .len = new_len }; + + { + var latest_list = if (offset.used < overflow_size) + @atomicLoad([*]KeyType, &this.keys.blocks[offset.used], .SeqCst) + else + @atomicLoad([*]KeyType, &this.keys.block_overflow.items[offset.used - overflow_size], .SeqCst); + + assert(@atomicRmw(KeyType, &latest_list[offset.len], .Xchg, key, .Release) != key); + } + + // We only should need to lock when we're allocating memory + if (is_new_list) { + this.pushList(new_offset.used) catch unreachable; + } + + this.keys.offset.store(new_offset.bits(), .Release); + + return false; + } + + inline fn _writeItem(this: *BunQueue, value: Value) !void { + _ = this.count.fetchAdd(1, .Release); + try this.queue.enqueue(value); + } + + pub fn upsert(this: *BunQueue, key: KeyType, value: Value) !void { + if (!this.hasItem(key)) { + try this._writeItem(value); + } + } + + pub fn upsertWithResult(this: *BunQueue, key: KeyType, value: Value) !bool { + if (!this.hasItem(key)) { + try this._writeItem(value); + return true; + } + + return false; + } + pub inline fn next(this: *BunQueue) ?Value { + return this.queue.get(); + } + }; +} + +test "BunQueue: Single-threaded" { + const BunQueue = NewBunQueue([]const u8); + const hash = Wyhash.hash; + const expect = std.testing.expect; + + var queue = try BunQueue.init(default_allocator); + + var greet = [_]string{ + "hello", "how", "are", "you", + "https://", "ton.local.twitter.com", "/responsive-web-internal/", "sourcemaps", + "/client-web/", "loader.Typeahead.7c3b3805.js.map:", "ERR_BLOCKED_BY_CLIENT", "etch failed loading: POST ", + "ondemand.LottieWeb.08803c45.js", "ondemand.InlinePlayer.4990ef15.js", "ondemand.BranchSdk.bb99d145.js", "ondemand.Dropdown.011d5045.js", + }; + var greeted: [greet.len]bool = undefined; + std.mem.set(bool, &greeted, false); + + for (greet) |ing, i| { + const key = @truncate(u32, hash(0, ing)); + try expect(!queue.contains( + key, + )); + try queue.upsert( + key, + ing, + ); + try expect(queue.hasItem( + key, + )); + try expect(queue.getOffset().len == i + 1); + } + + { + var i: usize = 0; + while (i < greet.len) : (i += 1) { + const item = (queue.next()) orelse return try std.testing.expect(false); + try expect(strings.containsAny(&greet, item)); + const index = strings.indexAny(&greet, item) orelse unreachable; + try expect(!greeted[index]); + greeted[index] = true; + } + i = 0; + while (i < greet.len) : (i += 1) { + try expect(queue.next() == null); + } + i = 0; + while (i < greet.len) : (i += 1) { + try expect(greeted[i]); + } + i = 0; + } + + const end_offset = queue.getOffset().len; + + for (greet) |ing, i| { + const key = @truncate(u32, hash(0, ing)); + try queue.upsert( + key, + ing, + ); + + try expect(end_offset == queue.getOffset().len); + } +} + +test "BunQueue: Dedupes" { + const BunQueue = NewBunQueue([]const u8); + const hash = Wyhash.hash; + const expect = std.testing.expect; + + var queue = try BunQueue.init(default_allocator); + + var greet = [_]string{ + "uniq1", + "uniq2", + "uniq3", + "uniq4", + "uniq5", + "uniq6", + "uniq7", + "uniq8", + "uniq9", + "uniq10", + "uniq11", + "uniq12", + "uniq13", + "uniq14", + "uniq15", + "uniq16", + "uniq17", + "uniq18", + "uniq19", + "uniq20", + "uniq21", + "uniq22", + "uniq23", + "uniq24", + "uniq25", + "uniq26", + "uniq27", + "uniq28", + "uniq29", + "uniq30", + } ++ [_]string{ "dup20", "dup21", "dup27", "dup2", "dup12", "dup15", "dup4", "dup12", "dup10", "dup7", "dup26", "dup22", "dup1", "dup23", "dup11", "dup8", "dup11", "dup29", "dup28", "dup25", "dup20", "dup2", "dup6", "dup16", "dup22", "dup13", "dup30", "dup9", "dup3", "dup17", "dup14", "dup18", "dup8", "dup3", "dup28", "dup30", "dup24", "dup18", "dup24", "dup5", "dup23", "dup10", "dup13", "dup26", "dup27", "dup29", "dup25", "dup4", "dup19", "dup15", "dup6", "dup17", "dup1", "dup16", "dup19", "dup7", "dup9", "dup21", "dup14", "dup5" }; + var prng = std.rand.DefaultPrng.init(100); + prng.random.shuffle(string, &greet); + var deduped = std.BufSet.init(default_allocator); + var consumed = std.BufSet.init(default_allocator); + + for (greet) |ing, i| { + const key = @truncate(u32, hash(0, ing)); + + const is_new = !deduped.contains(ing); + try deduped.insert(ing); + try queue.upsert(key, ing); + } + + while (queue.next()) |i| { + try expect(consumed.contains(i) == false); + try consumed.insert(i); + } + + try std.testing.expectEqual(consumed.count(), deduped.count()); + try expect(deduped.count() > 0); +} + +test "BunQueue: SCMP Threaded" { + const BunQueue = NewBunQueue([]const u8); + const expect = std.testing.expect; + + var _queue = try BunQueue.init(default_allocator); + + var greet = [_]string{ + "uniq1", + "uniq2", + "uniq3", + "uniq4", + "uniq5", + "uniq6", + "uniq7", + "uniq8", + "uniq9", + "uniq10", + "uniq11", + "uniq12", + "uniq13", + "uniq14", + "uniq15", + "uniq16", + "uniq17", + "uniq18", + "uniq19", + "uniq20", + "uniq21", + "uniq22", + "uniq23", + "uniq24", + "uniq25", + "uniq26", + "uniq27", + "uniq28", + "uniq29", + "uniq30", + "uniq31", + "uniq32", + "uniq33", + "uniq34", + "uniq35", + "uniq36", + "uniq37", + "uniq38", + "uniq39", + "uniq40", + "uniq41", + "uniq42", + "uniq43", + "uniq44", + "uniq45", + "uniq46", + "uniq47", + "uniq48", + "uniq49", + "uniq50", + "uniq51", + "uniq52", + "uniq53", + "uniq54", + "uniq55", + "uniq56", + "uniq57", + "uniq58", + "uniq59", + "uniq60", + "uniq61", + "uniq62", + "uniq63", + "uniq64", + "uniq65", + "uniq66", + "uniq67", + "uniq68", + "uniq69", + "uniq70", + "uniq71", + "uniq72", + "uniq73", + "uniq74", + "uniq75", + "uniq76", + "uniq77", + "uniq78", + "uniq79", + "uniq80", + "uniq81", + "uniq82", + "uniq83", + "uniq84", + "uniq85", + "uniq86", + "uniq87", + "uniq88", + "uniq89", + "uniq90", + "uniq91", + "uniq92", + "uniq93", + "uniq94", + "uniq95", + "uniq96", + "uniq97", + "uniq98", + "uniq99", + "uniq100", + "uniq101", + "uniq102", + "uniq103", + "uniq104", + "uniq105", + "uniq106", + "uniq107", + "uniq108", + "uniq109", + "uniq110", + "uniq111", + "uniq112", + "uniq113", + "uniq114", + "uniq115", + "uniq116", + "uniq117", + "uniq118", + "uniq119", + "uniq120", + } ++ [_]string{ "dup1", "dup1", "dup10", "dup10", "dup11", "dup11", "dup12", "dup2", "dup20", "dup20", "dup21", "dup21", "dup22", "dup22", "dup23", "dup23", "dup12", "dup13", "dup13", "dup14", "dup14", "dup15", "dup15", "dup16", "dup16", "dup17", "dup17", "dup18", "dup18", "dup19", "dup19", "dup2", "dup2", "dup20", "dup20", "dup21", "dup21", "dup22", "dup22", "dup23", "dup23", "dup24", "dup24", "dup25", "dup3", "dup30", "dup30", "dup4", "dup4", "dup5", "dup5", "dup6", "dup23", "dup23", "dup12", "dup13", "dup13", "dup14", "dup14", "dup15", "dup15", "dup16", "dup16", "dup17", "dup17", "dup18", "dup18", "dup19", "dup19", "dup2", "dup2", "dup20", "dup20", "dup21", "dup21", "dup22", "dup22", "dup23", "dup23", "dup24", "dup24", "dup6", "dup7", "dup7", "dup8", "dup8", "dup9", "dup9", "dup25", "dup26", "dup26", "dup3", "dup30", "dup30", "dup4", "dup4", "dup5", "dup5", "dup6", "dup6", "dup7", "dup7", "dup8", "dup8", "dup9", "dup9", "dup27", "dup27", "dup28", "dup28", "dup29", "dup29", "dup3", "dup3", "dup30", "dup30", "dup4", "dup4", "dup5", "dup5", "dup6", "dup6", "dup7", "dup7", "dup8", "dup8", "dup9", "dup9" }; + var prng = std.rand.DefaultPrng.init(100); + prng.random.shuffle(string, &greet); + var in = try default_allocator.create(std.BufSet); + in.* = std.BufSet.init(default_allocator); + for (greet) |i| { + try in.insert(i); + try _queue.upsert(@truncate(u32, std.hash.Wyhash.hash(0, i)), i); + } + + const Worker = struct { + index: u8 = 0, + + pub fn run(queue: *BunQueue, dedup_list: *std.BufSet, wg: *WaitGroup, mut: *Mutex) !void { + defer wg.done(); + // const tasks = more_work[num]; + // var remain = tasks; + while (queue.next()) |cur| { + mut.acquire(); + defer mut.release(); + try dedup_list.insert(cur); + } + } + + pub fn run1(queue: *BunQueue, num: u8, dedup_list: *std.BufSet, wg: *WaitGroup, mut: *Mutex) !void { + defer wg.done(); + const tasks = more_work[num]; + var remain = tasks; + try queue.upsert(@truncate(u32, std.hash.Wyhash.hash(0, remain[0])), remain[0]); + remain = tasks[1..]; + loop: while (true) { + while (queue.next()) |cur| { + mut.acquire(); + try dedup_list.insert(cur); + mut.release(); + } + + if (remain.len > 0) { + try queue.upsert(@truncate(u32, std.hash.Wyhash.hash(0, remain[0])), remain[0]); + remain = tasks[1..]; + var j: usize = 0; + while (j < 1000) : (j += 1) {} + continue :loop; + } + + break :loop; + } + } + }; + + var out = try default_allocator.create(std.BufSet); + out.* = std.BufSet.init(default_allocator); + + var waitgroup = try default_allocator.create(WaitGroup); + waitgroup.* = WaitGroup.init(); + + var worker1 = try default_allocator.create(Worker); + worker1.* = Worker{}; + var worker2 = try default_allocator.create(Worker); + worker2.* = Worker{}; + waitgroup.add(); + waitgroup.add(); + var mutex = try default_allocator.create(Mutex); + mutex.* = Mutex{}; + + var thread1 = try std.Thread.spawn(.{}, Worker.run, .{ _queue, out, waitgroup, mutex }); + var thread2 = try std.Thread.spawn(.{}, Worker.run, .{ _queue, out, waitgroup, mutex }); + + waitgroup.wait(); + thread1.join(); + thread2.join(); + + try std.testing.expectEqual(out.count(), in.count()); + var iter = in.hash_map.iterator(); + + while (iter.next()) |entry| { + try expect(in.contains(entry.key_ptr.*)); + } +} + +test "BunQueue: MPMC Threaded" { + const BunQueue = NewBunQueue([]const u8); + const expect = std.testing.expect; + var _queue = try BunQueue.init(default_allocator); + + var in = try default_allocator.create(std.BufSet); + in.* = std.BufSet.init(default_allocator); + + const Worker = struct { + index: u8 = 0, + const WorkerCount = 2; + const lodash_all = shuffle(@TypeOf(@import("./test/project.zig").lodash), @import("./test/project.zig").lodash); + const lodash1 = lodash_all[0 .. lodash_all.len / 3]; + const lodash2 = lodash_all[lodash1.len..][0 .. lodash_all.len / 3]; + const lodash3 = lodash_all[lodash1.len + lodash2.len ..]; + + pub fn shuffle(comptime Type: type, comptime val: Type) Type { + var copy = val; + @setEvalBranchQuota(99999); + var rand = std.rand.DefaultPrng.init(100); + rand.random.shuffle(string, ©); + return copy; + } + const three_all = shuffle(@TypeOf(@import("./test/project.zig").three), @import("./test/project.zig").three); + const three1 = three_all[0 .. three_all.len / 3]; + const three2 = three_all[three1.len..][0 .. three_all.len / 3]; + const three3 = three_all[three1.len + three2.len ..]; + + fn run1(queue: *BunQueue, num: u8, dedup_list: *std.BufSet, wg: *WaitGroup, mut: *Mutex) !void { + defer wg.done(); + const tasks = switch (num) { + 0 => lodash1, + 1 => lodash2, + 2 => lodash3, + 3 => three1, + 4 => three2, + 5 => three3, + else => unreachable, + }; + + var remain = tasks; + try queue.upsert(@truncate(u32, std.hash.Wyhash.hash(0, remain[0])), remain[0]); + remain = tasks[1..]; + loop: while (true) { + while (queue.next()) |cur| { + mut.acquire(); + defer mut.release(); + try expect(!dedup_list.contains(cur)); + try dedup_list.insert(cur); + } + + if (remain.len > 0) { + try queue.upsert(@truncate(u32, std.hash.Wyhash.hash(0, remain[0])), remain[0]); + remain = remain[1..]; + var j: usize = 0; + while (j < 10000) : (j += 1) {} + continue :loop; + } + + break :loop; + } + } + + pub fn run(queue: *BunQueue, num: u8, dedup_list: *std.BufSet, wg: *WaitGroup, mut: *Mutex) !void { + try run1(queue, num, dedup_list, wg, mut); + } + }; + + var greet = [_]string{ + "uniq1", + "uniq2", + "uniq3", + "uniq4", + "uniq5", + "uniq6", + "uniq7", + "uniq8", + "uniq9", + "uniq10", + "uniq11", + "uniq12", + "uniq13", + "uniq14", + "uniq15", + "uniq16", + "uniq17", + "uniq18", + "uniq19", + "uniq20", + "uniq21", + "uniq22", + "uniq23", + "uniq24", + "uniq25", + "uniq26", + "uniq27", + "uniq28", + "uniq29", + "uniq30", + } ++ [_]string{ "dup1", "dup1", "dup10", "dup10", "dup11", "dup11", "dup12", "dup2", "dup20", "dup20", "dup21", "dup21", "dup22", "dup22", "dup23", "dup23", "dup12", "dup13", "dup13", "dup14", "dup14", "dup15", "dup15", "dup16", "dup16", "dup17", "dup17", "dup18", "dup18", "dup19", "dup19", "dup2", "dup2", "dup20", "dup20", "dup21", "dup21", "dup22", "dup22", "dup23", "dup23", "dup24", "dup24", "dup25", "dup3", "dup30", "dup30", "dup4", "dup4", "dup5", "dup5", "dup6", "dup23", "dup23", "dup12", "dup13", "dup13", "dup14", "dup14", "dup15", "dup15", "dup16", "dup16", "dup17", "dup17", "dup18", "dup18", "dup19", "dup19", "dup2", "dup2", "dup20", "dup20", "dup21", "dup21", "dup22", "dup22", "dup23", "dup23", "dup24", "dup24", "dup6", "dup7", "dup7", "dup8", "dup8", "dup9", "dup9", "dup25", "dup26", "dup26", "dup3", "dup30", "dup30", "dup4", "dup4", "dup5", "dup5", "dup6", "dup6", "dup7", "dup7", "dup8", "dup8", "dup9", "dup9", "dup27", "dup27", "dup28", "dup28", "dup29", "dup29", "dup3", "dup3", "dup30", "dup30", "dup4", "dup4", "dup5", "dup5", "dup6", "dup6", "dup7", "dup7", "dup8", "dup8", "dup9", "dup9" }; + + for (greet) |a| { + try in.insert(a); + try _queue.upsert(@truncate(u32, std.hash.Wyhash.hash(0, a)), a); + } + + for (Worker.lodash_all) |a| { + try in.insert(a); + } + + for (Worker.three_all) |a| { + try in.insert(a); + } + + var out = try default_allocator.create(std.BufSet); + out.* = std.BufSet.init(default_allocator); + + var waitgroup = try default_allocator.create(WaitGroup); + waitgroup.* = WaitGroup.init(); + + waitgroup.add(); + waitgroup.add(); + waitgroup.add(); + waitgroup.add(); + waitgroup.add(); + waitgroup.add(); + var mutex = try default_allocator.create(Mutex); + mutex.* = Mutex{}; + + var thread1 = try std.Thread.spawn(.{}, Worker.run, .{ _queue, 0, out, waitgroup, mutex }); + var thread2 = try std.Thread.spawn(.{}, Worker.run, .{ _queue, 1, out, waitgroup, mutex }); + var thread3 = try std.Thread.spawn(.{}, Worker.run, .{ _queue, 2, out, waitgroup, mutex }); + var thread4 = try std.Thread.spawn(.{}, Worker.run, .{ _queue, 3, out, waitgroup, mutex }); + var thread5 = try std.Thread.spawn(.{}, Worker.run, .{ _queue, 4, out, waitgroup, mutex }); + var thread6 = try std.Thread.spawn(.{}, Worker.run, .{ _queue, 5, out, waitgroup, mutex }); + + waitgroup.wait(); + thread1.join(); + thread2.join(); + thread3.join(); + thread4.join(); + thread5.join(); + thread6.join(); + + try std.testing.expectEqual(out.count(), in.count()); + var iter = in.hash_map.iterator(); + + while (iter.next()) |entry| { + try expect(out.contains(entry.key_ptr.*)); + } +} diff --git a/src/bundler.zig b/src/bundler.zig index fcfffdd15..4942c3989 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -34,149 +34,7 @@ const isPackagePath = _resolver.isPackagePath; const Css = @import("css_scanner.zig"); const DotEnv = @import("./env_loader.zig"); const Lock = @import("./lock.zig").Lock; -pub const ServeResult = struct { - file: options.OutputFile, - mime_type: MimeType, -}; - -pub const ClientEntryPoint = struct { - code_buffer: [8096]u8 = undefined, - path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined, - source: logger.Source = undefined, - - pub fn isEntryPointPath(extname: string) bool { - return strings.startsWith("entry.", extname); - } - - pub fn generateEntryPointPath(outbuffer: []u8, original_path: Fs.PathName) string { - var joined_base_and_dir_parts = [_]string{ original_path.dir, original_path.base }; - var generated_path = Fs.FileSystem.instance.absBuf(&joined_base_and_dir_parts, outbuffer); - - std.mem.copy(u8, outbuffer[generated_path.len..], ".entry"); - generated_path = outbuffer[0 .. generated_path.len + ".entry".len]; - std.mem.copy(u8, outbuffer[generated_path.len..], original_path.ext); - return outbuffer[0 .. generated_path.len + original_path.ext.len]; - } - - pub fn decodeEntryPointPath(outbuffer: []u8, original_path: Fs.PathName) string { - var joined_base_and_dir_parts = [_]string{ original_path.dir, original_path.base }; - var generated_path = Fs.FileSystem.instance.absBuf(&joined_base_and_dir_parts, outbuffer); - var original_ext = original_path.ext; - if (strings.indexOf(original_path.ext, "entry")) |entry_i| { - original_ext = original_path.ext[entry_i + "entry".len ..]; - } - - std.mem.copy(u8, outbuffer[generated_path.len..], original_ext); - - return outbuffer[0 .. generated_path.len + original_ext.len]; - } - - pub fn generate(entry: *ClientEntryPoint, comptime BundlerType: type, bundler: *BundlerType, original_path: Fs.PathName, client: string) !void { - - // This is *extremely* naive. - // The basic idea here is this: - // -- - // import * as EntryPoint from 'entry-point'; - // import boot from 'framework'; - // boot(EntryPoint); - // -- - // We go through the steps of printing the code -- only to then parse/transpile it because - // we want it to go through the linker and the rest of the transpilation process - - const dir_to_use: string = original_path.dirWithTrailingSlash(); - - const code = try std.fmt.bufPrint( - &entry.code_buffer, - \\var lastErrorHandler = globalThis.onerror; - \\var loaded = {{boot: false, entry: false, onError: null}}; - \\if (!lastErrorHandler || !lastErrorHandler.__onceTag) {{ - \\ globalThis.onerror = function (evt) {{ - \\ if (this.onError && typeof this.onError == 'function') {{ - \\ this.onError(evt, loaded); - \\ }} - \\ console.error(evt.error); - \\ debugger; - \\ }}; - \\ globalThis.onerror.__onceTag = true; - \\ globalThis.onerror.loaded = loaded; - \\}} - \\ - \\import boot from '{s}'; - \\loaded.boot = true; - \\if ('setLoaded' in boot) boot.setLoaded(loaded); - \\import * as EntryPoint from '{s}{s}'; - \\loaded.entry = true; - \\ - \\if (!boot) {{ - \\ const now = Date.now(); - \\ debugger; - \\ const elapsed = Date.now() - now; - \\ if (elapsed < 1000) {{ - \\ throw new Error('Expected framework to export default a function. Instead, framework exported:', Object.keys(boot)); - \\ }} - \\}} - \\ - \\boot(EntryPoint, loaded); - , - .{ - client, - dir_to_use, - original_path.filename, - }, - ); - - entry.source = logger.Source.initPathString(generateEntryPointPath(&entry.path_buffer, original_path), code); - entry.source.path.namespace = "client-entry"; - } -}; - -pub const ServerEntryPoint = struct { - code_buffer: [std.fs.MAX_PATH_BYTES * 2 + 500]u8 = undefined, - output_code_buffer: [std.fs.MAX_PATH_BYTES * 8 + 500]u8 = undefined, - source: logger.Source = undefined, - - pub fn generate( - entry: *ServerEntryPoint, - comptime BundlerType: type, - bundler: *BundlerType, - original_path: Fs.PathName, - name: string, - ) !void { - - // This is *extremely* naive. - // The basic idea here is this: - // -- - // import * as EntryPoint from 'entry-point'; - // import boot from 'framework'; - // boot(EntryPoint); - // -- - // We go through the steps of printing the code -- only to then parse/transpile it because - // we want it to go through the linker and the rest of the transpilation process - - const dir_to_use: string = original_path.dirWithTrailingSlash(); - - const code = try std.fmt.bufPrint( - &entry.code_buffer, - \\//Auto-generated file - \\import * as start from '{s}{s}'; - \\export * from '{s}{s}'; - , - .{ - dir_to_use, - original_path.filename, - dir_to_use, - original_path.filename, - }, - ); - - entry.source = logger.Source.initPathString(name, code); - entry.source.path.text = name; - entry.source.path.namespace = "server-entry"; - } -}; - -pub const ResolveResults = std.AutoHashMap(u64, void); -pub const ResolveQueue = std.fifo.LinearFifo(_resolver.Result, std.fifo.LinearFifoBufferType.Dynamic); +const NewBunQueue = @import("./bun_queue.zig").NewBunQueue; // How it works end-to-end // 1. Resolve a file path from input using the resolver @@ -184,7 +42,7 @@ pub const ResolveQueue = std.fifo.LinearFifo(_resolver.Result, std.fifo.LinearFi // 3. If the loader is .js, .jsx, .ts, .tsx, or .json, run it through our JavaScript Parser // IF serving via HTTP and it's parsed without errors: // 4. If parsed without errors, generate a strong ETag & write the output to a buffer that sends to the in the Printer. -// 7. Else, write any errors to error page +// 4. Else, write any errors to error page (which doesn't exist yet) // IF writing to disk AND it's parsed without errors: // 4. Write the output to a temporary file. // Why? Two reasons. @@ -210,7 +68,7 @@ pub const ResolveQueue = std.fifo.LinearFifo(_resolver.Result, std.fifo.LinearFi // buffer (react-dom.development.js is 550 KB) // ^ This is how it used to work! // - If we delay printing, we need to keep the AST around. Which breaks all our -// recycling logic since that could be many many ASTs. +// memory-saving recycling logic since that could be many many ASTs. // 5. Once all files are written, determine the shortest common path // 6. Move all the temporary files to their intended destinations // IF writing to disk AND it's a file-like loader @@ -219,22 +77,12 @@ pub const ResolveQueue = std.fifo.LinearFifo(_resolver.Result, std.fifo.LinearFi // 5. Resolve any imports of this file to that hash(file(absolute_path)) // 6. Append to the files array with the new filename // 7. When parsing & resolving is over, just copy the file. -// - on macOS, ensure it does an APFS shallow clone so that doesn't use disk space +// - on macOS, ensure it does an APFS shallow clone so that doesn't use disk space (only possible if file doesn't already exist) +// fclonefile // IF serving via HTTP AND it's a file-like loader: -// 4. Hash the metadata ${absolute_path}-${fstat.mtime}-${fstat.size} -// 5. Use a deterministic prefix so we know what file to look for without copying it -// Example scenario: -// GET /logo-SIU3242.png -// 404 Not Found because there is no file named "logo-SIu3242.png" -// Instead, we can do this: -// GET /public/SIU3242/logo.png -// Our server sees "/public/" and knows the next segment will be a token -// which lets it ignore that when resolving the absolute path on disk -// 6. Compare the current hash with the expected hash -// 7. IF does not match, do a 301 Temporary Redirect to the new file path -// This adds an extra network request for outdated files, but that should be uncommon. -// 7. IF does match, serve it with that hash as a weak ETag -// 8. This should also just work unprefixed, but that will be served Cache-Control: private, no-store +// 4. Use os.sendfile so copying/reading the file happens in the kernel instead of in Bun. +// This unfortunately means content hashing for HTTP server is unsupported, but metadata etags work +// For each imported file, GOTO 1. pub const ParseResult = struct { source: logger.Source, @@ -243,29 +91,6 @@ pub const ParseResult = struct { input_fd: ?StoredFileDescriptorType = null, }; -pub const ScanResult = struct { - path: Fs.Path, - is_node_module: bool = false, - file_size: u32 = 0, - import_record_start: u32, - import_record_length: u32, - - pub const Summary = struct { - import_records: std.ArrayList(ImportRecord), - scan_results: std.ArrayList(ScanResult), - pub fn list(summary: *const Summary) List { - return List{ - .import_records = summary.import_records.items, - .scan_results = summary.scan_results.items, - }; - } - pub const List = struct { - import_records: []ImportRecord, - scan_results: []ScanResult, - }; - }; -}; - pub fn NewBundler(cache_files: bool) type { return struct { pub const Linker = if (cache_files) linker.Linker else linker.ServeLinker; @@ -551,62 +376,44 @@ pub fn NewBundler(cache_files: bool) type { } pub const GenerateNodeModuleBundle = struct { - pub const PathMap = struct { - const HashTable = std.StringHashMap(u32); - - backing: HashTable, - mutex: Lock, - - pub fn init(allocator: *std.mem.Allocator) PathMap { - return PathMap{ - .backing = HashTable.init(allocator), - .mutex = Lock.init(), - }; - } - - pub inline fn lock(this: *PathMap) void { - this.mutex.lock(); - } - - pub inline fn unlock(this: *PathMap) void { - this.mutex.unlock(); - } - - pub inline fn hashOf(str: string) u64 { - return std.hash.Wyhash.hash(0, str); - } - - pub inline fn getOrPut(this: *PathMap, str: string) !HashTable.GetOrPutResult { - return this.backing.getOrPut(str); - } - - pub inline fn contains(this: *PathMap, str: string) bool { - return this.backing.contains(str); - } - }; - - const BunQueue = sync.Channel(_resolver.Result, .Dynamic); + const BunQueue = NewBunQueue(_resolver.Result); pub const ThreadPool = struct { // Hardcode 512 as max number of threads for now. workers: [512]Worker = undefined, - workers_used: u16 = 0, - cpu_count: u16 = 0, - wait_group: sync.WaitGroup = sync.WaitGroup.init(), - + workers_used: u32 = 0, + cpu_count: u32 = 0, + started_workers: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), + stopped_workers: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), + completed_count: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), pub fn start(this: *ThreadPool, generator: *GenerateNodeModuleBundle) !void { - this.cpu_count = @truncate(u16, @divFloor((try std.Thread.getCpuCount()) + 1, 2)); + this.cpu_count = @truncate(u32, @divFloor((try std.Thread.getCpuCount()) + 1, 2)); while (this.workers_used < this.cpu_count) : (this.workers_used += 1) { - this.workers[this.workers_used].wg = &this.wait_group; - - this.wait_group.add(); try this.workers[this.workers_used].init(generator); } } - pub fn wait(this: *ThreadPool) void { - this.wait_group.wait(); + pub fn wait(this: *ThreadPool, generator: *GenerateNodeModuleBundle) void { + while (generator.queue.count.load(.SeqCst) != generator.pool.completed_count.load(.SeqCst)) { + var j: usize = 0; + while (j < 100) : (j += 1) {} + std.atomic.spinLoopHint(); + } + + for (this.workers[0..this.workers_used]) |*worker| { + @atomicStore(bool, &worker.quit, true, .Release); + } + + while (this.stopped_workers.load(.Acquire) != this.workers_used) { + var j: usize = 0; + while (j < 100) : (j += 1) {} + std.atomic.spinLoopHint(); + } + + for (this.workers[0..this.workers_used]) |*worker| { + worker.thread.join(); + } } pub const Task = struct { @@ -617,10 +424,13 @@ pub fn NewBundler(cache_files: bool) type { pub const Worker = struct { thread_id: std.Thread.Id, thread: std.Thread, + allocator: *std.mem.Allocator, - wg: *sync.WaitGroup, generator: *GenerateNodeModuleBundle, data: *WorkerData = undefined, + quit: bool = false, + + has_notify_started: bool = false, pub const WorkerData = struct { shared_buffer: MutableString = undefined, @@ -641,11 +451,26 @@ pub fn NewBundler(cache_files: bool) type { worker.thread = try std.Thread.spawn(.{}, Worker.run, .{worker}); } + pub fn notifyStarted(this: *Worker) void { + if (!this.has_notify_started) { + this.has_notify_started = true; + _ = this.generator.pool.started_workers.fetchAdd(1, .Release); + std.Thread.Futex.wake(&this.generator.pool.started_workers, std.math.maxInt(u32)); + } + } + pub fn run(this: *Worker) void { - defer this.wg.done(); Output.Source.configureThread(); this.thread_id = std.Thread.getCurrentId(); - defer Output.flush(); + if (isDebug) { + Output.prettyln("Thread started.\n", .{}); + } + defer { + if (isDebug) { + Output.prettyln("Thread stopped.\n", .{}); + } + Output.flush(); + } this.loop() catch |err| { Output.prettyErrorln("<r><red>Error: {s}<r>", .{@errorName(err)}); @@ -653,20 +478,33 @@ pub fn NewBundler(cache_files: bool) type { } pub fn loop(this: *Worker) anyerror!void { - // Delay initializing until we get the first thing. - const first = (try this.generator.resolve_queue.tryReadItem()) orelse return; + defer { + _ = this.generator.pool.stopped_workers.fetchAdd(1, .Release); + this.notifyStarted(); + + std.Thread.Futex.wake(&this.generator.pool.stopped_workers, 1); + // std.Thread.Futex.wake(&this.generator.queue.len, std.math.maxInt(u32)); + } + js_ast.Expr.Data.Store.create(this.generator.allocator); js_ast.Stmt.Data.Store.create(this.generator.allocator); this.data = this.generator.allocator.create(WorkerData) catch unreachable; this.data.* = WorkerData{}; this.data.shared_buffer = try MutableString.init(this.generator.allocator, 0); this.data.scan_pass_result = js_parser.ScanPassResult.init(this.generator.allocator); + defer this.data.deinit(this.generator.allocator); - try this.generator.processFile(this, first); + this.notifyStarted(); + + while (!@atomicLoad(bool, &this.quit, .Acquire)) { + while (this.generator.queue.next()) |item| { + defer { + _ = this.generator.pool.completed_count.fetchAdd(1, .Release); + } - while (try this.generator.resolve_queue.tryReadItem()) |item| { - try this.generator.processFile(this, item); + try this.generator.processFile(this, item); + } } } }; @@ -677,9 +515,8 @@ pub fn NewBundler(cache_files: bool) type { package_list: std.ArrayList(Api.JavascriptBundledPackage), header_string_buffer: MutableString, // Just need to know if we've already enqueued this one - resolved_paths: PathMap, package_list_map: std.AutoHashMap(u64, u32), - resolve_queue: *BunQueue, + queue: *BunQueue, bundler: *ThisBundler, allocator: *std.mem.Allocator, tmpfile: std.fs.File, @@ -689,47 +526,46 @@ pub fn NewBundler(cache_files: bool) type { code_end_byte_offset: u32 = 0, has_jsx: bool = false, + work_waiter: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), list_lock: Lock = Lock.init(), pub const current_version: u32 = 1; pub fn enqueueItem(this: *GenerateNodeModuleBundle, resolve: _resolver.Result) !void { - var this_module_resolved_path = try this.resolved_paths.getOrPut(resolve.path_pair.primary.text); + const loader = this.bundler.options.loaders.get(resolve.path_pair.primary.name.ext) orelse .file; + if (!loader.isJavaScriptLike()) return; - if (!this_module_resolved_path.found_existing) { - if (resolve.isLikelyNodeModule()) { - if (BundledModuleData.get(this, &resolve)) |module_data_| { - this_module_resolved_path.value_ptr.* = module_data_.module_id; - } - } - var result = resolve; - result.path_pair.primary = Fs.Path.init(std.mem.span(try this.allocator.dupeZ(u8, resolve.path_pair.primary.text))); - try this.resolve_queue.writeItem(result); - } + var result = resolve; + result.path_pair.primary = Fs.Path.init(std.mem.span(try this.allocator.dupeZ(u8, resolve.path_pair.primary.text))); + + try this.queue.upsert(result.hash(loader), result); } // The Bun Bundle Format - // Your entire node_modules folder in a single compact file designed for web browsers. - // A binary JavaScript bundle format prioritizing bundle time and serialization/deserialization time + // All the node_modules your app uses in a single compact file with metadata + // A binary JavaScript bundle format prioritizing generation time and deserialization time pub const magic_bytes = "#!/usr/bin/env bun\n\n"; - // This makes it possible to do ./path-to-bundle on posix systems you can see the raw JS contents + // This makes it possible to do ./path-to-bundle on posix systems so you can see the raw JS contents // https://en.wikipedia.org/wiki/Magic_number_(programming)#In_files // Immediately after the magic bytes, the next character is a uint32 followed by a newline // 0x00000000\n // That uint32 denotes the byte offset in the file where the code for the bundle ends // - If the value is 0, that means the file did not finish writing or there are no modules - // - This imposes a maximum bundle size of around 4,294,967,295 bytes. If your JS is more than 4 GB, you're a + // - This imposes a maximum bundle size of around 4,294,967,295 bytes. If your JS is more than 4 GB, it won't work. // The raw JavaScript is encoded as a UTF-8 string starting from the current position + 1 until the above byte offset. // This uint32 is useful for HTTP servers to separate: // - Which part of the bundle is the JS code? // - Which part is the metadata? - // Without needing to do a full pass through the file. - // The metadata is at the bottom of the file instead of the top because the metadata is generated after the entire bundle is written. + // Without needing to do a full pass through the file, or necessarily care about the metadata. + // The metadata is at the bottom of the file instead of the top because the metadata is written after all JS code in the bundle is written. // The rationale there is: - // 1. We cannot prepend to a file without a pass over the entire file - // 2. The metadata is variable-length and that format will change more often. Perhaps different bundlers will generate different metadata. - // If you have 32 MB of JavaScript dependencies, the only time it's acceptable to do a full pass is when sending it over HTTP via sendfile() - // So instead, we append to the file after printing each node_module + // 1. We cannot prepend to a file without rewriting the entire file + // 2. The metadata is variable-length and that format will change often. + // 3. We won't have all the metadata until after all JS is finished writing + // If you have 32 MB of JavaScript dependencies, you really want to avoid reading the code in memory. + // - This lets you seek to the specific position in the file. + // - HTTP servers should use sendfile() instead of copying the file to userspace memory. + // So instead, we append metadata to the file after printing each node_module // When there are no more modules to process, we generate the metadata // To find the metadata, you look at the byte offset: initial_header[magic_bytes.len..initial_header.len - 1] // Then, you add that number to initial_header.len @@ -737,12 +573,13 @@ pub fn NewBundler(cache_files: bool) type { var buf = std.mem.zeroes([magic_bytes.len + 5]u8); std.mem.copy(u8, &buf, magic_bytes); var remainder = buf[magic_bytes.len..]; - // Write an invalid byte offset to be updated after the file ends + // Write an invalid byte offset to be updated after we finish generating the code std.mem.writeIntNative(u32, remainder[0 .. remainder.len - 1], 0); buf[buf.len - 1] = '\n'; break :brk buf; }; const code_start_byte_offset: u32 = initial_header.len; + // The specifics of the metadata is not documented here. You can find it in src/api/schema.peechy. pub fn appendHeaderString(generator: *GenerateNodeModuleBundle, str: string) !Api.StringPointer { var offset = generator.header_string_buffer.list.items.len; @@ -773,16 +610,15 @@ pub fn NewBundler(cache_files: bool) type { var tmpfile = try tmpdir.createFileZ(tmpname, .{ .read = isDebug, .exclusive = true }); var generator = try allocator.create(GenerateNodeModuleBundle); - var queue = try allocator.create(BunQueue); - queue.* = BunQueue.init(allocator); + var queue = try BunQueue.init(allocator); defer allocator.destroy(generator); generator.* = GenerateNodeModuleBundle{ .module_list = std.ArrayList(Api.JavascriptBundledModule).init(allocator), .package_list = std.ArrayList(Api.JavascriptBundledPackage).init(allocator), .header_string_buffer = try MutableString.init(allocator, 0), .allocator = allocator, - .resolved_paths = PathMap.init(allocator), - .resolve_queue = queue, + .queue = queue, + // .resolve_queue = queue, .bundler = bundler, .tmpfile = tmpfile, .log = bundler.log, @@ -821,16 +657,13 @@ pub fn NewBundler(cache_files: bool) type { defer this.bundler.resetStore(); const entry_points = try router.getEntryPoints(allocator); - try this.resolve_queue.buffer.ensureUnusedCapacity(entry_points.len + resolve_queue_estimate); for (entry_points) |entry_point| { const source_dir = bundler.fs.top_level_dir; const resolved = try bundler.linker.resolver.resolve(source_dir, entry_point, .entry_point); try this.enqueueItem(resolved); } this.bundler.resetStore(); - } else { - try this.resolve_queue.buffer.ensureUnusedCapacity(resolve_queue_estimate); - } + } else {} for (bundler.options.entry_points) |entry_point| { defer this.bundler.resetStore(); @@ -885,8 +718,9 @@ pub fn NewBundler(cache_files: bool) type { } this.bundler.resetStore(); + try this.pool.start(this); - this.pool.wait(); + this.pool.wait(this); if (this.log.errors > 0) { // We stop here because if there are errors we don't know if the bundle is valid @@ -1140,10 +974,6 @@ pub fn NewBundler(cache_files: bool) type { &source, )) orelse return; if (ast.import_records.len > 0) { - this.resolved_paths.lock(); - defer { - this.resolved_paths.unlock(); - } { for (ast.import_records) |*import_record, record_id| { @@ -1162,17 +992,14 @@ 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); - 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; - - if (!get_or_put_result.found_existing) { - try this.resolve_queue.writeItem(_resolved_import.*); - } + try this.queue.upsert( + _resolved_import.hash(this.bundler.options.loaders.get(resolved_import.path_pair.primary.name.ext) orelse .file), + _resolved_import.*, + ); } else |err| { if (comptime isDebug) { Output.prettyErrorln("\n<r><red>{s}<r> on resolving \"{s}\" from \"{s}\"", .{ @@ -1364,6 +1191,8 @@ pub fn NewBundler(cache_files: bool) type { Output.flush(); } + this.list_lock.lock(); + defer this.list_lock.unlock(); code_offset = write_result.off; written = write_result.len; @@ -1373,11 +1202,6 @@ pub fn NewBundler(cache_files: bool) type { const code_length = this.tmpfile_byte_offset - code_offset; // std.debug.assert(code_length == written); - this.list_lock.lock(); - defer { - this.list_lock.unlock(); - } - var package_get_or_put_entry = try this.package_list_map.getOrPut(package.hash); if (!package_get_or_put_entry.found_existing) { @@ -1443,8 +1267,6 @@ pub fn NewBundler(cache_files: bool) type { ); { - this.resolved_paths.lock(); - defer this.resolved_paths.unlock(); for (scan_pass_result.import_records.items) |*import_record, i| { if (import_record.is_internal) { continue; @@ -1455,22 +1277,13 @@ pub fn NewBundler(cache_files: bool) type { continue; } - const resolved_import: *const _resolver.Result = _resolved_import; - - const get_or_put_result = try this.resolved_paths.getOrPut(resolved_import.path_pair.primary.text); - - if (get_or_put_result.found_existing) { - continue; - } - _resolved_import.path_pair.primary = Fs.Path.init(std.mem.span(try this.allocator.dupeZ(u8, _resolved_import.path_pair.primary.text))); - - // 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.*); - - if (BundledModuleData.get(this, resolved_import)) |module| { - get_or_put_result.value_ptr.* = module.module_id; - } + try this.queue.upsert( + _resolved_import.hash( + this.bundler.options.loaders.get(_resolved_import.path_pair.primary.name.ext) orelse .file, + ), + _resolved_import.*, + ); } else |err| { switch (err) { error.ModuleNotFound => { @@ -1801,74 +1614,6 @@ pub fn NewBundler(cache_files: bool) type { return output_file; } - pub fn scanWithResolveResult( - bundler: *ThisBundler, - resolve_result: _resolver.Result, - scan_pass_result: *js_parser.ScanPassResult, - ) !?ScanResult { - if (resolve_result.is_external) { - return null; - } - var import_records = &scan_pass_result.import_records; - var named_imports = &scan_pass_result.named_imports; - errdefer js_ast.Expr.Data.Store.reset(); - errdefer js_ast.Stmt.Data.Store.reset(); - - // Step 1. Parse & scan - const loader = bundler.options.loaders.get(resolve_result.path_pair.primary.name.ext) orelse .file; - var file_path = resolve_result.path_pair.primary; - file_path.pretty = Linker.relative_paths_list.append(string, bundler.fs.relativeTo(file_path.text)) catch unreachable; - - switch (loader) { - .jsx, .tsx, .js, .ts, .json => { - const entry = bundler.resolver.caches.fs.readFile( - bundler.fs, - file_path.text, - resolve_result.dirname_fd, - !cache_files, - null, - ) catch return null; - - const source = logger.Source.initFile(Fs.File{ .path = file_path, .contents = entry.contents }, bundler.allocator) catch return null; - const source_dir = file_path.name.dirWithTrailingSlash(); - - var jsx = bundler.options.jsx; - jsx.parse = loader.isJSX(); - var opts = js_parser.Parser.Options.init(jsx, loader); - - var result = ScanResult{ - .path = file_path, - .file_size = @truncate(u32, source.contents.len), - .is_node_module = resolve_result.isLikelyNodeModule(), - .import_record_start = @truncate(u32, import_records.items.len), - .import_record_length = 0, - }; - - try bundler.resolver.caches.js.scan( - bundler.allocator, - scan_pass_result, - opts, - bundler.options.define, - bundler.log, - &source, - ); - result.import_record_length = @truncate(u32, import_records.items.len - result.import_record_start); - for (import_records.items[result.import_record_start..import_records.items.len]) |*import_record, i| { - if (bundler.linker.resolver.resolve(source_dir, import_record.path.text, import_record.kind)) |*resolved_import| { - if (resolved_import.is_external) { - continue; - } - } else |err| {} - } - return result; - }, - // TODO: - else => { - return null; - }, - } - } - pub fn print( bundler: *ThisBundler, result: ParseResult, @@ -2144,90 +1889,6 @@ pub fn NewBundler(cache_files: bool) type { return entry; } - // pub fn scanDependencies( - // allocator: *std.mem.Allocator, - // log: *logger.Log, - // _opts: Api.TransformOptions, - // ) !ScanResult.Summary { - // var opts = _opts; - // opts.resolve = .dev; - // var bundler = try ThisBundler.init(allocator, log, opts, null); - - // bundler.configureLinker(); - - // var entry_points = try allocator.alloc(_resolver.Result, bundler.options.entry_points.len); - - // if (log.level == .verbose) { - // bundler.resolver.debug_logs = try DebugLogs.init(allocator); - // } - - // var rfs: *Fs.FileSystem.RealFS = &bundler.fs.fs; - - // var entry_point_i: usize = 0; - // for (bundler.options.entry_points) |_entry| { - // var entry: string = bundler.normalizeEntryPointPath(_entry); - - // defer { - // js_ast.Expr.Data.Store.reset(); - // js_ast.Stmt.Data.Store.reset(); - // } - - // const result = bundler.resolver.resolve(bundler.fs.top_level_dir, entry, .entry_point) catch |err| { - // Output.printError("Error resolving \"{s}\": {s}\n", .{ entry, @errorName(err) }); - // continue; - // }; - - // const key = result.path_pair.primary.text; - // if (bundler.resolve_results.contains(key)) { - // continue; - // } - // try bundler.resolve_results.put(key, result); - // entry_points[entry_point_i] = result; - - // if (isDebug) { - // Output.print("Resolved {s} => {s}", .{ entry, result.path_pair.primary.text }); - // } - - // entry_point_i += 1; - // bundler.resolve_queue.writeItem(result) catch unreachable; - // } - // var scan_results = std.ArrayList(ScanResult).init(allocator); - // var scan_pass_result = js_parser.ScanPassResult.init(allocator); - - // switch (bundler.options.resolve_mode) { - // .lazy, .dev, .bundle => { - // while (bundler.resolve_queue.readItem()) |item| { - // js_ast.Expr.Data.Store.reset(); - // js_ast.Stmt.Data.Store.reset(); - // scan_pass_result.named_imports.clearRetainingCapacity(); - // scan_results.append(bundler.scanWithResolveResult(item, &scan_pass_result) catch continue orelse continue) catch continue; - // } - // }, - // else => Global.panic("Unsupported resolve mode: {s}", .{@tagName(bundler.options.resolve_mode)}), - // } - - // // if (log.level == .verbose) { - // // for (log.msgs.items) |msg| { - // // try msg.writeFormat(std.io.getStdOut().writer()); - // // } - // // } - - // if (FeatureFlags.tracing) { - // Output.printError( - // "\n---Tracing---\nResolve time: {d}\nParsing time: {d}\n---Tracing--\n\n", - // .{ - // bundler.resolver.elapsed, - // bundler.elapsed, - // }, - // ); - // } - - // return ScanResult.Summary{ - // .scan_results = scan_results, - // .import_records = scan_pass_result.import_records, - // }; - // } - fn enqueueEntryPoints(bundler: *ThisBundler, entry_points: []_resolver.Result, comptime normalize_entry_point: bool) usize { var entry_point_i: usize = 0; @@ -2277,7 +1938,7 @@ pub fn NewBundler(cache_files: bool) type { // 100.00 µs std.fifo.LinearFifo(resolver.Result,std.fifo.LinearFifoBufferType { .Dynamic = {}}).writeItemAssumeCapacity if (bundler.options.resolve_mode != .lazy) { - try bundler.resolve_queue.ensureUnusedCapacity(24); + try bundler.resolve_queue.ensureUnusedCapacity(3); } var entry_points = try allocator.alloc(_resolver.Result, bundler.options.entry_points.len); @@ -2380,6 +2041,8 @@ pub fn NewBundler(cache_files: bool) type { return final_result; } + // pub fn processResolveQueueWithThreadPool(bundler) + pub fn processResolveQueue( bundler: *ThisBundler, comptime import_path_format: options.BundleOptions.ImportPathFormat, @@ -2387,10 +2050,13 @@ pub fn NewBundler(cache_files: bool) type { comptime Outstream: type, outstream: Outstream, ) !void { + // var count: u8 = 0; while (bundler.resolve_queue.readItem()) |item| { js_ast.Expr.Data.Store.reset(); js_ast.Stmt.Data.Store.reset(); + // defer count += 1; + if (comptime wrap_entry_point) { const loader = bundler.options.loaders.get(item.path_pair.primary.name.ext) orelse .file; @@ -2437,6 +2103,8 @@ pub fn NewBundler(cache_files: bool) type { null, ) catch continue orelse continue; bundler.output_files.append(output_file) catch unreachable; + + // if (count >= 3) return try bundler.processResolveQueueWithThreadPool(import_path_format, wrap_entry_point, Outstream, outstream); } } }; @@ -2721,3 +2389,153 @@ pub const Transformer = struct { ); } }; + +pub const ServeResult = struct { + file: options.OutputFile, + mime_type: MimeType, +}; + +pub const ClientEntryPoint = struct { + code_buffer: [8096]u8 = undefined, + path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined, + source: logger.Source = undefined, + + pub fn isEntryPointPath(extname: string) bool { + return strings.startsWith("entry.", extname); + } + + pub fn generateEntryPointPath(outbuffer: []u8, original_path: Fs.PathName) string { + var joined_base_and_dir_parts = [_]string{ original_path.dir, original_path.base }; + var generated_path = Fs.FileSystem.instance.absBuf(&joined_base_and_dir_parts, outbuffer); + + std.mem.copy(u8, outbuffer[generated_path.len..], ".entry"); + generated_path = outbuffer[0 .. generated_path.len + ".entry".len]; + std.mem.copy(u8, outbuffer[generated_path.len..], original_path.ext); + return outbuffer[0 .. generated_path.len + original_path.ext.len]; + } + + pub fn decodeEntryPointPath(outbuffer: []u8, original_path: Fs.PathName) string { + var joined_base_and_dir_parts = [_]string{ original_path.dir, original_path.base }; + var generated_path = Fs.FileSystem.instance.absBuf(&joined_base_and_dir_parts, outbuffer); + var original_ext = original_path.ext; + if (strings.indexOf(original_path.ext, "entry")) |entry_i| { + original_ext = original_path.ext[entry_i + "entry".len ..]; + } + + std.mem.copy(u8, outbuffer[generated_path.len..], original_ext); + + return outbuffer[0 .. generated_path.len + original_ext.len]; + } + + pub fn generate(entry: *ClientEntryPoint, comptime BundlerType: type, bundler: *BundlerType, original_path: Fs.PathName, client: string) !void { + + // This is *extremely* naive. + // The basic idea here is this: + // -- + // import * as EntryPoint from 'entry-point'; + // import boot from 'framework'; + // boot(EntryPoint); + // -- + // We go through the steps of printing the code -- only to then parse/transpile it because + // we want it to go through the linker and the rest of the transpilation process + + const dir_to_use: string = original_path.dirWithTrailingSlash(); + + const code = try std.fmt.bufPrint( + &entry.code_buffer, + \\var lastErrorHandler = globalThis.onerror; + \\var loaded = {{boot: false, entry: false, onError: null}}; + \\if (!lastErrorHandler || !lastErrorHandler.__onceTag) {{ + \\ globalThis.onerror = function (evt) {{ + \\ if (this.onError && typeof this.onError == 'function') {{ + \\ this.onError(evt, loaded); + \\ }} + \\ console.error(evt.error); + \\ debugger; + \\ }}; + \\ globalThis.onerror.__onceTag = true; + \\ globalThis.onerror.loaded = loaded; + \\}} + \\ + \\import boot from '{s}'; + \\loaded.boot = true; + \\if ('setLoaded' in boot) boot.setLoaded(loaded); + \\import * as EntryPoint from '{s}{s}'; + \\loaded.entry = true; + \\ + \\if (!boot) {{ + \\ const now = Date.now(); + \\ debugger; + \\ const elapsed = Date.now() - now; + \\ if (elapsed < 1000) {{ + \\ throw new Error('Expected framework to export default a function. Instead, framework exported:', Object.keys(boot)); + \\ }} + \\}} + \\ + \\boot(EntryPoint, loaded); + , + .{ + client, + dir_to_use, + original_path.filename, + }, + ); + + entry.source = logger.Source.initPathString(generateEntryPointPath(&entry.path_buffer, original_path), code); + entry.source.path.namespace = "client-entry"; + } +}; + +pub const ServerEntryPoint = struct { + code_buffer: [std.fs.MAX_PATH_BYTES * 2 + 500]u8 = undefined, + output_code_buffer: [std.fs.MAX_PATH_BYTES * 8 + 500]u8 = undefined, + source: logger.Source = undefined, + + pub fn generate( + entry: *ServerEntryPoint, + comptime BundlerType: type, + bundler: *BundlerType, + original_path: Fs.PathName, + name: string, + ) !void { + + // This is *extremely* naive. + // The basic idea here is this: + // -- + // import * as EntryPoint from 'entry-point'; + // import boot from 'framework'; + // boot(EntryPoint); + // -- + // We go through the steps of printing the code -- only to then parse/transpile it because + // we want it to go through the linker and the rest of the transpilation process + + const dir_to_use: string = original_path.dirWithTrailingSlash(); + + const code = try std.fmt.bufPrint( + &entry.code_buffer, + \\//Auto-generated file + \\import * as start from '{s}{s}'; + \\export * from '{s}{s}'; + , + .{ + dir_to_use, + original_path.filename, + dir_to_use, + original_path.filename, + }, + ); + + entry.source = logger.Source.initPathString(name, code); + entry.source.path.text = name; + entry.source.path.namespace = "server-entry"; + } +}; + +pub const ResolveResults = std.AutoHashMap( + u64, + void, +); +pub const ResolveQueue = std.fifo.LinearFifo( + _resolver.Result, + std.fifo.LinearFifoBufferType.Dynamic, +); diff --git a/src/cli.zig b/src/cli.zig index 83ebea850..b1eb3fe52 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -139,7 +139,7 @@ pub const Arguments = struct { pub const ParamType = clap.Param(clap.Help); - const params: [26]ParamType = brk: { + const params: [25]ParamType = brk: { @setEvalBranchQuota(9999); break :brk [_]ParamType{ clap.parseParam("--use <STR> Choose a framework, e.g. \"--use next\". It checks first for a package named \"bun-framework-packagename\" and then \"packagename\".") catch unreachable, @@ -157,7 +157,7 @@ pub const Arguments = struct { clap.parseParam("--no-summary  Don't print a summary (when generating .bun") catch unreachable, clap.parseParam("--origin <STR> Rewrite import paths to start with --origin. Default: \"/\"") catch unreachable, clap.parseParam("--platform <STR> \"browser\" or \"node\". Defaults to \"browser\"") catch unreachable, - clap.parseParam("--production  [not implemented] generate production code") catch unreachable, + // clap.parseParam("--production  [not implemented] generate production code") catch unreachable, clap.parseParam("--static-dir <STR> Top-level directory for .html files, fonts or anything external. Defaults to \"<cwd>/public\", to match create-react-app and Next.js") catch unreachable, clap.parseParam("--tsconfig-override <STR> Load tsconfig from path instead of cwd/tsconfig.json") catch unreachable, clap.parseParam("-d, --define <STR>... Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:development") catch unreachable, @@ -208,7 +208,7 @@ pub const Arguments = struct { .loaders = loader_tuple.values, }, - .serve = cmd == .DevCommand, + .serve = cmd == .DevCommand or (FeatureFlags.dev_only and cmd == .AutoCommand), .main_fields = args.options("--main-fields"), .generate_node_module_bundle = cmd == .BunCommand, .inject = args.options("--inject"), @@ -276,7 +276,7 @@ pub const Arguments = struct { else => {}, } - const production = args.flag("--production"); + const production = false; //args.flag("--production"); var write = entry_points.len > 1 or output_dir != null; if (write and output_dir == null) { @@ -309,7 +309,7 @@ pub const Arguments = struct { }; switch (comptime cmd) { - .DevCommand, .BuildCommand => { + .AutoCommand, .DevCommand, .BuildCommand => { if (args.option("--static-dir")) |public_dir| { opts.router = Api.RouteConfig{ .extensions = &.{}, .dir = &.{}, .static_dir = public_dir }; } @@ -426,20 +426,35 @@ const HelpCommand = struct { var cwd_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; const cwd = std.os.getcwd(&cwd_buf) catch unreachable; const dirname = std.fs.path.basename(cwd); - const fmt = - \\> <r> <b><white>init<r> Setup Bun in \"{s}\" - \\> <r> <b><green>dev <r><d> ./a.ts ./b.jsx<r> Start a Bun Dev Server - \\<d>*<r> <b><cyan>build <r><d> ./a.ts ./b.jsx<r> Make JavaScript-like code runnable & bundle CSS - \\> <r> <b><magenta>bun <r><d> ./a.ts ./b.jsx<r> Bundle dependencies of input files into a <r><magenta>.bun<r> - \\> <r> <green>run <r><d> ./a.ts <r> Run a JavaScript-like file with Bun.js - \\> <r> <b><blue>discord<r> Open Bun's Discord server - \\> <r> <b><d>help <r> Print this help menu - \\ - ; - - switch (reason) { - .explicit => Output.pretty("Bun: a fast bundler & transpiler for web software.\n\n" ++ fmt, .{dirname}), - .invalid_command => Output.prettyError("<r><red>Uh-oh<r> not sure what to do with that command.\n\n" ++ fmt, .{dirname}), + if (FeatureFlags.dev_only) { + const fmt = + \\> <r> <b><green>dev <r><d> ./a.ts ./b.jsx<r> Start a Bun Dev Server + \\> <r> <b><magenta>bun <r><d> ./a.ts ./b.jsx<r> Bundle dependencies of input files into a <r><magenta>.bun<r> + \\> <r> <b><blue>discord<r> Open Bun's Discord server + \\> <r> <b><d>help <r> Print this help menu + \\ + ; + + switch (reason) { + .explicit => Output.pretty("Bun: a fast bundler & transpiler for web software.\n\n" ++ fmt, .{}), + .invalid_command => Output.prettyError("<r><red>Uh-oh<r> not sure what to do with that command.\n\n" ++ fmt, .{}), + } + } else { + const fmt = + \\> <r> <b><white>init<r> Setup Bun in \"{s}\" + \\> <r> <b><green>dev <r><d> ./a.ts ./b.jsx<r> Start a Bun Dev Server + \\<d>*<r> <b><cyan>build <r><d> ./a.ts ./b.jsx<r> Make JavaScript-like code runnable & bundle CSS + \\> <r> <b><magenta>bun <r><d> ./a.ts ./b.jsx<r> Bundle dependencies of input files into a <r><magenta>.bun<r> + \\> <r> <green>run <r><d> ./a.ts <r> Run a JavaScript-like file with Bun.js + \\> <r> <b><blue>discord<r> Open Bun's Discord server + \\> <r> <b><d>help <r> Print this help menu + \\ + ; + + switch (reason) { + .explicit => Output.pretty("Bun: a fast bundler & transpiler for web software.\n\n" ++ fmt, .{dirname}), + .invalid_command => Output.prettyError("<r><red>Uh-oh<r> not sure what to do with that command.\n\n" ++ fmt, .{dirname}), + } } Output.flush(); @@ -506,18 +521,30 @@ pub const Command = struct { const first_arg_name = std.mem.span(next_arg); const RootCommandMatcher = strings.ExactSizeMatcher(8); - return switch (RootCommandMatcher.match(first_arg_name)) { - RootCommandMatcher.case("init") => .InitCommand, - RootCommandMatcher.case("bun") => .BunCommand, - RootCommandMatcher.case("discord") => .DiscordCommand, + if (comptime FeatureFlags.dev_only) { + return switch (RootCommandMatcher.match(first_arg_name)) { + RootCommandMatcher.case("init") => .InitCommand, + RootCommandMatcher.case("bun") => .BunCommand, + RootCommandMatcher.case("discord") => .DiscordCommand, - RootCommandMatcher.case("b"), RootCommandMatcher.case("build") => .BuildCommand, - RootCommandMatcher.case("r"), RootCommandMatcher.case("run") => .RunCommand, - RootCommandMatcher.case("d"), RootCommandMatcher.case("dev") => .DevCommand, + RootCommandMatcher.case("b"), RootCommandMatcher.case("build") => .BuildCommand, + RootCommandMatcher.case("r"), RootCommandMatcher.case("run") => .RunCommand, + RootCommandMatcher.case("d"), RootCommandMatcher.case("dev") => .DevCommand, - RootCommandMatcher.case("help") => .HelpCommand, - else => .AutoCommand, - }; + RootCommandMatcher.case("help") => .HelpCommand, + else => .AutoCommand, + }; + } else { + return switch (RootCommandMatcher.match(first_arg_name)) { + RootCommandMatcher.case("init") => .InitCommand, + RootCommandMatcher.case("bun") => .BunCommand, + RootCommandMatcher.case("discord") => .DiscordCommand, + RootCommandMatcher.case("d"), RootCommandMatcher.case("dev") => .DevCommand, + + RootCommandMatcher.case("help") => .HelpCommand, + else => .AutoCommand, + }; + } } pub fn start(allocator: *std.mem.Allocator, log: *logger.Log) !void { @@ -551,7 +578,7 @@ pub const Command = struct { try RunCommand.exec(ctx); }, .AutoCommand => { - const ctx = Command.Context.create(allocator, log, .AutoCommand) catch |e| { + var ctx = Command.Context.create(allocator, log, .AutoCommand) catch |e| { switch (e) { error.MissingEntryPoint => { HelpCommand.execWithReason(allocator, .explicit); @@ -570,7 +597,11 @@ pub const Command = struct { return; } - try BuildCommand.exec(ctx); + if (FeatureFlags.dev_only) { + try DevCommand.exec(ctx); + } else { + try BuildCommand.exec(ctx); + } }, else => unreachable, } diff --git a/src/feature_flags.zig b/src/feature_flags.zig index 1efd806e8..036f86dda 100644 --- a/src/feature_flags.zig +++ b/src/feature_flags.zig @@ -34,6 +34,8 @@ pub const css_supports_fence = true; pub const enable_entry_cache = true; pub const enable_bytecode_caching = false; +pub const dev_only = true; + pub const verbose_fs = false; pub const watch_directories = true; diff --git a/src/fs.zig b/src/fs.zig index 2bf4cbeb7..93eb16acc 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -191,21 +191,22 @@ pub const FileSystem = struct { else strings.StringOrTinyString.initLowerCase(entry.name); - const result = Entry{ - .base_ = name, - .base_lowercase_ = name_lowercased, - .dir = dir.dir, - .mutex = Mutex.init(), - // Call "stat" lazily for performance. The "@material-ui/icons" package - // contains a directory with over 11,000 entries in it and running "stat" - // for each entry was a big performance issue for that package. - .need_stat = entry.kind == .SymLink, - .cache = Entry.Cache{ - .symlink = "", - .kind = _kind, + const stored = try EntryStore.instance.appendGet( + Entry{ + .base_ = name, + .base_lowercase_ = name_lowercased, + .dir = dir.dir, + .mutex = Mutex.init(), + // Call "stat" lazily for performance. The "@material-ui/icons" package + // contains a directory with over 11,000 entries in it and running "stat" + // for each entry was a big performance issue for that package. + .need_stat = entry.kind == .SymLink, + .cache = Entry.Cache{ + .symlink = "", + .kind = _kind, + }, }, - }; - const stored = try EntryStore.instance.appendGet(result); + ); const stored_name = stored.value.base(); @@ -317,6 +318,7 @@ pub const FileSystem = struct { pub const Entry = struct { cache: Cache = Cache{}, dir: string, + base_: strings.StringOrTinyString, // Necessary because the hash table uses it as a key diff --git a/src/global.zig b/src/global.zig index cb0e351b2..b4289a1ba 100644 --- a/src/global.zig +++ b/src/global.zig @@ -1,7 +1,7 @@ const std = @import("std"); pub usingnamespace @import("strings.zig"); -pub const default_allocator = @import("./memory_allocator.zig").c_allocator; +pub const default_allocator: *std.mem.Allocator = if (isTest) std.heap.c_allocator else @import("./memory_allocator.zig").c_allocator; pub const C = @import("c.zig"); pub usingnamespace @import("env.zig"); diff --git a/src/http.zig b/src/http.zig index 316bbb802..3e53b349b 100644 --- a/src/http.zig +++ b/src/http.zig @@ -2108,6 +2108,15 @@ pub const Server = struct { } } + pub fn detectFastRefresh(this: *Server) void { + defer this.bundler.resetStore(); + + _ = this.bundler.resolver.resolve(this.bundler.fs.top_level_dir, "react-refresh/runtime", .internal) catch |err| { + this.bundler.options.jsx.supports_fast_refresh = false; + return; + }; + } + pub fn start(allocator: *std.mem.Allocator, options: Api.TransformOptions) !void { var log = logger.Log.init(allocator); var server = try allocator.create(Server); @@ -2119,10 +2128,13 @@ pub const Server = struct { .transform_options = options, .timer = try std.time.Timer.start(), }; + server.bundler = try Bundler.init(allocator, &server.log, options, null, null); server.bundler.configureLinker(); try server.bundler.configureRouter(true); + server.detectFastRefresh(); + try server.initWatcher(); if (server.bundler.router != null and server.bundler.options.routes.static_dir_enabled) { diff --git a/src/javascript/jsc/WebKit b/src/javascript/jsc/WebKit -Subproject e17b749830a4e3faf87f751630fdcc149906ee9 +Subproject e7d31961d4bf98b3e8b1df3ea0398ea1517a61d diff --git a/src/js_lexer.zig b/src/js_lexer.zig index 507cf7aed..ac7e4b574 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -123,16 +123,6 @@ pub const Lexer = struct { return logger.usize2Loc(self.start); } - inline fn nextCodepointSlice(it: *LexerType) []const u8 { - @setRuntimeSafety(false); - - const cp_len = strings.utf8ByteSequenceLength(it.source.contents[it.current]); - it.end = it.current; - it.current += cp_len; - - return if (!(it.current > it.source.contents.len)) it.source.contents[it.current - cp_len .. it.current] else ""; - } - pub fn syntaxError(self: *LexerType) !void { @setCold(true); @@ -187,19 +177,6 @@ pub const Lexer = struct { return @intCast(CodePoint, a) == self.code_point; } - inline fn nextCodepoint(it: *LexerType) !CodePoint { - 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 { @@ -522,7 +499,7 @@ pub const Lexer = struct { }, '\r' => { - if (quote != '`') { + if (comptime quote != '`') { try lexer.addDefaultError("Unterminated string literal"); } @@ -531,13 +508,13 @@ pub const Lexer = struct { }, '\n' => { - if (quote != '`') { + if (comptime quote != '`') { try lexer.addDefaultError("Unterminated string literal"); } }, '$' => { - if (quote == '`') { + if (comptime quote == '`') { try lexer.step(); if (lexer.code_point == '{') { suffix_len = 2; @@ -621,6 +598,29 @@ pub const Lexer = struct { // // } } + inline fn nextCodepointSlice(it: *LexerType) []const u8 { + @setRuntimeSafety(false); + + const cp_len = strings.utf8ByteSequenceLength(it.source.contents[it.current]); + it.end = it.current; + it.current += cp_len; + + return if (!(it.current > it.source.contents.len)) it.source.contents[it.current - cp_len .. it.current] else ""; + } + + inline fn nextCodepoint(it: *LexerType) !CodePoint { + 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, + }; + } + fn step(lexer: *LexerType) !void { lexer.code_point = try lexer.nextCodepoint(); diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 9d37230cd..28e2e04b1 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -2182,6 +2182,14 @@ pub const Parser = struct { if (p.options.transform_require_to_import) { var args = p.allocator.alloc(Expr, 2) catch unreachable; wrapper_expr = p.callRuntime(logger.Loc.Empty, "__commonJS", args); + + // Disable HMR if we're wrapping it in CommonJS + // It's technically possible to support this. + // But we need to cut scope for the v0. + p.options.features.hot_module_reloading = false; + p.runtime_imports.__HMRModule = null; + p.runtime_imports.__FastRefreshModule = null; + p.runtime_imports.__HMRClient = null; } } else { exports_kind = .esm; diff --git a/src/lock.zig b/src/lock.zig index e76a4cdf7..73dfdebd2 100644 --- a/src/lock.zig +++ b/src/lock.zig @@ -41,7 +41,7 @@ pub const Mutex = struct { var acquire_state = LOCKED; var state = self.state.load(.Monotonic); - var spin: u8 = if (has_fast_swap) 100 else 10; + var spin: u8 = if (comptime has_fast_swap) 100 else 10; while (true) { // Try to lock the Mutex if its unlocked. @@ -75,7 +75,7 @@ pub const Mutex = struct { // Indicate that there will be a waiting thread by updating to CONTENDED. // Acquire barrier as this swap could also possibly lock the Mutex. - if (has_fast_swap) { + if (comptime has_fast_swap) { state = self.state.swap(CONTENDED, .Acquire); if (state == UNLOCKED) return; break :uncontended; @@ -135,3 +135,8 @@ pub const Lock = struct { this.mutex.release(); } }; + + +pub fn spinCycle() void { + +}
\ No newline at end of file diff --git a/src/options.zig b/src/options.zig index 1fc07191d..c3069c54e 100644 --- a/src/options.zig +++ b/src/options.zig @@ -363,7 +363,7 @@ pub const Platform = enum { }; }; -pub const Loader = enum { +pub const Loader = enum(u3) { jsx, js, ts, @@ -398,6 +398,13 @@ pub const Loader = enum { return loader == .tsx or loader == .ts; } + pub fn isJavaScriptLike(loader: Loader) bool { + return switch (loader) { + .jsx, .js, .ts, .tsx => true, + else => false, + }; + } + pub fn forFileName(filename: string, obj: anytype) ?Loader { const ext = std.fs.path.extension(filename); if (ext.len == 0 or (ext.len == 1 and ext[0] == '.')) return null; @@ -966,7 +973,7 @@ pub const BundleOptions = struct { // 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.joinAlloc(allocator, &_dirs); + const check_static = try fs.absAlloc(allocator, &_dirs); defer allocator.free(check_static); std.fs.accessAbsolute(check_static, .{}) catch { diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index b104823b0..46a849dc9 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -10,11 +10,9 @@ const TSConfigJSON = @import("./tsconfig_json.zig").TSConfigJSON; const PackageJSON = @import("./package_json.zig").PackageJSON; usingnamespace @import("./data_url.zig"); pub const DirInfo = @import("./dir_info.zig"); -const Expr = @import("../js_ast.zig").Expr; const HTTPWatcher = @import("../http.zig").Watcher; const Wyhash = std.hash.Wyhash; -const hash_map_v2 = @import("../hash_map_v2.zig"); const Mutex = @import("../lock.zig").Lock; const StringBoolMap = std.StringHashMap(bool); @@ -148,6 +146,23 @@ pub const Result = struct { }); } }; + + pub fn hash(this: *const Result, loader: options.Loader) u32 { + const HashValue = packed struct { + loader: options.Loader, + len: u8, + path_hash: u21, + }; + + return @bitCast( + u32, + HashValue{ + .loader = loader, + .len = @truncate(u8, this.path_pair.primary.text.len), + .path_hash = @truncate(u21, std.hash.Wyhash.hash(0, this.path_pair.primary.text)), + }, + ); + } }; pub const DirEntryResolveQueueItem = struct { @@ -430,7 +445,8 @@ pub fn NewResolver(cache_files: bool) type { // support passing a package.json or path to a package const pkg: *const PackageJSON = result.package_json orelse r.packageJSONForResolvedNodeModuleWithIgnoreMissingName(&result, true) orelse return error.MissingPackageJSON; - const json: Expr = (try r.caches.json.parseJSON(r.log, pkg.source, r.allocator)) orelse return error.JSONParseError; + const json = (try r.caches.json.parseJSON(r.log, pkg.source, r.allocator)) orelse return error.JSONParseError; + pkg.loadFrameworkWithPreference(pair, json, r.allocator, load_defines, preference); const dir = pkg.source.path.name.dirWithTrailingSlash(); var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; @@ -554,8 +570,8 @@ pub fn NewResolver(cache_files: bool) type { return error.MissingResolveDir; } - r.mutex.lock(); - defer r.mutex.unlock(); + // r.mutex.lock(); + // defer r.mutex.unlock(); errdefer (r.flushDebugLogs(.fail) catch {}); var result = (try r.resolveWithoutSymlinks(source_dir, import_path, kind)) orelse { r.flushDebugLogs(.fail) catch {}; @@ -894,11 +910,31 @@ pub fn NewResolver(cache_files: bool) type { result: *const Result, ) ?*const PackageJSON { const absolute = result.path_pair.primary.text; + // /foo/node_modules/@babel/standalone/index.js + // ^------------^ 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; + end += 1; + // /foo/node_modules/@babel/standalone/index.js + // ^ + if (absolute[end] == '@') { + end += strings.indexOfChar(absolute[end..], std.fs.path.sep) orelse return null; + end += 1; + } + // /foo/node_modules/@babel/standalone/index.js + // ^ + const slice = absolute[0..end]; + + // Try to avoid the hash table lookup whenever possible + // That can cause filesystem lookups in parent directories and it requires a lock + if (result.package_json) |pkg| { + if (strings.eql(slice, pkg.source.path.name.dirWithTrailingSlash())) { + return pkg; + } + } - const dir_info = (r.dirInfoCached(absolute[0 .. end + 1]) catch null) orelse return null; + const dir_info = (r.dirInfoCached(slice) catch null) orelse return null; return dir_info.package_json; } @@ -1066,6 +1102,9 @@ pub fn NewResolver(cache_files: bool) type { } inline fn dirInfoCachedMaybeLog(r: *ThisResolver, path: string, comptime enable_logging: bool, comptime follow_symlinks: bool) !?*DirInfo { + r.mutex.lock(); + defer r.mutex.unlock(); + const top_result = try r.dir_cache.getOrPut(path); if (top_result.status != .unknown) { return r.dir_cache.atIndex(top_result.index); diff --git a/src/string_immutable.zig b/src/string_immutable.zig index 52b7e05ce..bac00ba45 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -13,6 +13,16 @@ pub inline fn contains(self: string, str: string) bool { return std.mem.indexOf(u8, self, str) != null; } +pub inline fn containsAny(in: anytype, target: string) bool { + for (in) |str| if (contains(str, target)) return true; + return false; +} + +pub inline fn indexAny(in: anytype, target: string) ?usize { + for (in) |str, i| if (indexOf(str, target) != null) return i; + return null; +} + pub inline fn indexOfChar(self: string, char: u8) ?usize { return std.mem.indexOfScalar(@TypeOf(char), self, char); } diff --git a/src/test/project.zig b/src/test/project.zig new file mode 100644 index 000000000..5715778c1 --- /dev/null +++ b/src/test/project.zig @@ -0,0 +1,1466 @@ +pub const lodash = [_][]const u8{ + "/project/node_modules/lodash/_apply.js", + "/project/node_modules/lodash/_arrayAggregator.js", + "/project/node_modules/lodash/_arrayEach.js", + "/project/node_modules/lodash/_arrayEachRight.js", + "/project/node_modules/lodash/_arrayEvery.js", + "/project/node_modules/lodash/_arrayFilter.js", + "/project/node_modules/lodash/_arrayIncludes.js", + "/project/node_modules/lodash/_arrayIncludesWith.js", + "/project/node_modules/lodash/_arrayLikeKeys.js", + "/project/node_modules/lodash/_arrayMap.js", + "/project/node_modules/lodash/_arrayPush.js", + "/project/node_modules/lodash/_arrayReduce.js", + "/project/node_modules/lodash/_arrayReduceRight.js", + "/project/node_modules/lodash/_arraySample.js", + "/project/node_modules/lodash/_arraySampleSize.js", + "/project/node_modules/lodash/_arrayShuffle.js", + "/project/node_modules/lodash/_arraySome.js", + "/project/node_modules/lodash/_asciiSize.js", + "/project/node_modules/lodash/_asciiToArray.js", + "/project/node_modules/lodash/_asciiWords.js", + "/project/node_modules/lodash/_assignMergeValue.js", + "/project/node_modules/lodash/_assignValue.js", + "/project/node_modules/lodash/_assocIndexOf.js", + "/project/node_modules/lodash/_baseAggregator.js", + "/project/node_modules/lodash/_baseAssign.js", + "/project/node_modules/lodash/_baseAssignIn.js", + "/project/node_modules/lodash/_baseAssignValue.js", + "/project/node_modules/lodash/_baseAt.js", + "/project/node_modules/lodash/_baseClamp.js", + "/project/node_modules/lodash/_baseClone.js", + "/project/node_modules/lodash/_baseConforms.js", + "/project/node_modules/lodash/_baseConformsTo.js", + "/project/node_modules/lodash/_baseCreate.js", + "/project/node_modules/lodash/_baseDelay.js", + "/project/node_modules/lodash/_baseDifference.js", + "/project/node_modules/lodash/_baseEach.js", + "/project/node_modules/lodash/_baseEachRight.js", + "/project/node_modules/lodash/_baseEvery.js", + "/project/node_modules/lodash/_baseExtremum.js", + "/project/node_modules/lodash/_baseFill.js", + "/project/node_modules/lodash/_baseFilter.js", + "/project/node_modules/lodash/_baseFindIndex.js", + "/project/node_modules/lodash/_baseFindKey.js", + "/project/node_modules/lodash/_baseFlatten.js", + "/project/node_modules/lodash/_baseFor.js", + "/project/node_modules/lodash/_baseForOwn.js", + "/project/node_modules/lodash/_baseForOwnRight.js", + "/project/node_modules/lodash/_baseForRight.js", + "/project/node_modules/lodash/_baseFunctions.js", + "/project/node_modules/lodash/_baseGet.js", + "/project/node_modules/lodash/_baseGetAllKeys.js", + "/project/node_modules/lodash/_baseGetTag.js", + "/project/node_modules/lodash/_baseGt.js", + "/project/node_modules/lodash/_baseHas.js", + "/project/node_modules/lodash/_baseHasIn.js", + "/project/node_modules/lodash/_baseIndexOf.js", + "/project/node_modules/lodash/_baseIndexOfWith.js", + "/project/node_modules/lodash/_baseInRange.js", + "/project/node_modules/lodash/_baseIntersection.js", + "/project/node_modules/lodash/_baseInverter.js", + "/project/node_modules/lodash/_baseInvoke.js", + "/project/node_modules/lodash/_baseIsArguments.js", + "/project/node_modules/lodash/_baseIsArrayBuffer.js", + "/project/node_modules/lodash/_baseIsDate.js", + "/project/node_modules/lodash/_baseIsEqual.js", + "/project/node_modules/lodash/_baseIsEqualDeep.js", + "/project/node_modules/lodash/_baseIsMap.js", + "/project/node_modules/lodash/_baseIsMatch.js", + "/project/node_modules/lodash/_baseIsNaN.js", + "/project/node_modules/lodash/_baseIsNative.js", + "/project/node_modules/lodash/_baseIsRegExp.js", + "/project/node_modules/lodash/_baseIsSet.js", + "/project/node_modules/lodash/_baseIsTypedArray.js", + "/project/node_modules/lodash/_baseIteratee.js", + "/project/node_modules/lodash/_baseKeys.js", + "/project/node_modules/lodash/_baseKeysIn.js", + "/project/node_modules/lodash/_baseLodash.js", + "/project/node_modules/lodash/_baseLt.js", + "/project/node_modules/lodash/_baseMap.js", + "/project/node_modules/lodash/_baseMatches.js", + "/project/node_modules/lodash/_baseMatchesProperty.js", + "/project/node_modules/lodash/_baseMean.js", + "/project/node_modules/lodash/_baseMerge.js", + "/project/node_modules/lodash/_baseMergeDeep.js", + "/project/node_modules/lodash/_baseNth.js", + "/project/node_modules/lodash/_baseOrderBy.js", + "/project/node_modules/lodash/_basePick.js", + "/project/node_modules/lodash/_basePickBy.js", + "/project/node_modules/lodash/_baseProperty.js", + "/project/node_modules/lodash/_basePropertyDeep.js", + "/project/node_modules/lodash/_basePropertyOf.js", + "/project/node_modules/lodash/_basePullAll.js", + "/project/node_modules/lodash/_basePullAt.js", + "/project/node_modules/lodash/_baseRandom.js", + "/project/node_modules/lodash/_baseRange.js", + "/project/node_modules/lodash/_baseReduce.js", + "/project/node_modules/lodash/_baseRepeat.js", + "/project/node_modules/lodash/_baseRest.js", + "/project/node_modules/lodash/_baseSample.js", + "/project/node_modules/lodash/_baseSampleSize.js", + "/project/node_modules/lodash/_baseSet.js", + "/project/node_modules/lodash/_baseSetData.js", + "/project/node_modules/lodash/_baseSetToString.js", + "/project/node_modules/lodash/_baseShuffle.js", + "/project/node_modules/lodash/_baseSlice.js", + "/project/node_modules/lodash/_baseSome.js", + "/project/node_modules/lodash/_baseSortBy.js", + "/project/node_modules/lodash/_baseSortedIndex.js", + "/project/node_modules/lodash/_baseSortedIndexBy.js", + "/project/node_modules/lodash/_baseSortedUniq.js", + "/project/node_modules/lodash/_baseSum.js", + "/project/node_modules/lodash/_baseTimes.js", + "/project/node_modules/lodash/_baseToNumber.js", + "/project/node_modules/lodash/_baseToPairs.js", + "/project/node_modules/lodash/_baseToString.js", + "/project/node_modules/lodash/_baseTrim.js", + "/project/node_modules/lodash/_baseUnary.js", + "/project/node_modules/lodash/_baseUniq.js", + "/project/node_modules/lodash/_baseUnset.js", + "/project/node_modules/lodash/_baseUpdate.js", + "/project/node_modules/lodash/_baseValues.js", + "/project/node_modules/lodash/_baseWhile.js", + "/project/node_modulges/lodash/_baseWrapperValue.js", + "/project/node_modules/lodash/_baseXor.js", + "/project/node_modules/lodash/_baseZipObject.js", + "/project/node_modules/lodash/_cacheHas.js", + "/project/node_modules/lodash/_castArrayLikeObject.js", + "/project/node_modules/lodash/_castFunction.js", + "/project/node_modules/lodash/_castPath.js", + "/project/node_modules/lodash/_castRest.js", + "/project/node_modules/lodash/_castSlice.js", + "/project/node_modules/lodash/_charsEndIndex.js", + "/project/node_modules/lodash/_charsStartIndex.js", + "/project/node_modules/lodash/_cloneArrayBuffer.js", + "/project/node_modules/lodash/_cloneBuffer.js", + "/project/node_modules/lodash/_cloneDataView.js", + "/project/node_modules/lodash/_cloneRegExp.js", + "/project/node_modules/lodash/_cloneSymbol.js", + "/project/node_modules/lodash/_cloneTypedArray.js", + "/project/node_modules/lodash/_compareAscending.js", + "/project/node_modules/lodash/_compareMultiple.js", + "/project/node_modules/lodash/_composeArgs.js", + "/project/node_modules/lodash/_composeArgsRight.js", + "/project/node_modules/lodash/_copyArray.js", + "/project/node_modules/lodash/_copyObject.js", + "/project/node_modules/lodash/_copySymbols.js", + "/project/node_modules/lodash/_copySymbolsIn.js", + "/project/node_modules/lodash/_coreJsData.js", + "/project/node_modules/lodash/_countHolders.js", + "/project/node_modules/lodash/_createAggregator.js", + "/project/node_modules/lodash/_createAssigner.js", + "/project/node_modules/lodash/_createBaseEach.js", + "/project/node_modules/lodash/_createBaseFor.js", + "/project/node_modules/lodash/_createBind.js", + "/project/node_modules/lodash/_createCaseFirst.js", + "/project/node_modules/lodash/_createCompounder.js", + "/project/node_modules/lodash/_createCtor.js", + "/project/node_modules/lodash/_createCurry.js", + "/project/node_modules/lodash/_createFind.js", + "/project/node_modules/lodash/_createFlow.js", + "/project/node_modules/lodash/_createHybrid.js", + "/project/node_modules/lodash/_createInverter.js", + "/project/node_modules/lodash/_createMathOperation.js", + "/project/node_modules/lodash/_createOver.js", + "/project/node_modules/lodash/_createPadding.js", + "/project/node_modules/lodash/_createPartial.js", + "/project/node_modules/lodash/_createRange.js", + "/project/node_modules/lodash/_createRecurry.js", + "/project/node_modules/lodash/_createRelationalOperation.js", + "/project/node_modules/lodash/_createRound.js", + "/project/node_modules/lodash/_createSet.js", + "/project/node_modules/lodash/_createToPairs.js", + "/project/node_modules/lodash/_createWrap.js", + "/project/node_modules/lodash/_customDefaultsAssignIn.js", + "/project/node_modules/lodash/_customDefaultsMerge.js", + "/project/node_modules/lodash/_customOmitClone.js", + "/project/node_modules/lodash/_DataView.js", + "/project/node_modules/lodash/_deburrLetter.js", + "/project/node_modules/lodash/_defineProperty.js", + "/project/node_modules/lodash/_equalArrays.js", + "/project/node_modules/lodash/_equalByTag.js", + "/project/node_modules/lodash/_equalObjects.js", + "/project/node_modules/lodash/_escapeHtmlChar.js", + "/project/node_modules/lodash/_escapeStringChar.js", + "/project/node_modules/lodash/_flatRest.js", + "/project/node_modules/lodash/_freeGlobal.js", + "/project/node_modules/lodash/_getAllKeys.js", + "/project/node_modules/lodash/_getAllKeysIn.js", + "/project/node_modules/lodash/_getData.js", + "/project/node_modules/lodash/_getFuncName.js", + "/project/node_modules/lodash/_getHolder.js", + "/project/node_modules/lodash/_getMapData.js", + "/project/node_modules/lodash/_getMatchData.js", + "/project/node_modules/lodash/_getNative.js", + "/project/node_modules/lodash/_getPrototype.js", + "/project/node_modules/lodash/_getRawTag.js", + "/project/node_modules/lodash/_getSymbols.js", + "/project/node_modules/lodash/_getSymbolsIn.js", + "/project/node_modules/lodash/_getTag.js", + "/project/node_modules/lodash/_getValue.js", + "/project/node_modules/lodash/_getView.js", + "/project/node_modules/lodash/_getWrapDetails.js", + "/project/node_modules/lodash/_Hash.js", + "/project/node_modules/lodash/_hashClear.js", + "/project/node_modules/lodash/_hashDelete.js", + "/project/node_modules/lodash/_hashGet.js", + "/project/node_modules/lodash/_hashHas.js", + "/project/node_modules/lodash/_hashSet.js", + "/project/node_modules/lodash/_hasPath.js", + "/project/node_modules/lodash/_hasUnicode.js", + "/project/node_modules/lodash/_hasUnicodeWord.js", + "/project/node_modules/lodash/_initCloneArray.js", + "/project/node_modules/lodash/_initCloneByTag.js", + "/project/node_modules/lodash/_initCloneObject.js", + "/project/node_modules/lodash/_insertWrapDetails.js", + "/project/node_modules/lodash/_isFlattenable.js", + "/project/node_modules/lodash/_isIndex.js", + "/project/node_modules/lodash/_isIterateeCall.js", + "/project/node_modules/lodash/_isKey.js", + "/project/node_modules/lodash/_isKeyable.js", + "/project/node_modules/lodash/_isLaziable.js", + "/project/node_modules/lodash/_isMaskable.js", + "/project/node_modules/lodash/_isMasked.js", + "/project/node_modules/lodash/_isPrototype.js", + "/project/node_modules/lodash/_isStrictComparable.js", + "/project/node_modules/lodash/_iteratorToArray.js", + "/project/node_modules/lodash/_lazyClone.js", + "/project/node_modules/lodash/_lazyReverse.js", + "/project/node_modules/lodash/_lazyValue.js", + "/project/node_modules/lodash/_LazyWrapper.js", + "/project/node_modules/lodash/_ListCache.js", + "/project/node_modules/lodash/_listCacheClear.js", + "/project/node_modules/lodash/_listCacheDelete.js", + "/project/node_modules/lodash/_listCacheGet.js", + "/project/node_modules/lodash/_listCacheHas.js", + "/project/node_modules/lodash/_listCacheSet.js", + "/project/node_modules/lodash/_LodashWrapper.js", + "/project/node_modules/lodash/_Map.js", + "/project/node_modules/lodash/_MapCache.js", + "/project/node_modules/lodash/_mapCacheClear.js", + "/project/node_modules/lodash/_mapCacheDelete.js", + "/project/node_modules/lodash/_mapCacheGet.js", + "/project/node_modules/lodash/_mapCacheHas.js", + "/project/node_modules/lodash/_mapCacheSet.js", + "/project/node_modules/lodash/_mapToArray.js", + "/project/node_modules/lodash/_matchesStrictComparable.js", + "/project/node_modules/lodash/_memoizeCapped.js", + "/project/node_modules/lodash/_mergeData.js", + "/project/node_modules/lodash/_metaMap.js", + "/project/node_modules/lodash/_nativeCreate.js", + "/project/node_modules/lodash/_nativeKeys.js", + "/project/node_modules/lodash/_nativeKeysIn.js", + "/project/node_modules/lodash/_nodeUtil.js", + "/project/node_modules/lodash/_objectToString.js", + "/project/node_modules/lodash/_overArg.js", + "/project/node_modules/lodash/_overRest.js", + "/project/node_modules/lodash/_parent.js", + "/project/node_modules/lodash/_Promise.js", + "/project/node_modules/lodash/_realNames.js", + "/project/node_modules/lodash/_reEscape.js", + "/project/node_modules/lodash/_reEvaluate.js", + "/project/node_modules/lodash/_reInterpolate.js", + "/project/node_modules/lodash/_reorder.js", + "/project/node_modules/lodash/_replaceHolders.js", + "/project/node_modules/lodash/_root.js", + "/project/node_modules/lodash/_safeGet.js", + "/project/node_modules/lodash/_Set.js", + "/project/node_modules/lodash/_SetCache.js", + "/project/node_modules/lodash/_setCacheAdd.js", + "/project/node_modules/lodash/_setCacheHas.js", + "/project/node_modules/lodash/_setData.js", + "/project/node_modules/lodash/_setToArray.js", + "/project/node_modules/lodash/_setToPairs.js", + "/project/node_modules/lodash/_setToString.js", + "/project/node_modules/lodash/_setWrapToString.js", + "/project/node_modules/lodash/_shortOut.js", + "/project/node_modules/lodash/_shuffleSelf.js", + "/project/node_modules/lodash/_Stack.js", + "/project/node_modules/lodash/_stackClear.js", + "/project/node_modules/lodash/_stackDelete.js", + "/project/node_modules/lodash/_stackGet.js", + "/project/node_modules/lodash/_stackHas.js", + "/project/node_modules/lodash/_stackSet.js", + "/project/node_modules/lodash/_strictIndexOf.js", + "/project/node_modules/lodash/_strictLastIndexOf.js", + "/project/node_modules/lodash/_stringSize.js", + "/project/node_modules/lodash/_stringToArray.js", + "/project/node_modules/lodash/_stringToPath.js", + "/project/node_modules/lodash/_Symbol.js", + "/project/node_modules/lodash/_toKey.js", + "/project/node_modules/lodash/_toSource.js", + "/project/node_modules/lodash/_trimmedEndIndex.js", + "/project/node_modules/lodash/_Uint8Array.js", + "/project/node_modules/lodash/_unescapeHtmlChar.js", + "/project/node_modules/lodash/_unicodeSize.js", + "/project/node_modules/lodash/_unicodeToArray.js", + "/project/node_modules/lodash/_unicodeWords.js", + "/project/node_modules/lodash/_updateWrapDetails.js", + "/project/node_modules/lodash/_WeakMap.js", + "/project/node_modules/lodash/_wrapperClone.js", + "/project/node_modules/lodash/add.js", + "/project/node_modules/lodash/after.js", + "/project/node_modules/lodash/array.js", + "/project/node_modules/lodash/ary.js", + "/project/node_modules/lodash/assign.js", + "/project/node_modules/lodash/assignIn.js", + "/project/node_modules/lodash/assignInWith.js", + "/project/node_modules/lodash/assignWith.js", + "/project/node_modules/lodash/at.js", + "/project/node_modules/lodash/attempt.js", + "/project/node_modules/lodash/before.js", + "/project/node_modules/lodash/bind.js", + "/project/node_modules/lodash/bindAll.js", + "/project/node_modules/lodash/bindKey.js", + "/project/node_modules/lodash/camelCase.js", + "/project/node_modules/lodash/capitalize.js", + "/project/node_modules/lodash/castArray.js", + "/project/node_modules/lodash/ceil.js", + "/project/node_modules/lodash/chain.js", + "/project/node_modules/lodash/chunk.js", + "/project/node_modules/lodash/clamp.js", + "/project/node_modules/lodash/clone.js", + "/project/node_modules/lodash/cloneDeep.js", + "/project/node_modules/lodash/cloneDeepWith.js", + "/project/node_modules/lodash/cloneWith.js", + "/project/node_modules/lodash/collection.js", + "/project/node_modules/lodash/commit.js", + "/project/node_modules/lodash/compact.js", + "/project/node_modules/lodash/concat.js", + "/project/node_modules/lodash/cond.js", + "/project/node_modules/lodash/conforms.js", + "/project/node_modules/lodash/conformsTo.js", + "/project/node_modules/lodash/constant.js", + "/project/node_modules/lodash/core.js", + "/project/node_modules/lodash/core.min.js", + "/project/node_modules/lodash/countBy.js", + "/project/node_modules/lodash/create.js", + "/project/node_modules/lodash/curry.js", + "/project/node_modules/lodash/curryRight.js", + "/project/node_modules/lodash/date.js", + "/project/node_modules/lodash/debounce.js", + "/project/node_modules/lodash/deburr.js", + "/project/node_modules/lodash/defaults.js", + "/project/node_modules/lodash/defaultsDeep.js", + "/project/node_modules/lodash/defaultTo.js", + "/project/node_modules/lodash/defer.js", + "/project/node_modules/lodash/delay.js", + "/project/node_modules/lodash/difference.js", + "/project/node_modules/lodash/differenceBy.js", + "/project/node_modules/lodash/differenceWith.js", + "/project/node_modules/lodash/divide.js", + "/project/node_modules/lodash/drop.js", + "/project/node_modules/lodash/dropRight.js", + "/project/node_modules/lodash/dropRightWhile.js", + "/project/node_modules/lodash/dropWhile.js", + "/project/node_modules/lodash/each.js", + "/project/node_modules/lodash/eachRight.js", + "/project/node_modules/lodash/endsWith.js", + "/project/node_modules/lodash/entries.js", + "/project/node_modules/lodash/entriesIn.js", + "/project/node_modules/lodash/eq.js", + "/project/node_modules/lodash/escape.js", + "/project/node_modules/lodash/escapeRegExp.js", + "/project/node_modules/lodash/every.js", + "/project/node_modules/lodash/extend.js", + "/project/node_modules/lodash/extendWith.js", + "/project/node_modules/lodash/fill.js", + "/project/node_modules/lodash/filter.js", + "/project/node_modules/lodash/find.js", + "/project/node_modules/lodash/findIndex.js", + "/project/node_modules/lodash/findKey.js", + "/project/node_modules/lodash/findLast.js", + "/project/node_modules/lodash/findLastIndex.js", + "/project/node_modules/lodash/findLastKey.js", + "/project/node_modules/lodash/first.js", + "/project/node_modules/lodash/flake.lock", + "/project/node_modules/lodash/flake.nix", + "/project/node_modules/lodash/flatMap.js", + "/project/node_modules/lodash/flatMapDeep.js", + "/project/node_modules/lodash/flatMapDepth.js", + "/project/node_modules/lodash/flatten.js", + "/project/node_modules/lodash/flattenDeep.js", + "/project/node_modules/lodash/flattenDepth.js", + "/project/node_modules/lodash/flip.js", + "/project/node_modules/lodash/floor.js", + "/project/node_modules/lodash/flow.js", + "/project/node_modules/lodash/flowRight.js", + "/project/node_modules/lodash/forEach.js", + "/project/node_modules/lodash/forEachRight.js", + "/project/node_modules/lodash/forIn.js", + "/project/node_modules/lodash/forInRight.js", + "/project/node_modules/lodash/forOwn.js", + "/project/node_modules/lodash/forOwnRight.js", + "/project/node_modules/lodash/fp", + "/project/node_modules/lodash/fp.js", + "/project/node_modules/lodash/fromPairs.js", + "/project/node_modules/lodash/function.js", + "/project/node_modules/lodash/functions.js", + "/project/node_modules/lodash/functionsIn.js", + "/project/node_modules/lodash/get.js", + "/project/node_modules/lodash/groupBy.js", + "/project/node_modules/lodash/gt.js", + "/project/node_modules/lodash/gte.js", + "/project/node_modules/lodash/has.js", + "/project/node_modules/lodash/hasIn.js", + "/project/node_modules/lodash/head.js", + "/project/node_modules/lodash/identity.js", + "/project/node_modules/lodash/includes.js", + "/project/node_modules/lodash/index.js", + "/project/node_modules/lodash/indexOf.js", + "/project/node_modules/lodash/initial.js", + "/project/node_modules/lodash/inRange.js", + "/project/node_modules/lodash/intersection.js", + "/project/node_modules/lodash/intersectionBy.js", + "/project/node_modules/lodash/intersectionWith.js", + "/project/node_modules/lodash/invert.js", + "/project/node_modules/lodash/invertBy.js", + "/project/node_modules/lodash/invoke.js", + "/project/node_modules/lodash/invokeMap.js", + "/project/node_modules/lodash/isArguments.js", + "/project/node_modules/lodash/isArray.js", + "/project/node_modules/lodash/isArrayBuffer.js", + "/project/node_modules/lodash/isArrayLike.js", + "/project/node_modules/lodash/isArrayLikeObject.js", + "/project/node_modules/lodash/isBoolean.js", + "/project/node_modules/lodash/isBuffer.js", + "/project/node_modules/lodash/isDate.js", + "/project/node_modules/lodash/isElement.js", + "/project/node_modules/lodash/isEmpty.js", + "/project/node_modules/lodash/isEqual.js", + "/project/node_modules/lodash/isEqualWith.js", + "/project/node_modules/lodash/isError.js", + "/project/node_modules/lodash/isFinite.js", + "/project/node_modules/lodash/isFunction.js", + "/project/node_modules/lodash/isInteger.js", + "/project/node_modules/lodash/isLength.js", + "/project/node_modules/lodash/isMap.js", + "/project/node_modules/lodash/isMatch.js", + "/project/node_modules/lodash/isMatchWith.js", + "/project/node_modules/lodash/isNaN.js", + "/project/node_modules/lodash/isNative.js", + "/project/node_modules/lodash/isNil.js", + "/project/node_modules/lodash/isNull.js", + "/project/node_modules/lodash/isNumber.js", + "/project/node_modules/lodash/isObject.js", + "/project/node_modules/lodash/isObjectLike.js", + "/project/node_modules/lodash/isPlainObject.js", + "/project/node_modules/lodash/isRegExp.js", + "/project/node_modules/lodash/isSafeInteger.js", + "/project/node_modules/lodash/isSet.js", + "/project/node_modules/lodash/isString.js", + "/project/node_modules/lodash/isSymbol.js", + "/project/node_modules/lodash/isTypedArray.js", + "/project/node_modules/lodash/isUndefined.js", + "/project/node_modules/lodash/isWeakMap.js", + "/project/node_modules/lodash/isWeakSet.js", + "/project/node_modules/lodash/iteratee.js", + "/project/node_modules/lodash/join.js", + "/project/node_modules/lodash/kebabCase.js", + "/project/node_modules/lodash/keyBy.js", + "/project/node_modules/lodash/keys.js", + "/project/node_modules/lodash/keysIn.js", + "/project/node_modules/lodash/lang.js", + "/project/node_modules/lodash/last.js", + "/project/node_modules/lodash/lastIndexOf.js", + "/project/node_modules/lodash/LICENSE", + "/project/node_modules/lodash/lodash.js", + "/project/node_modules/lodash/lodash.min.js", + "/project/node_modules/lodash/lowerCase.js", + "/project/node_modules/lodash/lowerFirst.js", + "/project/node_modules/lodash/lt.js", + "/project/node_modules/lodash/lte.js", + "/project/node_modules/lodash/map.js", + "/project/node_modules/lodash/mapKeys.js", + "/project/node_modules/lodash/mapValues.js", + "/project/node_modules/lodash/matches.js", + "/project/node_modules/lodash/matchesProperty.js", + "/project/node_modules/lodash/math.js", + "/project/node_modules/lodash/max.js", + "/project/node_modules/lodash/maxBy.js", + "/project/node_modules/lodash/mean.js", + "/project/node_modules/lodash/meanBy.js", + "/project/node_modules/lodash/memoize.js", + "/project/node_modules/lodash/merge.js", + "/project/node_modules/lodash/mergeWith.js", + "/project/node_modules/lodash/method.js", + "/project/node_modules/lodash/methodOf.js", + "/project/node_modules/lodash/min.js", + "/project/node_modules/lodash/minBy.js", + "/project/node_modules/lodash/mixin.js", + "/project/node_modules/lodash/multiply.js", + "/project/node_modules/lodash/negate.js", + "/project/node_modules/lodash/next.js", + "/project/node_modules/lodash/noop.js", + "/project/node_modules/lodash/now.js", + "/project/node_modules/lodash/nth.js", + "/project/node_modules/lodash/nthArg.js", + "/project/node_modules/lodash/number.js", + "/project/node_modules/lodash/object.js", + "/project/node_modules/lodash/omit.js", + "/project/node_modules/lodash/omitBy.js", + "/project/node_modules/lodash/once.js", + "/project/node_modules/lodash/orderBy.js", + "/project/node_modules/lodash/over.js", + "/project/node_modules/lodash/overArgs.js", + "/project/node_modules/lodash/overEvery.js", + "/project/node_modules/lodash/overSome.js", + "/project/node_modules/lodash/package.json", + "/project/node_modules/lodash/pad.js", + "/project/node_modules/lodash/padEnd.js", + "/project/node_modules/lodash/padStart.js", + "/project/node_modules/lodash/parseInt.js", + "/project/node_modules/lodash/partial.js", + "/project/node_modules/lodash/partialRight.js", + "/project/node_modules/lodash/partition.js", + "/project/node_modules/lodash/pick.js", + "/project/node_modules/lodash/pickBy.js", + "/project/node_modules/lodash/plant.js", + "/project/node_modules/lodash/property.js", + "/project/node_modules/lodash/propertyOf.js", + "/project/node_modules/lodash/pull.js", + "/project/node_modules/lodash/pullAll.js", + "/project/node_modules/lodash/pullAllBy.js", + "/project/node_modules/lodash/pullAllWith.js", + "/project/node_modules/lodash/pullAt.js", + "/project/node_modules/lodash/random.js", + "/project/node_modules/lodash/range.js", + "/project/node_modules/lodash/rangeRight.js", + "/project/node_modules/lodash/README.md", + "/project/node_modules/lodash/rearg.js", + "/project/node_modules/lodash/reduce.js", + "/project/node_modules/lodash/reduceRight.js", + "/project/node_modules/lodash/reject.js", + "/project/node_modules/lodash/release.md", + "/project/node_modules/lodash/remove.js", + "/project/node_modules/lodash/repeat.js", + "/project/node_modules/lodash/replace.js", + "/project/node_modules/lodash/rest.js", + "/project/node_modules/lodash/result.js", + "/project/node_modules/lodash/reverse.js", + "/project/node_modules/lodash/round.js", + "/project/node_modules/lodash/sample.js", + "/project/node_modules/lodash/sampleSize.js", + "/project/node_modules/lodash/seq.js", + "/project/node_modules/lodash/set.js", + "/project/node_modules/lodash/setWith.js", + "/project/node_modules/lodash/shuffle.js", + "/project/node_modules/lodash/size.js", + "/project/node_modules/lodash/slice.js", + "/project/node_modules/lodash/snakeCase.js", + "/project/node_modules/lodash/some.js", + "/project/node_modules/lodash/sortBy.js", + "/project/node_modules/lodash/sortedIndex.js", + "/project/node_modules/lodash/sortedIndexBy.js", + "/project/node_modules/lodash/sortedIndexOf.js", + "/project/node_modules/lodash/sortedLastIndex.js", + "/project/node_modules/lodash/sortedLastIndexBy.js", + "/project/node_modules/lodash/sortedLastIndexOf.js", + "/project/node_modules/lodash/sortedUniq.js", + "/project/node_modules/lodash/sortedUniqBy.js", + "/project/node_modules/lodash/split.js", + "/project/node_modules/lodash/spread.js", + "/project/node_modules/lodash/startCase.js", + "/project/node_modules/lodash/startsWith.js", + "/project/node_modules/lodash/string.js", + "/project/node_modules/lodash/stubArray.js", + "/project/node_modules/lodash/stubFalse.js", + "/project/node_modules/lodash/stubObject.js", + "/project/node_modules/lodash/stubString.js", + "/project/node_modules/lodash/stubTrue.js", + "/project/node_modules/lodash/subtract.js", + "/project/node_modules/lodash/sum.js", + "/project/node_modules/lodash/sumBy.js", + "/project/node_modules/lodash/tail.js", + "/project/node_modules/lodash/take.js", + "/project/node_modules/lodash/takeRight.js", + "/project/node_modules/lodash/takeRightWhile.js", + "/project/node_modules/lodash/takeWhile.js", + "/project/node_modules/lodash/tap.js", + "/project/node_modules/lodash/template.js", + "/project/node_modules/lodash/templateSettings.js", + "/project/node_modules/lodash/throttle.js", + "/project/node_modules/lodash/thru.js", + "/project/node_modules/lodash/times.js", + "/project/node_modules/lodash/toArray.js", + "/project/node_modules/lodash/toFinite.js", + "/project/node_modules/lodash/toInteger.js", + "/project/node_modules/lodash/toIterator.js", + "/project/node_modules/lodash/toJSON.js", + "/project/node_modules/lodash/toLength.js", + "/project/node_modules/lodash/toLower.js", + "/project/node_modules/lodash/toNumber.js", + "/project/node_modules/lodash/toPairs.js", + "/project/node_modules/lodash/toPairsIn.js", + "/project/node_modules/lodash/toPath.js", + "/project/node_modules/lodash/toPlainObject.js", + "/project/node_modules/lodash/toSafeInteger.js", + "/project/node_modules/lodash/toString.js", + "/project/node_modules/lodash/toUpper.js", + "/project/node_modules/lodash/transform.js", + "/project/node_modules/lodash/trim.js", + "/project/node_modules/lodash/trimEnd.js", + "/project/node_modules/lodash/trimStart.js", + "/project/node_modules/lodash/truncate.js", + "/project/node_modules/lodash/unary.js", + "/project/node_modules/lodash/unescape.js", + "/project/node_modules/lodash/union.js", + "/project/node_modules/lodash/unionBy.js", + "/project/node_modules/lodash/unionWith.js", + "/project/node_modules/lodash/uniq.js", + "/project/node_modules/lodash/uniqBy.js", + "/project/node_modules/lodash/uniqueId.js", + "/project/node_modules/lodash/uniqWith.js", + "/project/node_modules/lodash/unset.js", + "/project/node_modules/lodash/unzip.js", + "/project/node_modules/lodash/unzipWith.js", + "/project/node_modules/lodash/update.js", + "/project/node_modules/lodash/updateWith.js", + "/project/node_modules/lodash/upperCase.js", + "/project/node_modules/lodash/upperFirst.js", + "/project/node_modules/lodash/util.js", + "/project/node_modules/lodash/value.js", + "/project/node_modules/lodash/valueOf.js", + "/project/node_modules/lodash/values.js", + "/project/node_modules/lodash/valuesIn.js", + "/project/node_modules/lodash/without.js", + "/project/node_modules/lodash/words.js", + "/project/node_modules/lodash/wrap.js", + "/project/node_modules/lodash/wrapperAt.js", + "/project/node_modules/lodash/wrapperChain.js", + "/project/node_modules/lodash/wrapperLodash.js", + "/project/node_modules/lodash/wrapperReverse.js", + "/project/node_modules/lodash/wrapperValue.js", + "/project/node_modules/lodash/xor.js", + "/project/node_modules/lodash/xorBy.js", + "/project/node_modules/lodash/xorWith.js", + "/project/node_modules/lodash/zip.js", + "/project/node_modules/lodash/zipObject.js", + "/project/node_modules/lodash/zipObjectDeep.js", + "/project/node_modules/lodash/zipWith.js", +}; + +pub const three = [_][]const u8{ + "/project/node_modules/three/src", + "/project/node_modules/three/src/renderers", + "/project/node_modules/three/src/renderers/webgl", + "/project/node_modules/three/src/renderers/webgl/WebGLPrograms.js", + "/project/node_modules/three/src/renderers/webgl/WebGLGeometries.js", + "/project/node_modules/three/src/renderers/webgl/WebGLClipping.js", + "/project/node_modules/three/src/renderers/webgl/WebGLUniforms.js", + "/project/node_modules/three/src/renderers/webgl/WebGLShader.js", + "/project/node_modules/three/src/renderers/webgl/plugins", + "/project/node_modules/three/src/renderers/webgl/plugins/SpritePlugin.js", + "/project/node_modules/three/src/renderers/webgl/plugins/LensFlarePlugin.js", + "/project/node_modules/three/src/renderers/webgl/WebGLExtensions.js", + "/project/node_modules/three/src/renderers/webgl/WebGLBufferRenderer.js", + "/project/node_modules/three/src/renderers/webgl/WebGLObjects.js", + "/project/node_modules/three/src/renderers/webgl/WebGLLights.js", + "/project/node_modules/three/src/renderers/webgl/WebGLCapabilities.js", + "/project/node_modules/three/src/renderers/webgl/WebGLIndexedBufferRenderer.js", + "/project/node_modules/three/src/renderers/webgl/WebGLProperties.js", + "/project/node_modules/three/src/renderers/webgl/WebGLState.js", + "/project/node_modules/three/src/renderers/webgl/WebGLShadowMap.js", + "/project/node_modules/three/src/renderers/webgl/WebGLProgram.js", + "/project/node_modules/three/src/renderers/WebGLRenderTargetCube.js", + "/project/node_modules/three/src/renderers/shaders", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/color_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/uv2_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/ambient_pars.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/roughnessmap_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/roughnessmap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/uv2_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/encodings_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/clipping_planes_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/clipping_planes_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/envmap_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/normal_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/metalnessmap_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/color_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/common.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/lights_pars.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/aomap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/tonemapping_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/skinning_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/tonemapping_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/beginnormal_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/aomap_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/encodings_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/clipping_planes_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/map_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/project_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/clipping_planes_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/lights_template.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/packing.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/premultiplied_alpha_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/fog_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/bsdfs.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/begin_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/uv_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/metalnessmap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/uv2_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/emissivemap_pars_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk/displacementmap_pars_vertex.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderChunk.js", + "/project/node_modules/three/src/renderers/shaders/UniformsUtils.js", + "/project/node_modules/three/src/renderers/shaders/ShaderLib.js", + "/project/node_modules/three/src/renderers/shaders/DefinesUtils.js", + "/project/node_modules/three/src/renderers/shaders/ShaderLib", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshbasic_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/shadow_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshlambert_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/points_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/equirect_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/cube_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshphong_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/normal_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/depth_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/distanceRGBA_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/linedashed_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/normal_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/depth_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/linedashed_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/shadow_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshbasic_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshlambert_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/points_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/equirect_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/cube_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshphysical_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshphong_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/UniformsLib.js", + "/project/node_modules/three/src/renderers/WebGLRenderer.js", + "/project/node_modules/three/src/renderers/WebGLRenderTarget.js", + "/project/node_modules/three/src/textures", + "/project/node_modules/three/src/textures/DepthTexture.js", + "/project/node_modules/three/src/textures/CompressedTexture.js", + "/project/node_modules/three/src/textures/VideoTexture.js", + "/project/node_modules/three/src/textures/CubeTexture.js", + "/project/node_modules/three/src/textures/CanvasTexture.js", + "/project/node_modules/three/src/textures/Texture.js", + "/project/node_modules/three/src/textures/DataTexture.js", + "/project/node_modules/three/src/scenes", + "/project/node_modules/three/src/scenes/Fog.js", + "/project/node_modules/three/src/scenes/Scene.js", + "/project/node_modules/three/src/scenes/FogExp2.js", + "/project/node_modules/three/src/materials", + "/project/node_modules/three/src/materials/MultiMaterial.js", + "/project/node_modules/three/src/materials/LineDashedMaterial.js", + "/project/node_modules/three/src/materials/LineBasicMaterial.js", + "/project/node_modules/three/src/materials/MeshNormalMaterial.js", + "/project/node_modules/three/src/materials/Material.js", + "/project/node_modules/three/src/materials/MeshPhysicalMaterial.js", + "/project/node_modules/three/src/materials/MeshBasicMaterial.js", + "/project/node_modules/three/src/materials/MeshStandardMaterial.js", + "/project/node_modules/three/src/materials/MeshPhongMaterial.js", + "/project/node_modules/three/src/materials/SpriteMaterial.js", + "/project/node_modules/three/src/materials/MeshDepthMaterial.js", + "/project/node_modules/three/src/materials/ShadowMaterial.js", + "/project/node_modules/three/src/materials/PointsMaterial.js", + "/project/node_modules/three/src/materials/ShaderMaterial.js", + "/project/node_modules/three/src/materials/MeshLambertMaterial.js", + "/project/node_modules/three/src/materials/RawShaderMaterial.js", + "/project/node_modules/three/src/core", + "/project/node_modules/three/src/core/InstancedBufferAttribute.js", + "/project/node_modules/three/src/core/Face3.js", + "/project/node_modules/three/src/core/Clock.js", + "/project/node_modules/three/src/core/BufferAttribute.js", + "/project/node_modules/three/src/core/Raycaster.js", + "/project/node_modules/three/src/core/InstancedInterleavedBuffer.js", + "/project/node_modules/three/src/core/InterleavedBufferAttribute.js", + "/project/node_modules/three/src/core/EventDispatcher.js", + "/project/node_modules/three/src/core/InstancedBufferGeometry.js", + "/project/node_modules/three/src/core/Layers.js", + "/project/node_modules/three/src/core/Uniform.js", + "/project/node_modules/three/src/core/BufferGeometry.js", + "/project/node_modules/three/src/core/DirectGeometry.js", + "/project/node_modules/three/src/core/Geometry.js", + "/project/node_modules/three/src/core/InterleavedBuffer.js", + "/project/node_modules/three/src/core/Object3D.js", + "/project/node_modules/three/src/Three.js", + "/project/node_modules/three/src/animation", + "/project/node_modules/three/src/animation/AnimationUtils.js", + "/project/node_modules/three/src/animation/PropertyBinding.js", + "/project/node_modules/three/src/animation/KeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks", + "/project/node_modules/three/src/animation/tracks/VectorKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/NumberKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/ColorKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/StringKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/QuaternionKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/BooleanKeyframeTrack.js", + "/project/node_modules/three/src/animation/AnimationMixer.js", + "/project/node_modules/three/src/animation/PropertyMixer.js", + "/project/node_modules/three/src/animation/AnimationClip.js", + "/project/node_modules/three/src/animation/AnimationAction.js", + "/project/node_modules/three/src/animation/AnimationObjectGroup.js", + "/project/node_modules/three/src/objects", + "/project/node_modules/three/src/objects/Line.js", + "/project/node_modules/three/src/objects/Skeleton.js", + "/project/node_modules/three/src/objects/Mesh.js", + "/project/node_modules/three/src/objects/LensFlare.js", + "/project/node_modules/three/src/objects/Points.js", + "/project/node_modules/three/src/objects/LOD.js", + "/project/node_modules/three/src/objects/LineSegments.js", + "/project/node_modules/three/src/objects/Bone.js", + "/project/node_modules/three/src/objects/Sprite.js", + "/project/node_modules/three/src/objects/SkinnedMesh.js", + "/project/node_modules/three/src/objects/Group.js", + "/project/node_modules/three/src/cameras", + "/project/node_modules/three/src/cameras/CubeCamera.js", + "/project/node_modules/three/src/cameras/StereoCamera.js", + "/project/node_modules/three/src/cameras/PerspectiveCamera.js", + "/project/node_modules/three/src/cameras/Camera.js", + "/project/node_modules/three/src/cameras/OrthographicCamera.js", + "/project/node_modules/three/src/math", + "/project/node_modules/three/src/math/Vector2.js", + "/project/node_modules/three/src/math/Quaternion.js", + "/project/node_modules/three/src/math/Matrix3.js", + "/project/node_modules/three/src/math/Vector3.js", + "/project/node_modules/three/src/math/Ray.js", + "/project/node_modules/three/src/math/Spline.js", + "/project/node_modules/three/src/math/Color.js", + "/project/node_modules/three/src/math/Box3.js", + "/project/node_modules/three/src/math/Math.js", + "/project/node_modules/three/src/math/Euler.js", + "/project/node_modules/three/src/math/Frustum.js", + "/project/node_modules/three/src/math/Plane.js", + "/project/node_modules/three/src/math/Sphere.js", + "/project/node_modules/three/src/math/Interpolant.js", + "/project/node_modules/three/src/math/Box2.js", + "/project/node_modules/three/src/math/Line3.js", + "/project/node_modules/three/src/math/interpolants", + "/project/node_modules/three/src/math/interpolants/QuaternionLinearInterpolant.js", + "/project/node_modules/three/src/math/interpolants/LinearInterpolant.js", + "/project/node_modules/three/src/math/interpolants/DiscreteInterpolant.js", + "/project/node_modules/three/src/math/interpolants/CubicInterpolant.js", + "/project/node_modules/three/src/math/Vector4.js", + "/project/node_modules/three/src/math/Matrix4.js", + "/project/node_modules/three/src/math/Spherical.js", + "/project/node_modules/three/src/math/Triangle.js", + "/project/node_modules/three/src/audio", + "/project/node_modules/three/src/audio/AudioContext.js", + "/project/node_modules/three/src/audio/AudioAnalyser.js", + "/project/node_modules/three/src/audio/AudioListener.js", + "/project/node_modules/three/src/audio/PositionalAudio.js", + "/project/node_modules/three/src/audio/Audio.js", + "/project/node_modules/three/src/Three.Legacy.js", + "/project/node_modules/three/src/loaders", + "/project/node_modules/three/src/loaders/ImageLoader.js", + "/project/node_modules/three/src/loaders/FontLoader.js", + "/project/node_modules/three/src/loaders/AnimationLoader.js", + "/project/node_modules/three/src/loaders/Cache.js", + "/project/node_modules/three/src/loaders/MaterialLoader.js", + "/project/node_modules/three/src/loaders/TextureLoader.js", + "/project/node_modules/three/src/loaders/LoadingManager.js", + "/project/node_modules/three/src/loaders/ObjectLoader.js", + "/project/node_modules/three/src/loaders/XHRLoader.js", + "/project/node_modules/three/src/loaders/CubeTextureLoader.js", + "/project/node_modules/three/src/loaders/AudioLoader.js", + "/project/node_modules/three/src/loaders/BufferGeometryLoader.js", + "/project/node_modules/three/src/loaders/CompressedTextureLoader.js", + "/project/node_modules/three/src/loaders/JSONLoader.js", + "/project/node_modules/three/src/loaders/BinaryTextureLoader.js", + "/project/node_modules/three/src/loaders/Loader.js", + "/project/node_modules/three/src/lights", + "/project/node_modules/three/src/lights/DirectionalLight.js", + "/project/node_modules/three/src/lights/SpotLightShadow.js", + "/project/node_modules/three/src/lights/AmbientLight.js", + "/project/node_modules/three/src/lights/SpotLight.js", + "/project/node_modules/three/src/lights/HemisphereLight.js", + "/project/node_modules/three/src/lights/Light.js", + "/project/node_modules/three/src/lights/DirectionalLightShadow.js", + "/project/node_modules/three/src/lights/LightShadow.js", + "/project/node_modules/three/src/lights/PointLight.js", + "/project/node_modules/three/src/extras", + "/project/node_modules/three/src/extras/SceneUtils.js", + "/project/node_modules/three/src/extras/core", + "/project/node_modules/three/src/extras/core/Font.js", + "/project/node_modules/three/src/extras/core/Path.js", + "/project/node_modules/three/src/extras/core/CurvePath.js", + "/project/node_modules/three/src/extras/core/Curve.js", + "/project/node_modules/three/src/extras/core/Shape.js", + "/project/node_modules/three/src/extras/ShapeUtils.js", + "/project/node_modules/three/src/extras/objects", + "/project/node_modules/three/src/extras/objects/MorphBlendMesh.js", + "/project/node_modules/three/src/extras/objects/ImmediateRenderObject.js", + "/project/node_modules/three/src/extras/geometries", + "/project/node_modules/three/src/extras/geometries/TextGeometry.js", + "/project/node_modules/three/src/extras/geometries/WireframeGeometry.js", + "/project/node_modules/three/src/extras/geometries/PlaneGeometry.js", + "/project/node_modules/three/src/extras/geometries/DodecahedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/CircleBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/ParametricGeometry.js", + "/project/node_modules/three/src/extras/geometries/SphereBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/RingBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/BoxGeometry.js", + "/project/node_modules/three/src/extras/geometries/EdgesGeometry.js", + "/project/node_modules/three/src/extras/geometries/TetrahedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/RingGeometry.js", + "/project/node_modules/three/src/extras/geometries/ConeBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/LatheBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/LatheGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/SphereGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusGeometry.js", + "/project/node_modules/three/src/extras/geometries/IcosahedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/CircleGeometry.js", + "/project/node_modules/three/src/extras/geometries/ShapeGeometry.js", + "/project/node_modules/three/src/extras/geometries/PlaneBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusKnotBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/BoxBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/CylinderGeometry.js", + "/project/node_modules/three/src/extras/geometries/ExtrudeGeometry.js", + "/project/node_modules/three/src/extras/geometries/ConeGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusKnotGeometry.js", + "/project/node_modules/three/src/extras/geometries/TubeGeometry.js", + "/project/node_modules/three/src/extras/geometries/CylinderBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/PolyhedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/OctahedronGeometry.js", + "/project/node_modules/three/src/extras/CurveUtils.js", + "/project/node_modules/three/src/extras/helpers", + "/project/node_modules/three/src/extras/helpers/WireframeHelper.js", + "/project/node_modules/three/src/extras/helpers/ArrowHelper.js", + "/project/node_modules/three/src/extras/helpers/SkeletonHelper.js", + "/project/node_modules/three/src/extras/helpers/PointLightHelper.js", + "/project/node_modules/three/src/extras/helpers/AxisHelper.js", + "/project/node_modules/three/src/extras/helpers/SpotLightHelper.js", + "/project/node_modules/three/src/extras/helpers/CameraHelper.js", + "/project/node_modules/three/src/extras/helpers/BoxHelper.js", + "/project/node_modules/three/src/extras/helpers/VertexNormalsHelper.js", + "/project/node_modules/three/src/extras/helpers/BoundingBoxHelper.js", + "/project/node_modules/three/src/extras/helpers/EdgesHelper.js", + "/project/node_modules/three/src/extras/helpers/FaceNormalsHelper.js", + "/project/node_modules/three/src/extras/helpers/GridHelper.js", + "/project/node_modules/three/src/extras/helpers/HemisphereLightHelper.js", + "/project/node_modules/three/src/extras/helpers/DirectionalLightHelper.js", + "/project/node_modules/three/src/extras/curves", + "/project/node_modules/three/src/extras/curves/CubicBezierCurve.js", + "/project/node_modules/three/src/extras/curves/EllipseCurve.js", + "/project/node_modules/three/src/extras/curves/LineCurve3.js", + "/project/node_modules/three/src/extras/curves/SplineCurve3.js", + "/project/node_modules/three/src/extras/curves/ArcCurve.js", + "/project/node_modules/three/src/extras/curves/ClosedSplineCurve3.js", + "/project/node_modules/three/src/extras/curves/CubicBezierCurve3.js", + "/project/node_modules/three/src/extras/curves/QuadraticBezierCurve3.js", + "/project/node_modules/three/src/extras/curves/QuadraticBezierCurve.js", + "/project/node_modules/three/src/extras/curves/LineCurve.js", + "/project/node_modules/three/src/extras/curves/CatmullRomCurve3.js", + "/project/node_modules/three/src/extras/curves/SplineCurve.js", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/depth_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/distanceRGBA_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/linedashed_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/normal_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/depth_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/linedashed_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/shadow_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshbasic_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshlambert_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/points_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/equirect_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/cube_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshphysical_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshphong_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/UniformsLib.js", + "/project/node_modules/three/src/renderers/WebGLRenderer.js", + "/project/node_modules/three/src/renderers/WebGLRenderTarget.js", + "/project/node_modules/three/src/textures", + "/project/node_modules/three/src/textures/DepthTexture.js", + "/project/node_modules/three/src/textures/CompressedTexture.js", + "/project/node_modules/three/src/textures/VideoTexture.js", + "/project/node_modules/three/src/textures/CubeTexture.js", + "/project/node_modules/three/src/textures/CanvasTexture.js", + "/project/node_modules/three/src/textures/Texture.js", + "/project/node_modules/three/src/textures/DataTexture.js", + "/project/node_modules/three/src/scenes", + "/project/node_modules/three/src/scenes/Fog.js", + "/project/node_modules/three/src/scenes/Scene.js", + "/project/node_modules/three/src/scenes/FogExp2.js", + "/project/node_modules/three/src/materials", + "/project/node_modules/three/src/materials/MultiMaterial.js", + "/project/node_modules/three/src/materials/LineDashedMaterial.js", + "/project/node_modules/three/src/materials/LineBasicMaterial.js", + "/project/node_modules/three/src/materials/MeshNormalMaterial.js", + "/project/node_modules/three/src/materials/Material.js", + "/project/node_modules/three/src/materials/MeshPhysicalMaterial.js", + "/project/node_modules/three/src/materials/MeshBasicMaterial.js", + "/project/node_modules/three/src/materials/MeshStandardMaterial.js", + "/project/node_modules/three/src/materials/MeshPhongMaterial.js", + "/project/node_modules/three/src/materials/SpriteMaterial.js", + "/project/node_modules/three/src/materials/MeshDepthMaterial.js", + "/project/node_modules/three/src/materials/ShadowMaterial.js", + "/project/node_modules/three/src/materials/PointsMaterial.js", + "/project/node_modules/three/src/materials/ShaderMaterial.js", + "/project/node_modules/three/src/materials/MeshLambertMaterial.js", + "/project/node_modules/three/src/materials/RawShaderMaterial.js", + "/project/node_modules/three/src/core", + "/project/node_modules/three/src/core/InstancedBufferAttribute.js", + "/project/node_modules/three/src/core/Face3.js", + "/project/node_modules/three/src/core/Clock.js", + "/project/node_modules/three/src/core/BufferAttribute.js", + "/project/node_modules/three/src/core/Raycaster.js", + "/project/node_modules/three/src/core/InstancedInterleavedBuffer.js", + "/project/node_modules/three/src/core/InterleavedBufferAttribute.js", + "/project/node_modules/three/src/core/EventDispatcher.js", + "/project/node_modules/three/src/core/InstancedBufferGeometry.js", + "/project/node_modules/three/src/core/Layers.js", + "/project/node_modules/three/src/core/Uniform.js", + "/project/node_modules/three/src/core/BufferGeometry.js", + "/project/node_modules/three/src/core/DirectGeometry.js", + "/project/node_modules/three/src/core/Geometry.js", + "/project/node_modules/three/src/core/InterleavedBuffer.js", + "/project/node_modules/three/src/core/Object3D.js", + "/project/node_modules/three/src/Three.js", + "/project/node_modules/three/src/animation", + "/project/node_modules/three/src/animation/AnimationUtils.js", + "/project/node_modules/three/src/animation/PropertyBinding.js", + "/project/node_modules/three/src/animation/KeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks", + "/project/node_modules/three/src/animation/tracks/VectorKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/NumberKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/ColorKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/StringKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/QuaternionKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/BooleanKeyframeTrack.js", + "/project/node_modules/three/src/animation/AnimationMixer.js", + "/project/node_modules/three/src/animation/PropertyMixer.js", + "/project/node_modules/three/src/animation/AnimationClip.js", + "/project/node_modules/three/src/animation/AnimationAction.js", + "/project/node_modules/three/src/animation/AnimationObjectGroup.js", + "/project/node_modules/three/src/objects", + "/project/node_modules/three/src/objects/Line.js", + "/project/node_modules/three/src/objects/Skeleton.js", + "/project/node_modules/three/src/objects/Mesh.js", + "/project/node_modules/three/src/objects/LensFlare.js", + "/project/node_modules/three/src/objects/Points.js", + "/project/node_modules/three/src/objects/LOD.js", + "/project/node_modules/three/src/objects/LineSegments.js", + "/project/node_modules/three/src/objects/Bone.js", + "/project/node_modules/three/src/objects/Sprite.js", + "/project/node_modules/three/src/objects/SkinnedMesh.js", + "/project/node_modules/three/src/objects/Group.js", + "/project/node_modules/three/src/cameras", + "/project/node_modules/three/src/cameras/CubeCamera.js", + "/project/node_modules/three/src/cameras/StereoCamera.js", + "/project/node_modules/three/src/cameras/PerspectiveCamera.js", + "/project/node_modules/three/src/cameras/Camera.js", + "/project/node_modules/three/src/cameras/OrthographicCamera.js", + "/project/node_modules/three/src/math", + "/project/node_modules/three/src/math/Vector2.js", + "/project/node_modules/three/src/math/Quaternion.js", + "/project/node_modules/three/src/math/Matrix3.js", + "/project/node_modules/three/src/math/Vector3.js", + "/project/node_modules/three/src/math/Ray.js", + "/project/node_modules/three/src/math/Spline.js", + "/project/node_modules/three/src/math/Color.js", + "/project/node_modules/three/src/math/Box3.js", + "/project/node_modules/three/src/math/Math.js", + "/project/node_modules/three/src/math/Euler.js", + "/project/node_modules/three/src/math/Frustum.js", + "/project/node_modules/three/src/math/Plane.js", + "/project/node_modules/three/src/math/Sphere.js", + "/project/node_modules/three/src/math/Interpolant.js", + "/project/node_modules/three/src/math/Box2.js", + "/project/node_modules/three/src/math/Line3.js", + "/project/node_modules/three/src/math/interpolants", + "/project/node_modules/three/src/math/interpolants/QuaternionLinearInterpolant.js", + "/project/node_modules/three/src/math/interpolants/LinearInterpolant.js", + "/project/node_modules/three/src/math/interpolants/DiscreteInterpolant.js", + "/project/node_modules/three/src/math/interpolants/CubicInterpolant.js", + "/project/node_modules/three/src/math/Vector4.js", + "/project/node_modules/three/src/math/Matrix4.js", + "/project/node_modules/three/src/math/Spherical.js", + "/project/node_modules/three/src/math/Triangle.js", + "/project/node_modules/three/src/audio", + "/project/node_modules/three/src/audio/AudioContext.js", + "/project/node_modules/three/src/audio/AudioAnalyser.js", + "/project/node_modules/three/src/audio/AudioListener.js", + "/project/node_modules/three/src/audio/PositionalAudio.js", + "/project/node_modules/three/src/audio/Audio.js", + "/project/node_modules/three/src/Three.Legacy.js", + "/project/node_modules/three/src/loaders", + "/project/node_modules/three/src/loaders/ImageLoader.js", + "/project/node_modules/three/src/loaders/FontLoader.js", + "/project/node_modules/three/src/loaders/AnimationLoader.js", + "/project/node_modules/three/src/loaders/Cache.js", + "/project/node_modules/three/src/loaders/MaterialLoader.js", + "/project/node_modules/three/src/loaders/TextureLoader.js", + "/project/node_modules/three/src/loaders/LoadingManager.js", + "/project/node_modules/three/src/loaders/ObjectLoader.js", + "/project/node_modules/three/src/loaders/XHRLoader.js", + "/project/node_modules/three/src/loaders/CubeTextureLoader.js", + "/project/node_modules/three/src/loaders/AudioLoader.js", + "/project/node_modules/three/src/loaders/BufferGeometryLoader.js", + "/project/node_modules/three/src/loaders/CompressedTextureLoader.js", + "/project/node_modules/three/src/loaders/JSONLoader.js", + "/project/node_modules/three/src/loaders/BinaryTextureLoader.js", + "/project/node_modules/three/src/loaders/Loader.js", + "/project/node_modules/three/src/lights", + "/project/node_modules/three/src/lights/DirectionalLight.js", + "/project/node_modules/three/src/lights/SpotLightShadow.js", + "/project/node_modules/three/src/lights/AmbientLight.js", + "/project/node_modules/three/src/lights/SpotLight.js", + "/project/node_modules/three/src/lights/HemisphereLight.js", + "/project/node_modules/three/src/lights/Light.js", + "/project/node_modules/three/src/lights/DirectionalLightShadow.js", + "/project/node_modules/three/src/lights/LightShadow.js", + "/project/node_modules/three/src/lights/PointLight.js", + "/project/node_modules/three/src/extras", + "/project/node_modules/three/src/extras/SceneUtils.js", + "/project/node_modules/three/src/extras/core", + "/project/node_modules/three/src/extras/core/Font.js", + "/project/node_modules/three/src/extras/core/Path.js", + "/project/node_modules/three/src/extras/core/CurvePath.js", + "/project/node_modules/three/src/extras/core/Curve.js", + "/project/node_modules/three/src/extras/core/Shape.js", + "/project/node_modules/three/src/extras/ShapeUtils.js", + "/project/node_modules/three/src/extras/objects", + "/project/node_modules/three/src/extras/objects/MorphBlendMesh.js", + "/project/node_modules/three/src/extras/objects/ImmediateRenderObject.js", + "/project/node_modules/three/src/extras/geometries", + "/project/node_modules/three/src/extras/geometries/TextGeometry.js", + "/project/node_modules/three/src/extras/geometries/WireframeGeometry.js", + "/project/node_modules/three/src/extras/geometries/PlaneGeometry.js", + "/project/node_modules/three/src/extras/geometries/DodecahedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/CircleBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/ParametricGeometry.js", + "/project/node_modules/three/src/extras/geometries/SphereBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/RingBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/BoxGeometry.js", + "/project/node_modules/three/src/extras/geometries/EdgesGeometry.js", + "/project/node_modules/three/src/extras/geometries/TetrahedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/RingGeometry.js", + "/project/node_modules/three/src/extras/geometries/ConeBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/LatheBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/LatheGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/SphereGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusGeometry.js", + "/project/node_modules/three/src/extras/geometries/IcosahedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/CircleGeometry.js", + "/project/node_modules/three/src/extras/geometries/ShapeGeometry.js", + "/project/node_modules/three/src/extras/geometries/PlaneBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusKnotBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/BoxBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/CylinderGeometry.js", + "/project/node_modules/three/src/extras/geometries/ExtrudeGeometry.js", + "/project/node_modules/three/src/extras/geometries/ConeGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusKnotGeometry.js", + "/project/node_modules/three/src/extras/geometries/TubeGeometry.js", + "/project/node_modules/three/src/extras/geometries/CylinderBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/PolyhedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/OctahedronGeometry.js", + "/project/node_modules/three/src/extras/CurveUtils.js", + "/project/node_modules/three/src/extras/helpers", + "/project/node_modules/three/src/extras/helpers/WireframeHelper.js", + "/project/node_modules/three/src/extras/helpers/ArrowHelper.js", + "/project/node_modules/three/src/extras/helpers/SkeletonHelper.js", + "/project/node_modules/three/src/extras/helpers/PointLightHelper.js", + "/project/node_modules/three/src/extras/helpers/AxisHelper.js", + "/project/node_modules/three/src/extras/helpers/SpotLightHelper.js", + "/project/node_modules/three/src/extras/helpers/CameraHelper.js", + "/project/node_modules/three/src/extras/helpers/BoxHelper.js", + "/project/node_modules/three/src/extras/helpers/VertexNormalsHelper.js", + "/project/node_modules/three/src/extras/helpers/BoundingBoxHelper.js", + "/project/node_modules/three/src/extras/helpers/EdgesHelper.js", + "/project/node_modules/three/src/extras/helpers/FaceNormalsHelper.js", + "/project/node_modules/three/src/extras/helpers/GridHelper.js", + "/project/node_modules/three/src/extras/helpers/HemisphereLightHelper.js", + "/project/node_modules/three/src/extras/helpers/DirectionalLightHelper.js", + "/project/node_modules/three/src/extras/curves", + "/project/node_modules/three/src/extras/curves/CubicBezierCurve.js", + "/project/node_modules/three/src/extras/curves/EllipseCurve.js", + "/project/node_modules/three/src/extras/curves/LineCurve3.js", + "/project/node_modules/three/src/extras/curves/SplineCurve3.js", + "/project/node_modules/three/src/extras/curves/ArcCurve.js", + "/project/node_modules/three/src/extras/curves/ClosedSplineCurve3.js", + "/project/node_modules/three/src/extras/curves/CubicBezierCurve3.js", + "/project/node_modules/three/src/extras/curves/QuadraticBezierCurve3.js", + "/project/node_modules/three/src/extras/curves/QuadraticBezierCurve.js", + "/project/node_modules/three/src/extras/curves/LineCurve.js", + "/project/node_modules/three/src/extras/curves/CatmullRomCurve3.js", + "/project/node_modules/three/src/extras/curves/SplineCurve.js", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/depth_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/distanceRGBA_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/linedashed_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/normal_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/depth_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/linedashed_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/shadow_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshbasic_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshlambert_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/points_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/equirect_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/cube_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshphysical_vert.glsl", + "/project/node_modules/three/src/renderers/shaders/ShaderLib/meshphong_frag.glsl", + "/project/node_modules/three/src/renderers/shaders/UniformsLib.js", + "/project/node_modules/three/src/renderers/WebGLRenderer.js", + "/project/node_modules/three/src/renderers/WebGLRenderTarget.js", + "/project/node_modules/three/src/textures", + "/project/node_modules/three/src/textures/DepthTexture.js", + "/project/node_modules/three/src/textures/CompressedTexture.js", + "/project/node_modules/three/src/textures/VideoTexture.js", + "/project/node_modules/three/src/textures/CubeTexture.js", + "/project/node_modules/three/src/textures/CanvasTexture.js", + "/project/node_modules/three/src/textures/Texture.js", + "/project/node_modules/three/src/textures/DataTexture.js", + "/project/node_modules/three/src/scenes", + "/project/node_modules/three/src/scenes/Fog.js", + "/project/node_modules/three/src/scenes/Scene.js", + "/project/node_modules/three/src/scenes/FogExp2.js", + "/project/node_modules/three/src/materials", + "/project/node_modules/three/src/materials/MultiMaterial.js", + "/project/node_modules/three/src/materials/LineDashedMaterial.js", + "/project/node_modules/three/src/materials/LineBasicMaterial.js", + "/project/node_modules/three/src/materials/MeshNormalMaterial.js", + "/project/node_modules/three/src/materials/Material.js", + "/project/node_modules/three/src/materials/MeshPhysicalMaterial.js", + "/project/node_modules/three/src/materials/MeshBasicMaterial.js", + "/project/node_modules/three/src/materials/MeshStandardMaterial.js", + "/project/node_modules/three/src/materials/MeshPhongMaterial.js", + "/project/node_modules/three/src/materials/SpriteMaterial.js", + "/project/node_modules/three/src/materials/MeshDepthMaterial.js", + "/project/node_modules/three/src/materials/ShadowMaterial.js", + "/project/node_modules/three/src/materials/PointsMaterial.js", + "/project/node_modules/three/src/materials/ShaderMaterial.js", + "/project/node_modules/three/src/materials/MeshLambertMaterial.js", + "/project/node_modules/three/src/materials/RawShaderMaterial.js", + "/project/node_modules/three/src/core", + "/project/node_modules/three/src/core/InstancedBufferAttribute.js", + "/project/node_modules/three/src/core/Face3.js", + "/project/node_modules/three/src/core/Clock.js", + "/project/node_modules/three/src/core/BufferAttribute.js", + "/project/node_modules/three/src/core/Raycaster.js", + "/project/node_modules/three/src/core/InstancedInterleavedBuffer.js", + "/project/node_modules/three/src/core/InterleavedBufferAttribute.js", + "/project/node_modules/three/src/core/EventDispatcher.js", + "/project/node_modules/three/src/core/InstancedBufferGeometry.js", + "/project/node_modules/three/src/core/Layers.js", + "/project/node_modules/three/src/core/Uniform.js", + "/project/node_modules/three/src/core/BufferGeometry.js", + "/project/node_modules/three/src/core/DirectGeometry.js", + "/project/node_modules/three/src/core/Geometry.js", + "/project/node_modules/three/src/core/InterleavedBuffer.js", + "/project/node_modules/three/src/core/Object3D.js", + "/project/node_modules/three/src/Three.js", + "/project/node_modules/three/src/animation", + "/project/node_modules/three/src/animation/AnimationUtils.js", + "/project/node_modules/three/src/animation/PropertyBinding.js", + "/project/node_modules/three/src/animation/KeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks", + "/project/node_modules/three/src/animation/tracks/VectorKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/NumberKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/ColorKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/StringKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/QuaternionKeyframeTrack.js", + "/project/node_modules/three/src/animation/tracks/BooleanKeyframeTrack.js", + "/project/node_modules/three/src/animation/AnimationMixer.js", + "/project/node_modules/three/src/animation/PropertyMixer.js", + "/project/node_modules/three/src/animation/AnimationClip.js", + "/project/node_modules/three/src/animation/AnimationAction.js", + "/project/node_modules/three/src/animation/AnimationObjectGroup.js", + "/project/node_modules/three/src/objects", + "/project/node_modules/three/src/objects/Line.js", + "/project/node_modules/three/src/objects/Skeleton.js", + "/project/node_modules/three/src/objects/Mesh.js", + "/project/node_modules/three/src/objects/LensFlare.js", + "/project/node_modules/three/src/objects/Points.js", + "/project/node_modules/three/src/objects/LOD.js", + "/project/node_modules/three/src/objects/LineSegments.js", + "/project/node_modules/three/src/objects/Bone.js", + "/project/node_modules/three/src/objects/Sprite.js", + "/project/node_modules/three/src/objects/SkinnedMesh.js", + "/project/node_modules/three/src/objects/Group.js", + "/project/node_modules/three/src/cameras", + "/project/node_modules/three/src/cameras/CubeCamera.js", + "/project/node_modules/three/src/cameras/StereoCamera.js", + "/project/node_modules/three/src/cameras/PerspectiveCamera.js", + "/project/node_modules/three/src/cameras/Camera.js", + "/project/node_modules/three/src/cameras/OrthographicCamera.js", + "/project/node_modules/three/src/math", + "/project/node_modules/three/src/math/Vector2.js", + "/project/node_modules/three/src/math/Quaternion.js", + "/project/node_modules/three/src/math/Matrix3.js", + "/project/node_modules/three/src/math/Vector3.js", + "/project/node_modules/three/src/math/Ray.js", + "/project/node_modules/three/src/math/Spline.js", + "/project/node_modules/three/src/math/Color.js", + "/project/node_modules/three/src/math/Box3.js", + "/project/node_modules/three/src/math/Math.js", + "/project/node_modules/three/src/math/Euler.js", + "/project/node_modules/three/src/math/Frustum.js", + "/project/node_modules/three/src/math/Plane.js", + "/project/node_modules/three/src/math/Sphere.js", + "/project/node_modules/three/src/math/Interpolant.js", + "/project/node_modules/three/src/math/Box2.js", + "/project/node_modules/three/src/math/Line3.js", + "/project/node_modules/three/src/math/interpolants", + "/project/node_modules/three/src/math/interpolants/QuaternionLinearInterpolant.js", + "/project/node_modules/three/src/math/interpolants/LinearInterpolant.js", + "/project/node_modules/three/src/math/interpolants/DiscreteInterpolant.js", + "/project/node_modules/three/src/math/interpolants/CubicInterpolant.js", + "/project/node_modules/three/src/math/Vector4.js", + "/project/node_modules/three/src/math/Matrix4.js", + "/project/node_modules/three/src/math/Spherical.js", + "/project/node_modules/three/src/math/Triangle.js", + "/project/node_modules/three/src/audio", + "/project/node_modules/three/src/audio/AudioContext.js", + "/project/node_modules/three/src/audio/AudioAnalyser.js", + "/project/node_modules/three/src/audio/AudioListener.js", + "/project/node_modules/three/src/audio/PositionalAudio.js", + "/project/node_modules/three/src/audio/Audio.js", + "/project/node_modules/three/src/Three.Legacy.js", + "/project/node_modules/three/src/loaders", + "/project/node_modules/three/src/loaders/ImageLoader.js", + "/project/node_modules/three/src/loaders/FontLoader.js", + "/project/node_modules/three/src/loaders/AnimationLoader.js", + "/project/node_modules/three/src/loaders/Cache.js", + "/project/node_modules/three/src/loaders/MaterialLoader.js", + "/project/node_modules/three/src/loaders/TextureLoader.js", + "/project/node_modules/three/src/loaders/LoadingManager.js", + "/project/node_modules/three/src/loaders/ObjectLoader.js", + "/project/node_modules/three/src/loaders/XHRLoader.js", + "/project/node_modules/three/src/loaders/CubeTextureLoader.js", + "/project/node_modules/three/src/loaders/AudioLoader.js", + "/project/node_modules/three/src/loaders/BufferGeometryLoader.js", + "/project/node_modules/three/src/loaders/CompressedTextureLoader.js", + "/project/node_modules/three/src/loaders/JSONLoader.js", + "/project/node_modules/three/src/loaders/BinaryTextureLoader.js", + "/project/node_modules/three/src/loaders/Loader.js", + "/project/node_modules/three/src/lights", + "/project/node_modules/three/src/lights/DirectionalLight.js", + "/project/node_modules/three/src/lights/SpotLightShadow.js", + "/project/node_modules/three/src/lights/AmbientLight.js", + "/project/node_modules/three/src/lights/SpotLight.js", + "/project/node_modules/three/src/lights/HemisphereLight.js", + "/project/node_modules/three/src/lights/Light.js", + "/project/node_modules/three/src/lights/DirectionalLightShadow.js", + "/project/node_modules/three/src/lights/LightShadow.js", + "/project/node_modules/three/src/lights/PointLight.js", + "/project/node_modules/three/src/extras", + "/project/node_modules/three/src/extras/SceneUtils.js", + "/project/node_modules/three/src/extras/core", + "/project/node_modules/three/src/extras/core/Font.js", + "/project/node_modules/three/src/extras/core/Path.js", + "/project/node_modules/three/src/extras/core/CurvePath.js", + "/project/node_modules/three/src/extras/core/Curve.js", + "/project/node_modules/three/src/extras/core/Shape.js", + "/project/node_modules/three/src/extras/ShapeUtils.js", + "/project/node_modules/three/src/extras/objects", + "/project/node_modules/three/src/extras/objects/MorphBlendMesh.js", + "/project/node_modules/three/src/extras/objects/ImmediateRenderObject.js", + "/project/node_modules/three/src/extras/geometries", + "/project/node_modules/three/src/extras/geometries/TextGeometry.js", + "/project/node_modules/three/src/extras/geometries/WireframeGeometry.js", + "/project/node_modules/three/src/extras/geometries/PlaneGeometry.js", + "/project/node_modules/three/src/extras/geometries/DodecahedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/CircleBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/ParametricGeometry.js", + "/project/node_modules/three/src/extras/geometries/SphereBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/RingBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/BoxGeometry.js", + "/project/node_modules/three/src/extras/geometries/EdgesGeometry.js", + "/project/node_modules/three/src/extras/geometries/TetrahedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/RingGeometry.js", + "/project/node_modules/three/src/extras/geometries/ConeBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/LatheBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/LatheGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/SphereGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusGeometry.js", + "/project/node_modules/three/src/extras/geometries/IcosahedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/CircleGeometry.js", + "/project/node_modules/three/src/extras/geometries/ShapeGeometry.js", + "/project/node_modules/three/src/extras/geometries/PlaneBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusKnotBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/BoxBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/CylinderGeometry.js", + "/project/node_modules/three/src/extras/geometries/ExtrudeGeometry.js", + "/project/node_modules/three/src/extras/geometries/ConeGeometry.js", + "/project/node_modules/three/src/extras/geometries/TorusKnotGeometry.js", + "/project/node_modules/three/src/extras/geometries/TubeGeometry.js", + "/project/node_modules/three/src/extras/geometries/CylinderBufferGeometry.js", + "/project/node_modules/three/src/extras/geometries/PolyhedronGeometry.js", + "/project/node_modules/three/src/extras/geometries/OctahedronGeometry.js", + "/project/node_modules/three/src/extras/CurveUtils.js", + "/project/node_modules/three/src/extras/helpers", + "/project/node_modules/three/src/extras/helpers/WireframeHelper.js", + "/project/node_modules/three/src/extras/helpers/ArrowHelper.js", + "/project/node_modules/three/src/extras/helpers/SkeletonHelper.js", + "/project/node_modules/three/src/extras/helpers/PointLightHelper.js", + "/project/node_modules/three/src/extras/helpers/AxisHelper.js", + "/project/node_modules/three/src/extras/helpers/SpotLightHelper.js", + "/project/node_modules/three/src/extras/helpers/CameraHelper.js", + "/project/node_modules/three/src/extras/helpers/BoxHelper.js", + "/project/node_modules/three/src/extras/helpers/VertexNormalsHelper.js", + "/project/node_modules/three/src/extras/helpers/BoundingBoxHelper.js", + "/project/node_modules/three/src/extras/helpers/EdgesHelper.js", + "/project/node_modules/three/src/extras/helpers/FaceNormalsHelper.js", + "/project/node_modules/three/src/extras/helpers/GridHelper.js", + "/project/node_modules/three/src/extras/helpers/HemisphereLightHelper.js", + "/project/node_modules/three/src/extras/helpers/DirectionalLightHelper.js", + "/project/node_modules/three/src/extras/curves", + "/project/node_modules/three/src/extras/curves/CubicBezierCurve.js", + "/project/node_modules/three/src/extras/curves/EllipseCurve.js", + "/project/node_modules/three/src/extras/curves/LineCurve3.js", + "/project/node_modules/three/src/extras/curves/SplineCurve3.js", + "/project/node_modules/three/src/extras/curves/ArcCurve.js", + "/project/node_modules/three/src/extras/curves/ClosedSplineCurve3.js", + "/project/node_modules/three/src/extras/curves/CubicBezierCurve3.js", + "/project/node_modules/three/src/extras/curves/QuadraticBezierCurve3.js", + "/project/node_modules/three/src/extras/curves/QuadraticBezierCurve.js", + "/project/node_modules/three/src/extras/curves/LineCurve.js", + "/project/node_modules/three/src/extras/curves/CatmullRomCurve3.js", + "/project/node_modules/three/src/extras/curves/SplineCurve.js", +}; |