diff options
author | 2023-04-24 14:11:59 -0700 | |
---|---|---|
committer | 2023-04-24 14:11:59 -0700 | |
commit | 923ac39c0b718ac5d488f65232f0dcd7161423d4 (patch) | |
tree | c4a35c8e7c8f16a5139a4622b8a26ff2331f85b6 /src/bun.js/bindings/ModuleLoader.cpp | |
parent | 98209b8e101c8c0199f1360f7c1781938f502ed8 (diff) | |
download | bun-923ac39c0b718ac5d488f65232f0dcd7161423d4.tar.gz bun-923ac39c0b718ac5d488f65232f0dcd7161423d4.tar.zst bun-923ac39c0b718ac5d488f65232f0dcd7161423d4.zip |
Support plugins in `Bun.build` (#2720)
* wip
* Implement `onLoad` plugins
* Support exceptions and async `onLoad` plugins
* Fix filtering
* Handle empty files
* Fix JSON loader
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src/bun.js/bindings/ModuleLoader.cpp')
-rw-r--r-- | src/bun.js/bindings/ModuleLoader.cpp | 139 |
1 files changed, 119 insertions, 20 deletions
diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp index 40e41b083..00b975d88 100644 --- a/src/bun.js/bindings/ModuleLoader.cpp +++ b/src/bun.js/bindings/ModuleLoader.cpp @@ -40,7 +40,56 @@ namespace Bun { using namespace Zig; using namespace WebCore; -extern "C" BunLoaderType Bun__getDefaultLoader(JSC::JSGlobalObject*, ZigString* specifier); +extern "C" BunLoaderType Bun__getDefaultLoader(JSC::JSGlobalObject*, const ZigString* specifier); +extern "C" BunLoaderType JSBundlerPlugin__getDefaultLoader(void* context); +extern "C" void JSBundlerPlugin__OnLoadAsync(void* ctx, EncodedJSValue errorValue, ZigString* sourceCode, BunLoaderType loader); +OnLoadResult handleOnLoadResult(Zig::GlobalObject* globalObject, JSC::JSValue objectValue, const ZigString* specifier, void* context); + +JSValue handleVirtualModuleResultForJSBundlerPlugin( + Zig::GlobalObject* globalObject, + JSValue virtualModuleResult, + const ZigString* specifier, + const ZigString* referrer, + void* bundlerPluginContext) +{ + auto onLoadResult = handleOnLoadResult(globalObject, virtualModuleResult, specifier, bundlerPluginContext); + JSC::VM& vm = globalObject->vm(); + + switch (onLoadResult.type) { + case OnLoadResultTypeCode: { + JSBundlerPlugin__OnLoadAsync(bundlerPluginContext, JSValue::encode({}), &onLoadResult.value.sourceText.string, onLoadResult.value.sourceText.loader); + return jsUndefined(); + } + case OnLoadResultTypeError: { + JSBundlerPlugin__OnLoadAsync(bundlerPluginContext, JSValue::encode(onLoadResult.value.error), nullptr, BunLoaderTypeNone); + return jsUndefined(); + } + + case OnLoadResultTypePromise: { + JSFunction* performPromiseThenFunction = globalObject->performPromiseThenFunction(); + auto callData = JSC::getCallData(performPromiseThenFunction); + ASSERT(callData.type != CallData::Type::None); + auto specifierString = Zig::toString(*specifier); + auto referrerString = referrer ? Zig::toString(*referrer) : String(); + PendingVirtualModuleResult* pendingModule = PendingVirtualModuleResult::create(globalObject, specifierString, referrerString, bundlerPluginContext); + pendingModule->internalField(2).set(vm, pendingModule, virtualModuleResult); + JSC::JSPromise* promise = pendingModule->promise(); + + MarkedArgumentBuffer arguments; + arguments.append(promise); + arguments.append(globalObject->thenable(jsFunctionOnLoadObjectResultResolveForJSBundlerPlugin)); + arguments.append(globalObject->thenable(jsFunctionOnLoadObjectResultRejectForJSBundlerPlugin)); + arguments.append(jsUndefined()); + arguments.append(pendingModule); + ASSERT(!arguments.hasOverflowed()); + JSC::call(globalObject, performPromiseThenFunction, callData, jsUndefined(), arguments); + return promise; + } + default: { + __builtin_unreachable(); + } + } +} static JSC::JSInternalPromise* rejectedInternalPromise(JSC::JSGlobalObject* globalObject, JSC::JSValue value) { @@ -88,11 +137,16 @@ JSC::JSInternalPromise* PendingVirtualModuleResult::internalPromise() return jsCast<JSC::JSInternalPromise*>(internalField(2).get()); } +JSC::JSPromise* PendingVirtualModuleResult::promise() +{ + return jsCast<JSC::JSPromise*>(internalField(2).get()); +} + const ClassInfo PendingVirtualModuleResult::s_info = { "PendingVirtualModule"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(PendingVirtualModuleResult) }; -PendingVirtualModuleResult* PendingVirtualModuleResult::create(VM& vm, Structure* structure) +PendingVirtualModuleResult* PendingVirtualModuleResult::create(VM& vm, Structure* structure, void* bundlerPluginContext) { - PendingVirtualModuleResult* mod = new (NotNull, allocateCell<PendingVirtualModuleResult>(vm)) PendingVirtualModuleResult(vm, structure); + PendingVirtualModuleResult* mod = new (NotNull, allocateCell<PendingVirtualModuleResult>(vm)) PendingVirtualModuleResult(vm, structure, bundlerPluginContext); return mod; } Structure* PendingVirtualModuleResult::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) @@ -100,8 +154,9 @@ Structure* PendingVirtualModuleResult::createStructure(VM& vm, JSGlobalObject* g return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); } -PendingVirtualModuleResult::PendingVirtualModuleResult(VM& vm, Structure* structure) +PendingVirtualModuleResult::PendingVirtualModuleResult(VM& vm, Structure* structure, void* bundlerPluginContext) : Base(vm, structure) + , m_bundlerPluginContext(bundlerPluginContext) { } @@ -110,7 +165,9 @@ void PendingVirtualModuleResult::finishCreation(VM& vm, const WTF::String& speci Base::finishCreation(vm); Base::internalField(0).set(vm, this, JSC::jsString(vm, specifier)); Base::internalField(1).set(vm, this, JSC::jsString(vm, referrer)); - Base::internalField(2).set(vm, this, JSC::JSInternalPromise::create(vm, globalObject()->internalPromiseStructure())); + if (!this->m_bundlerPluginContext) { + Base::internalField(2).set(vm, this, JSC::JSInternalPromise::create(vm, globalObject()->internalPromiseStructure())); + } } template<typename Visitor> @@ -123,21 +180,22 @@ void PendingVirtualModuleResult::visitChildrenImpl(JSCell* cell, Visitor& visito DEFINE_VISIT_CHILDREN(PendingVirtualModuleResult); -PendingVirtualModuleResult* PendingVirtualModuleResult::create(JSC::JSGlobalObject* globalObject, const WTF::String& specifier, const WTF::String& referrer) +PendingVirtualModuleResult* PendingVirtualModuleResult::create(JSC::JSGlobalObject* globalObject, const WTF::String& specifier, const WTF::String& referrer, void* bundlerPluginContext) { - auto* virtualModule = create(globalObject->vm(), reinterpret_cast<Zig::GlobalObject*>(globalObject)->pendingVirtualModuleResultStructure()); + auto* virtualModule = create(globalObject->vm(), reinterpret_cast<Zig::GlobalObject*>(globalObject)->pendingVirtualModuleResultStructure(), bundlerPluginContext); virtualModule->finishCreation(globalObject->vm(), specifier, referrer); return virtualModule; } -OnLoadResult handleOnLoadResultNotPromise(Zig::GlobalObject* globalObject, JSC::JSValue objectValue, ZigString* specifier) +OnLoadResult handleOnLoadResultNotPromise(Zig::GlobalObject* globalObject, JSC::JSValue objectValue, const ZigString* specifier, void* bunPluginContext) { OnLoadResult result = {}; result.type = OnLoadResultTypeError; + result.bundlerPluginContext = bunPluginContext; JSC::VM& vm = globalObject->vm(); result.value.error = JSC::jsUndefined(); auto scope = DECLARE_THROW_SCOPE(vm); - BunLoaderType loader = Bun__getDefaultLoader(globalObject, specifier); + BunLoaderType loader = bunPluginContext ? JSBundlerPlugin__getDefaultLoader(bunPluginContext) : Bun__getDefaultLoader(globalObject, specifier); if (JSC::Exception* exception = JSC::jsDynamicCast<JSC::Exception*>(objectValue)) { result.value.error = exception->value(); @@ -211,16 +269,17 @@ OnLoadResult handleOnLoadResultNotPromise(Zig::GlobalObject* globalObject, JSC:: return result; } -static OnLoadResult handleOnLoadResult(Zig::GlobalObject* globalObject, JSC::JSValue objectValue, ZigString* specifier) +OnLoadResult handleOnLoadResult(Zig::GlobalObject* globalObject, JSC::JSValue objectValue, const ZigString* specifier, void* context) { if (JSC::JSPromise* promise = JSC::jsDynamicCast<JSC::JSPromise*>(objectValue)) { OnLoadResult result = {}; result.type = OnLoadResultTypePromise; result.value.promise = objectValue; + result.bundlerPluginContext = context; return result; } - return handleOnLoadResultNotPromise(globalObject, objectValue, specifier); + return handleOnLoadResultNotPromise(globalObject, objectValue, specifier, context); } template<bool allowPromise> @@ -228,10 +287,10 @@ static JSValue handleVirtualModuleResult( Zig::GlobalObject* globalObject, JSValue virtualModuleResult, ErrorableResolvedSource* res, - ZigString* specifier, - ZigString* referrer) + const ZigString* specifier, + const ZigString* referrer) { - auto onLoadResult = handleOnLoadResult(globalObject, virtualModuleResult, specifier); + auto onLoadResult = handleOnLoadResult(globalObject, virtualModuleResult, specifier, nullptr); JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); @@ -353,8 +412,8 @@ template<bool allowPromise> static JSValue fetchSourceCode( Zig::GlobalObject* globalObject, ErrorableResolvedSource* res, - ZigString* specifier, - ZigString* referrer) + const ZigString* specifier, + const ZigString* referrer) { void* bunVM = globalObject->bunVM(); auto& vm = globalObject->vm(); @@ -486,6 +545,46 @@ static JSValue fetchSourceCode( return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider)))); } +extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultResolveForJSBundlerPlugin(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + JSC::VM& vm = globalObject->vm(); + ErrorableResolvedSource res = {}; + res.success = false; + JSC::JSValue objectResult = callFrame->argument(0); + PendingVirtualModuleResult* pendingModule = JSC::jsCast<PendingVirtualModuleResult*>(callFrame->argument(1)); + JSC::JSValue specifierString = pendingModule->internalField(0).get(); + JSC::JSValue referrerString = pendingModule->internalField(1).get(); + pendingModule->internalField(0).set(vm, pendingModule, JSC::jsUndefined()); + pendingModule->internalField(1).set(vm, pendingModule, JSC::jsUndefined()); + void* bunPluginContext = pendingModule->m_bundlerPluginContext; + JSC::JSPromise* promise = pendingModule->promise(); + + ZigString specifier = Zig::toZigString(specifierString, globalObject); + ZigString referrer = Zig::toZigString(referrerString, globalObject); + return JSC::JSValue::encode( + handleVirtualModuleResultForJSBundlerPlugin(reinterpret_cast<Zig::GlobalObject*>(globalObject), objectResult, &specifier, &referrer, bunPluginContext)); +} + +extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultRejectForJSBundlerPlugin(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + JSC::VM& vm = globalObject->vm(); + ErrorableResolvedSource res = {}; + JSC::JSValue reason = callFrame->argument(0); + PendingVirtualModuleResult* pendingModule = JSC::jsCast<PendingVirtualModuleResult*>(callFrame->argument(1)); + JSC::JSValue specifierString = pendingModule->internalField(0).get(); + JSC::JSValue referrerString = pendingModule->internalField(1).get(); + pendingModule->internalField(0).set(vm, pendingModule, JSC::jsUndefined()); + pendingModule->internalField(1).set(vm, pendingModule, JSC::jsUndefined()); + + ZigString specifier = Zig::toZigString(specifierString, globalObject); + ZigString referrer = Zig::toZigString(referrerString, globalObject); + pendingModule->internalField(2).set(vm, pendingModule, JSC::jsUndefined()); + + JSBundlerPlugin__OnLoadAsync(pendingModule->m_bundlerPluginContext, JSValue::encode(reason), nullptr, BunLoaderTypeNone); + + return JSValue::encode(reason); +} + extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultResolve(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) { JSC::VM& vm = globalObject->vm(); @@ -544,8 +643,8 @@ extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultReject(JSC::JSGlobalO JSValue fetchSourceCodeSync( Zig::GlobalObject* globalObject, ErrorableResolvedSource* res, - ZigString* specifier, - ZigString* referrer) + const ZigString* specifier, + const ZigString* referrer) { return fetchSourceCode<false>(globalObject, res, specifier, referrer); } @@ -553,8 +652,8 @@ JSValue fetchSourceCodeSync( JSValue fetchSourceCodeAsync( Zig::GlobalObject* globalObject, ErrorableResolvedSource* res, - ZigString* specifier, - ZigString* referrer) + const ZigString* specifier, + const ZigString* referrer) { return fetchSourceCode<true>(globalObject, res, specifier, referrer); } |