Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
b94bfc5
document that
zackradisic Jul 3, 2025
5004362
think that fixed that
zackradisic Jul 3, 2025
f3be9b5
Okay that's the fix
zackradisic Jul 3, 2025
0b15f98
Document
zackradisic Jul 3, 2025
33d60b6
Test the named import bug
zackradisic Jul 3, 2025
6347c7f
Support catch-all routes
zackradisic Jul 3, 2025
3881ee1
kinda working sourcemap but with bug
zackradisic Jul 4, 2025
163e83f
Fix bug
zackradisic Jul 5, 2025
f0a605a
yoops
zackradisic Jul 5, 2025
aeddc6b
fix
zackradisic Jul 5, 2025
18b6b94
that works
zackradisic Jul 5, 2025
a88a94c
Merge branch 'main' into zack/ssg-2
zackradisic Jul 7, 2025
ee44ef5
Move per thread data outside
zackradisic Jul 7, 2025
d1bada7
fix import meta thing
zackradisic Jul 8, 2025
ecf1d1b
more test
zackradisic Jul 8, 2025
5f6f2e9
why tf is that there
zackradisic Jul 8, 2025
a6ac500
stuff
zackradisic Jul 8, 2025
ee319cf
don't crash with empty chunks list
zackradisic Jul 8, 2025
52c2487
more tests
zackradisic Jul 8, 2025
54f8153
fix catch all
zackradisic Jul 8, 2025
cf8c118
fix some stuff
zackradisic Jul 9, 2025
eb7e4d6
fix sourcemap crash in dev server
zackradisic Jul 10, 2025
4e338fc
register client and server sourcemaps properly
zackradisic Jul 10, 2025
0225723
add test for edgecase
zackradisic Jul 10, 2025
7eb340a
write runtime to disk for client side code
zackradisic Jul 10, 2025
8ab8e61
don't include client files in static only route
zackradisic Jul 12, 2025
c61d7eb
yoops
zackradisic Jul 12, 2025
7608393
error on using useState in server component
zackradisic Jul 12, 2025
c21e947
fix default import from client component
zackradisic Jul 12, 2025
9343189
Fix tests
zackradisic Jul 12, 2025
b8bf55e
don't include that
zackradisic Jul 12, 2025
a8604f5
fuck
zackradisic Jul 12, 2025
901b66b
stuff
zackradisic Jul 13, 2025
2a3c283
stuff
zackradisic Jul 14, 2025
498e313
stuff
zackradisic Jul 14, 2025
39cf845
Better name
zackradisic Jul 14, 2025
49db94d
yoops
zackradisic Jul 14, 2025
82f5acd
yoops
zackradisic Jul 14, 2025
1b55912
comment
zackradisic Jul 14, 2025
be424e5
fix crash
zackradisic Jul 15, 2025
b298cc8
lmao
zackradisic Jul 16, 2025
913d48c
damn
zackradisic Jul 16, 2025
b116bd9
Merge branch 'main' into zack/ssg-2
zackradisic Jul 17, 2025
28030d7
`bun scripts/glob-sources.mjs`
zackradisic Jul 17, 2025
1db235f
Merge branch 'main' into zack/ssg-2
zackradisic Jul 17, 2025
4def9fa
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 17, 2025
50053b6
resolve comments
zackradisic Jul 17, 2025
29938a6
Merge branch 'zack/ssg-2' of github.com:oven-sh/bun into zack/ssg-2
zackradisic Jul 17, 2025
5d2a7c8
remove stupid printfs
zackradisic Jul 18, 2025
ed55ccc
unsafely ref to stay alive
zackradisic Jul 18, 2025
c8da04f
fix bad crash
zackradisic Jul 18, 2025
9bee24a
Fix tests
zackradisic Jul 18, 2025
ecc8557
fix tests
zackradisic Jul 18, 2025
0aafdfe
proper useState check that does not apply to react internally
zackradisic Jul 18, 2025
22af318
check scope
zackradisic Jul 18, 2025
439d620
fix
zackradisic Jul 18, 2025
4381646
fix windows
zackradisic Jul 18, 2025
6b815e1
more fix
zackradisic Jul 18, 2025
14aa227
lol
zackradisic Jul 18, 2025
37db72b
fix windows tests
zackradisic Jul 18, 2025
bf9fdb1
windows
zackradisic Jul 19, 2025
ebe60ce
Merge branch 'main' into zack/ssg-2
Jarred-Sumner Jul 19, 2025
f623023
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 19, 2025
dec703d
fix window
zackradisic Jul 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmake/sources/ZigSources.txt
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,14 @@ src/bundler/linker_context/generateCodeForLazyExport.zig
src/bundler/linker_context/generateCompileResultForCssChunk.zig
src/bundler/linker_context/generateCompileResultForHtmlChunk.zig
src/bundler/linker_context/generateCompileResultForJSChunk.zig
src/bundler/linker_context/OutputFileListBuilder.zig
src/bundler/linker_context/postProcessCSSChunk.zig
src/bundler/linker_context/postProcessHTMLChunk.zig
src/bundler/linker_context/postProcessJSChunk.zig
src/bundler/linker_context/prepareCssAstsForChunk.zig
src/bundler/linker_context/renameSymbolsInChunk.zig
src/bundler/linker_context/scanImportsAndExports.zig
src/bundler/linker_context/StaticRouteVisitor.zig
src/bundler/linker_context/writeOutputFilesToDisk.zig
src/bundler/LinkerContext.zig
src/bundler/LinkerGraph.zig
Expand Down
33 changes: 29 additions & 4 deletions src/OutputFile.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,24 @@ side: ?bun.bake.Side,
/// This is only set for the JS bundle, and not files associated with an
/// entrypoint like sourcemaps and bytecode
entry_point_index: ?u32,
referenced_css_files: []const Index = &.{},
referenced_css_chunks: []const Index = &.{},
source_index: Index.Optional = .none,
bake_extra: BakeExtra = .{},

