mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
### What does this PR do?
Fixes a crash related to the dev server overwriting the uws user context
pointer when setting abort callback.
Adds support for `return new Response(<jsx />, { ... })` and `return
Response.render(...)` and `return Response.redirect(...)`:
- Created a `SSRResponse` class to handle this (see
`JSBakeResponse.{h,cpp}`)
- `SSRResponse` is designed to "fake" being a React component
- This is done in JSBakeResponse::create inside of
src/bun.js/bindings/JSBakeResponse.cpp
- And `src/js/builtins/BakeSSRResponse.ts` defines a `wrapComponent`
function which wraps
the passed in component (when doing `new Response(<jsx />, ...)`). It
does
this to throw an error (in redirect()/render() case) or return the
component.
- Created a `BakeAdditionsToGlobal` struct which contains some
properties
needed for this
- Added some of the properties we need to fake to BunBuiltinNames.h
(e.g.
`$$typeof`), the rationale behind this is that we couldn't use
`structure->addPropertyTransition` because JSBakeResponse is not a final
JSObject.
- When bake and server-side, bundler rewrites `Response ->
Bun.SSRResponse` (see `src/ast/P.zig` and `src/ast/visitExpr.zig`)
- Created a new WebCore body variant (`Render: struct { path: []const u8
}`)
- Created when `return Response.render(...)`
- When handled, it re-invokes dev server to render the new path
Enables server-side sourcemaps for the dev server:
- New source providers for server-side:
(`DevServerSourceProvider.{h,cpp}`)
- IncrementalGraph and SourceMapStore are updated to support this
There are numerous other stuff:
- allow `app` configuration from Bun.serve(...)
- fix errors stopping dev server
- fix use after free related to in
RequestContext.finishRunningErrorHandler
- Request.cookies
- Make `"use client";` components work
- Fix some bugs using `require(...)` in dev server
- Fix catch-all routes not working in the dev server
- Updates `findSourceMappingURL(...)` to use `std.mem.lastIndexOf(...)`
because
the sourcemap that should be used is the last one anyway
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Alistair Smith <hi@alistair.sh>
174 lines
6.0 KiB
C++
174 lines
6.0 KiB
C++
// clang-format off
|
|
#include "BakeSourceProvider.h"
|
|
#include "DevServerSourceProvider.h"
|
|
#include "BakeGlobalObject.h"
|
|
#include "JavaScriptCore/CallData.h"
|
|
#include "JavaScriptCore/Completion.h"
|
|
#include "JavaScriptCore/Identifier.h"
|
|
#include "JavaScriptCore/JSCJSValue.h"
|
|
#include "JavaScriptCore/JSCast.h"
|
|
#include "JavaScriptCore/JSLock.h"
|
|
#include "JavaScriptCore/JSMap.h"
|
|
#include "JavaScriptCore/JSModuleLoader.h"
|
|
#include "JavaScriptCore/JSModuleRecord.h"
|
|
#include "JavaScriptCore/JSString.h"
|
|
#include "JavaScriptCore/JSModuleNamespaceObject.h"
|
|
#include "ImportMetaObject.h"
|
|
|
|
namespace Bake {
|
|
|
|
|
|
extern "C" BunString BakeSourceProvider__getSourceSlice(SourceProvider* provider)
|
|
{
|
|
return Bun::toStringView(provider->source());
|
|
}
|
|
|
|
extern "C" JSC::EncodedJSValue BakeLoadInitialServerCode(JSC::JSGlobalObject* global, BunString source, bool separateSSRGraph) {
|
|
auto& vm = JSC::getVM(global);
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
String string = "bake://server-runtime.js"_s;
|
|
JSC::SourceOrigin origin = JSC::SourceOrigin(WTF::URL(string));
|
|
JSC::SourceCode sourceCode = JSC::SourceCode(SourceProvider::create(
|
|
global,
|
|
source.toWTFString(),
|
|
origin,
|
|
WTFMove(string),
|
|
WTF::TextPosition(),
|
|
JSC::SourceProviderSourceType::Program
|
|
));
|
|
|
|
JSC::JSValue fnValue = vm.interpreter.executeProgram(sourceCode, global, global);
|
|
RETURN_IF_EXCEPTION(scope, {});
|
|
|
|
RELEASE_ASSERT(fnValue);
|
|
|
|
JSC::JSFunction* fn = jsCast<JSC::JSFunction*>(fnValue);
|
|
JSC::CallData callData = JSC::getCallData(fn);
|
|
|
|
JSC::MarkedArgumentBuffer args;
|
|
args.append(JSC::jsBoolean(separateSSRGraph)); // separateSSRGraph
|
|
args.append(Zig::ImportMetaObject::create(global, "bake://server-runtime.js"_s)); // importMeta
|
|
|
|
RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::profiledCall(global, JSC::ProfilingReason::API, fn, callData, JSC::jsUndefined(), args)));
|
|
}
|
|
|
|
extern "C" JSC::JSInternalPromise* BakeLoadModuleByKey(GlobalObject* global, JSC::JSString* key) {
|
|
return global->moduleLoader()->loadAndEvaluateModule(global, key, JSC::jsUndefined(), JSC::jsUndefined());
|
|
}
|
|
|
|
extern "C" JSC::EncodedJSValue BakeLoadServerHmrPatch(GlobalObject* global, BunString source) {
|
|
JSC::VM&vm = global->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
String string = "bake://server.patch.js"_s;
|
|
JSC::SourceOrigin origin = JSC::SourceOrigin(WTF::URL(string));
|
|
JSC::SourceCode sourceCode = JSC::SourceCode(SourceProvider::create(
|
|
global,
|
|
source.toWTFString(),
|
|
origin,
|
|
WTFMove(string),
|
|
WTF::TextPosition(),
|
|
JSC::SourceProviderSourceType::Program
|
|
));
|
|
|
|
JSC::JSValue result = vm.interpreter.executeProgram(sourceCode, global, global);
|
|
RETURN_IF_EXCEPTION(scope, {});
|
|
|
|
RELEASE_ASSERT(result);
|
|
return JSC::JSValue::encode(result);
|
|
}
|
|
|
|
extern "C" JSC::EncodedJSValue BakeLoadServerHmrPatchWithSourceMap(GlobalObject* global, BunString source, const char* sourceMapJSONPtr, size_t sourceMapJSONLength) {
|
|
JSC::VM&vm = global->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
String string = "bake://server.patch.js"_s;
|
|
JSC::SourceOrigin origin = JSC::SourceOrigin(WTF::URL(string));
|
|
|
|
// Use DevServerSourceProvider with the source map JSON
|
|
auto provider = DevServerSourceProvider::create(
|
|
global,
|
|
source.toWTFString(),
|
|
sourceMapJSONPtr,
|
|
sourceMapJSONLength,
|
|
origin,
|
|
WTFMove(string),
|
|
WTF::TextPosition(),
|
|
JSC::SourceProviderSourceType::Program
|
|
);
|
|
|
|
JSC::SourceCode sourceCode = JSC::SourceCode(provider);
|
|
|
|
JSC::JSValue result = vm.interpreter.executeProgram(sourceCode, global, global);
|
|
RETURN_IF_EXCEPTION(scope, {});
|
|
|
|
RELEASE_ASSERT(result);
|
|
return JSC::JSValue::encode(result);
|
|
}
|
|
|
|
extern "C" JSC::EncodedJSValue BakeGetModuleNamespace(
|
|
JSC::JSGlobalObject* global,
|
|
JSC::JSValue keyValue
|
|
) {
|
|
JSC::JSString* key = JSC::jsCast<JSC::JSString*>(keyValue);
|
|
auto& vm = JSC::getVM(global);
|
|
JSC::JSMap* map = JSC::jsCast<JSC::JSMap*>(
|
|
global->moduleLoader()->getDirect(
|
|
vm, JSC::Identifier::fromString(global->vm(), "registry"_s)
|
|
));
|
|
JSC::JSValue entry = map->get(global, key);
|
|
ASSERT(entry.isObject()); // should have called BakeLoadServerCode and wait for that promise
|
|
JSC::JSValue module = entry.getObject()->get(global, JSC::Identifier::fromString(global->vm(), "module"_s));
|
|
ASSERT(module.isCell());
|
|
JSC::JSModuleNamespaceObject* namespaceObject = global->moduleLoader()->getModuleNamespaceObject(global, module);
|
|
ASSERT(namespaceObject);
|
|
return JSC::JSValue::encode(namespaceObject);
|
|
}
|
|
|
|
extern "C" JSC::EncodedJSValue BakeGetDefaultExportFromModule(
|
|
JSC::JSGlobalObject* global,
|
|
JSC::JSValue keyValue
|
|
) {
|
|
auto& vm = JSC::getVM(global);
|
|
return JSC::JSValue::encode(jsCast<JSC::JSModuleNamespaceObject*>(JSC::JSValue::decode(BakeGetModuleNamespace(global, keyValue)))->get(global, vm.propertyNames->defaultKeyword));
|
|
}
|
|
|
|
// There were issues when trying to use JSValue.get from zig
|
|
extern "C" JSC::EncodedJSValue BakeGetOnModuleNamespace(
|
|
JSC::JSGlobalObject* global,
|
|
JSC::JSModuleNamespaceObject* moduleNamespace,
|
|
const unsigned char* key,
|
|
size_t keyLength
|
|
) {
|
|
auto& vm = JSC::getVM(global);
|
|
const auto propertyString = String(StringImpl::createWithoutCopying({ key, keyLength }));
|
|
const auto identifier = JSC::Identifier::fromString(vm, propertyString);
|
|
const auto property = JSC::PropertyName(identifier);
|
|
return JSC::JSValue::encode(moduleNamespace->get(global, property));
|
|
}
|
|
|
|
extern "C" JSC::EncodedJSValue BakeRegisterProductionChunk(JSC::JSGlobalObject* global, BunString virtualPathName, BunString source) {
|
|
auto& vm = JSC::getVM(global);
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
String string = virtualPathName.toWTFString();
|
|
JSC::JSString* key = JSC::jsString(vm, string);
|
|
JSC::SourceOrigin origin = JSC::SourceOrigin(WTF::URL(string));
|
|
JSC::SourceCode sourceCode = JSC::SourceCode(SourceProvider::create(
|
|
global,
|
|
source.toWTFString(),
|
|
origin,
|
|
WTFMove(string),
|
|
WTF::TextPosition(),
|
|
JSC::SourceProviderSourceType::Module
|
|
));
|
|
|
|
global->moduleLoader()->provideFetch(global, key, sourceCode);
|
|
RETURN_IF_EXCEPTION(scope, {});
|
|
|
|
return JSC::JSValue::encode(key);
|
|
}
|
|
|
|
} // namespace Bake
|