pub const zero_value = OutputFile{
.loader = .file,
.src_path = Fs.Path.init(""),
.value = .noop,
.output_kind = .chunk,
.side = null,
.entry_point_index = null,
};

pub const BakeExtra = struct {
is_route: bool = false,
fully_static: bool = false,
bake_is_runtime: bool = false,
};

pub const Index = bun.GenericIndex(u32, OutputFile);

Expand All @@ -30,7 +46,7 @@ pub fn deinit(this: *OutputFile) void {

bun.default_allocator.free(this.src_path.text);
bun.default_allocator.free(this.dest_path);
bun.default_allocator.free(this.referenced_css_files);
bun.default_allocator.free(this.referenced_css_chunks);
}

// Depending on:
Expand Down Expand Up @@ -99,6 +115,13 @@ pub const Value = union(Kind) {
}
}

pub fn asSlice(v: Value) []const u8 {
return switch (v) {
.buffer => |buf| buf.bytes,
else => "",
};
}

pub fn toBunString(v: Value) bun.String {
return switch (v) {
.noop => bun.String.empty,
Expand Down Expand Up @@ -206,7 +229,8 @@ pub const Options = struct {
},
side: ?bun.bake.Side,
entry_point_index: ?u32,
referenced_css_files: []const Index = &.{},
referenced_css_chunks: []const Index = &.{},
bake_extra: BakeExtra = .{},
};

pub fn init(options: Options) OutputFile {
Expand Down Expand Up @@ -240,7 +264,8 @@ pub fn init(options: Options) OutputFile {
},
.side = options.side,
.entry_point_index = options.entry_point_index,
.referenced_css_files = options.referenced_css_files,
.referenced_css_chunks = options.referenced_css_chunks,
.bake_extra = options.bake_extra,
};
}

Expand Down
21 changes: 21 additions & 0 deletions src/api/schema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,27 @@ pub const Api = struct {

_,

pub fn fromJS(global: *bun.JSC.JSGlobalObject, value: bun.JSC.JSValue) bun.JSError!?SourceMapMode {
if (value.isString()) {
const str = try value.toSliceOrNull(global);
defer str.deinit();
const utf8 = str.slice();
if (bun.strings.eqlComptime(utf8, "none")) {
return .none;
}
if (bun.strings.eqlComptime(utf8, "inline")) {
return .@"inline";
}
if (bun.strings.eqlComptime(utf8, "external")) {
return .external;
}
if (bun.strings.eqlComptime(utf8, "linked")) {
return .linked;
}
}
return null;
}

pub fn jsonStringify(self: @This(), writer: anytype) !void {
return try writer.write(@tagName(self));
}
Expand Down
57 changes: 52 additions & 5 deletions src/bake/BakeGlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "JavaScriptCore/JSSourceCode.h"

extern "C" BunString BakeProdResolve(JSC::JSGlobalObject*, BunString a, BunString b);
extern "C" BunString BakeToWindowsPath(BunString a);

namespace Bake {
using namespace JSC;
Expand Down Expand Up @@ -107,7 +108,18 @@ static JSC::JSInternalPromise* resolvedInternalPromise(JSC::JSGlobalObject* glob
return promise;
}

extern "C" BunString BakeProdLoad(ProductionPerThread* perThreadData, BunString a);
extern "C" BunString BakeProdLoad(void* perThreadData, BunString a);

extern "C" bool BakeGlobalObject__isBakeGlobalObject(JSC::JSGlobalObject* global)
{
return global->JSCell::inherits(Bake::GlobalObject::info());
}

extern "C" void* BakeGlobalObject__getPerThreadData(JSC::JSGlobalObject* global)
{
Bake::GlobalObject* bake = jsCast<Bake::GlobalObject*>(global);
return bake->m_perThreadData;
}

JSC::JSInternalPromise* bakeModuleLoaderFetch(JSC::JSGlobalObject* globalObject,
JSC::JSModuleLoader* loader, JSC::JSValue key,
Expand All @@ -134,12 +146,33 @@ JSC::JSInternalPromise* bakeModuleLoaderFetch(JSC::JSGlobalObject* globalObject,
JSC::SourceProviderSourceType::Module));
return resolvedInternalPromise(globalObject, JSC::JSSourceCode::create(vm, WTFMove(sourceCode)));
}
return rejectedInternalPromise(globalObject, createTypeError(globalObject, makeString("Bundle does not have \""_s, moduleKey, "\". This is a bug in Bun's bundler."_s)));

// We unconditionally prefix the key with "bake:" inside
// BakeProdResolve in production.zig.
//
// But if someone does: `await import(resolve(import.meta.dir, "nav.ts"))`
// we don't actually want to load it from the Bake production module
// map and instead make it go through the normal codepath.
auto bakePrefixRemoved = moduleKey.substringSharingImpl("bake:"_s.length());

#ifdef _WIN32
// We normalize paths to contain forward slashes in bake so we don't
// have to worry about platform paths. Now we have to worry about
// it, because `moduleLoaderFetch(...)` may read the path from disk
// and so we need to give a Windows path to it.
auto temp = BakeToWindowsPath(Bun::toString(bakePrefixRemoved));
bakePrefixRemoved = temp.toWTFString();
#endif
JSString* bakePrefixRemovedString = jsNontrivialString(vm, bakePrefixRemoved);
JSValue bakePrefixRemovedJsvalue = bakePrefixRemovedString;
return Zig::GlobalObject::moduleLoaderFetch(globalObject, loader, bakePrefixRemovedJsvalue, parameters, script);
}
return rejectedInternalPromise(globalObject, createTypeError(globalObject, "BakeGlobalObject does not have per-thread data configured"_s));
}

return Zig::GlobalObject::moduleLoaderFetch(globalObject, loader, key, parameters, script);
auto result = Zig::GlobalObject::moduleLoaderFetch(globalObject, loader, key, parameters, script);
RETURN_IF_EXCEPTION(scope, rejectedInternalPromise(globalObject, scope.exception()->value()));
return result;
}

GlobalObject* GlobalObject::create(JSC::VM& vm, JSC::Structure* structure,
Expand Down Expand Up @@ -205,7 +238,16 @@ const JSC::GlobalObjectMethodTable& GlobalObject::globalObjectMethodTable()
// TODO: remove this entire method
extern "C" GlobalObject* BakeCreateProdGlobal(void* console)
{
JSC::VM& vm = JSC::VM::create(JSC::HeapType::Large).leakRef();
RefPtr<JSC::VM> vmPtr = JSC::VM::tryCreate(JSC::HeapType::Large);
if (!vmPtr) [[unlikely]] {
BUN_PANIC("Failed to allocate JavaScriptCore Virtual Machine. Did your computer run out of memory? Or maybe you compiled Bun with a mismatching libc++ version or compiler?");
}
// We need to unsafely ref this so it stays alive, later in
// `Zig__GlobalObject__destructOnExit` will call
// `vm.derefSuppressingSaferCPPChecking()` to free it.
vmPtr->refSuppressingSaferCPPChecking();
JSC::VM& vm = *vmPtr;

vm.heap.acquireAccess();
JSC::JSLockHolder locker(vm);
BunVirtualMachine* bunVM = Bun__getVM();
Expand All @@ -225,6 +267,11 @@ extern "C" GlobalObject* BakeCreateProdGlobal(void* console)
global->setStackTraceLimit(10); // Node.js defaults to 10
global->isThreadLocalDefaultGlobalObject = true;

// if (shouldDisableStopIfNecessaryTimer) {
vm.heap.disableStopIfNecessaryTimer();
// }

// if you process.nextTick on a microtask we need thsi
// TODO: it segfaults! process.nextTick is scoped out for now i guess!
// vm.setOnComputeErrorInfo(computeErrorInfoWrapper);
// vm.setOnEachMicrotaskTick([global](JSC::VM &vm) -> void {
Expand All @@ -240,7 +287,7 @@ extern "C" GlobalObject* BakeCreateProdGlobal(void* console)
return global;
}

extern "C" void BakeGlobalObject__attachPerThreadData(GlobalObject* global, ProductionPerThread* perThreadData)
extern "C" void BakeGlobalObject__attachPerThreadData(GlobalObject* global, void* perThreadData)
{
global->m_perThreadData = perThreadData;
}
Expand Down
7 changes: 4 additions & 3 deletions src/bake/BakeGlobalObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@

namespace Bake {

struct ProductionPerThread;

class GlobalObject : public Zig::GlobalObject {
public:
using Base = Zig::GlobalObject;

ProductionPerThread* m_perThreadData = nullptr;
void* m_perThreadData = nullptr;
DECLARE_INFO;

template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
Expand Down Expand Up @@ -39,4 +37,7 @@ class GlobalObject : public Zig::GlobalObject {
}
};

extern "C" void* BakeGlobalObject__getPerThreadData(JSC::JSGlobalObject* global);
extern "C" void BakeGlobalObject__attachPerThreadData(GlobalObject* global, void* perThreadData);

}; // namespace Kit
2 changes: 1 addition & 1 deletion src/bake/BakeSourceProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ extern "C" BunString BakeSourceProvider__getSourceSlice(SourceProvider* provider
return Bun::toStringView(provider->source());
}

extern "C" JSC::EncodedJSValue BakeLoadInitialServerCode(GlobalObject* global, BunString source, bool separateSSRGraph) {
extern "C" JSC::EncodedJSValue BakeLoadInitialServerCode(JSC::JSGlobalObject* global, BunString source, bool separateSSRGraph) {
auto& vm = JSC::getVM(global);
auto scope = DECLARE_THROW_SCOPE(vm);

Expand Down
31 changes: 29 additions & 2 deletions src/bake/FrameworkRouter.zig
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@ pub const EncodedPattern = struct {
},
.param => |name| {
const end = strings.indexOfCharPos(path, '/', i) orelse path.len;
// Check if we're about to exceed the maximum number of parameters
if (param_num >= MatchedParams.max_count) {
// TODO: ideally we should throw a nice user message
bun.Output.panic("Route pattern matched more than {d} parameters. Path: {s}", .{ MatchedParams.max_count, path });
}
params.params.len = @intCast(param_num + 1);
params.params.buffer[param_num] = .{
.key = name,
Expand All @@ -295,8 +300,30 @@ pub const EncodedPattern = struct {
param_num += 1;
i = if (end == path.len) end else end + 1;
},
.catch_all_optional => return true,
.catch_all => break,
.catch_all_optional, .catch_all => |name| {
// Capture remaining path segments as individual parameters
if (i < path.len) {
var segment_start = i;
while (segment_start < path.len) {
const segment_end = strings.indexOfCharPos(path, '/', segment_start) orelse path.len;
if (segment_start < segment_end) {
// Check if we're about to exceed the maximum number of parameters
if (param_num >= MatchedParams.max_count) {
// TODO: ideally we should throw a nice user message
bun.Output.panic("Route pattern matched more than {d} parameters. Path: {s}", .{ MatchedParams.max_count, path });
}
params.params.len = @intCast(param_num + 1);
params.params.buffer[param_num] = .{
.key = name,
.value = path[segment_start..segment_end],
};
param_num += 1;
}
segment_start = if (segment_end == path.len) segment_end else segment_end + 1;
}
}
return true;
},
.group => continue,
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/bake/bake.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,9 @@ declare module "bun" {
}

type GetParamIterator =
| AsyncIterable<Record<string, string>, GetParamsFinalOpts>
| Iterable<Record<string, string>, GetParamsFinalOpts>
| ({ pages: Array<Record<string, string>> } & GetParamsFinalOpts);
| AsyncIterable<Record<string, string | string[]>, GetParamsFinalOpts>
| Iterable<Record<string, string | string[]>, GetParamsFinalOpts>
| ({ pages: Array<Record<string, string | string[]>> } & GetParamsFinalOpts);

type GetParamsFinalOpts = void | null | {
/**
Expand Down Expand Up @@ -478,7 +478,7 @@ declare module "bun" {
*/
readonly layouts: ReadonlyArray<any>;
/** Received route params. `null` if the route does not take params */
readonly params: null | Record<string, string>;
readonly params: null | Record<string, string | string[]>;
/**
* A list of js files that the route will need to be interactive.
*/
Expand Down
Loading