aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-05-09 00:24:25 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-05-09 00:24:25 -0700
commit8014a0b8d8f5d9f7c20ad25f1ee7045bd2ca384a (patch)
tree8b5b2c4a67e64c6f04da79e8a0577a0ad78e6359
parent3bd83eb134f60044a231b6357e597be47831bdd4 (diff)
downloadbun-8014a0b8d8f5d9f7c20ad25f1ee7045bd2ca384a.tar.gz
bun-8014a0b8d8f5d9f7c20ad25f1ee7045bd2ca384a.tar.zst
bun-8014a0b8d8f5d9f7c20ad25f1ee7045bd2ca384a.zip
[napi] Support `import` and `require` of `.node` modules
-rw-r--r--src/base64/neonbase64.cc2
-rw-r--r--src/defines.zig23
-rw-r--r--src/javascript/jsc/bindings/Process.cpp2
-rw-r--r--src/javascript/jsc/bindings/ZigGlobalObject.cpp35
-rw-r--r--src/javascript/jsc/bindings/napi.cpp66
-rw-r--r--src/javascript/jsc/bindings/napi.h5
6 files changed, 80 insertions, 53 deletions
diff --git a/src/base64/neonbase64.cc b/src/base64/neonbase64.cc
index a1249d21b..deaf7ac38 100644
--- a/src/base64/neonbase64.cc
+++ b/src/base64/neonbase64.cc
@@ -6,7 +6,7 @@
#include "chromiumbase64.h"
#define MODP_B64_ERROR ((size_t)-1)
-#include <iostream>
+// #include <iostream>
extern "C" int neon_base64_decode(char *out, const char *src, size_t srclen, size_t *outlen);
diff --git a/src/defines.zig b/src/defines.zig
index 507ad8851..a0c885f34 100644
--- a/src/defines.zig
+++ b/src/defines.zig
@@ -196,11 +196,6 @@ pub const DotDefine = struct {
var nan_val = js_ast.E.Number{ .value = std.math.nan_f64 };
var inf_val = js_ast.E.Number{ .value = std.math.inf_f64 };
-const __dirname_str: string = std.fs.path.sep_str ++ "__dirname_is_not_implemented";
-const __filename_str: string = "__filename_is_not_implemented.js";
-var __dirname = js_ast.E.String.init(__dirname_str);
-var __filename = js_ast.E.String.init(__filename_str);
-
pub const Define = struct {
identifiers: std.StringHashMap(IdentifierDefine),
dots: std.StringHashMap([]DotDefine),
@@ -301,24 +296,6 @@ pub const Define = struct {
}
}
- // Node.js backwards compatibility hack
- define.identifiers.putAssumeCapacity(
- "__dirname",
- DefineData{
- .value = js_ast.Expr.Data{
- .e_string = &__dirname,
- },
- },
- );
- define.identifiers.putAssumeCapacity(
- "__filename",
- DefineData{
- .value = js_ast.Expr.Data{
- .e_string = &__filename,
- },
- },
- );
-
// Step 2. Swap in certain literal values because those can be constant folded
define.identifiers.putAssumeCapacity("undefined", .{
.value = val,
diff --git a/src/javascript/jsc/bindings/Process.cpp b/src/javascript/jsc/bindings/Process.cpp
index e732b0d54..5fc15db4d 100644
--- a/src/javascript/jsc/bindings/Process.cpp
+++ b/src/javascript/jsc/bindings/Process.cpp
@@ -146,7 +146,7 @@ static JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen,
if (!napi_register_module_v1) {
dlclose(handle);
- JSC::throwTypeError(globalObject, scope, "dlopen failed to napi_register_module_v1"_s);
+ JSC::throwTypeError(globalObject, scope, "symbol 'napi_register_module_v1' not found in native module. Is this a Node API (napi) module?"_s);
return JSC::JSValue::encode(JSC::JSValue {});
}
diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
index 72ea28c59..3820dcef2 100644
--- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp
+++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
@@ -108,6 +108,9 @@ using JSObject = JSC::JSObject;
using JSNonFinalObject = JSC::JSNonFinalObject;
namespace JSCastingHelpers = JSC::JSCastingHelpers;
using JSBuffer = WebCore::JSBuffer;
+#include <dlfcn.h>
+
+// #include <iostream>
static bool has_loaded_jsc = false;
@@ -1041,6 +1044,38 @@ JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
auto moduleKey = key.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope));
+ if (moduleKey.endsWith(".node")) {
+ CString utf8 = moduleKey.utf8();
+ void* handle = dlopen(utf8.data(), RTLD_LAZY);
+
+ if (!handle) {
+ WTF::String msg = WTF::String::fromUTF8(dlerror());
+ return rejectWithError(JSC::createTypeError(globalObject, msg));
+ }
+
+ JSC::EncodedJSValue (*napi_register_module_v1)(JSC::JSGlobalObject * globalObject,
+ JSC::EncodedJSValue exports);
+
+ napi_register_module_v1 = reinterpret_cast<JSC::EncodedJSValue (*)(JSC::JSGlobalObject*,
+ JSC::EncodedJSValue)>(
+ dlsym(handle, "napi_register_module_v1"));
+
+ if (!napi_register_module_v1) {
+ dlclose(handle);
+ return rejectWithError(JSC::createTypeError(globalObject, "symbol 'napi_register_module_v1' not found in native module. Is this a Node API (napi) module?"_s));
+ }
+ JSC::JSValue exports = JSC::constructEmptyObject(globalObject);
+
+ JSC::JSValue returnedExports = JSC::JSValue::decode(napi_register_module_v1(globalObject, JSC::JSValue::encode(exports)));
+
+ auto sourceCode = Napi::generateSourceCode(moduleKey, vm, returnedExports.getObject(), globalObject);
+
+ scope.releaseAssertNoExceptionExceptTermination();
+ auto jsSourceCode = JSC::JSSourceCode::create(vm, WTFMove(sourceCode));
+ promise->resolve(globalObject, jsSourceCode);
+ return promise;
+ }
+
auto moduleKeyZig = toZigString(moduleKey);
auto source = Zig::toZigString(value1, globalObject);
ErrorableResolvedSource res;
diff --git a/src/javascript/jsc/bindings/napi.cpp b/src/javascript/jsc/bindings/napi.cpp
index 5ec8bb6b2..94c18ebac 100644
--- a/src/javascript/jsc/bindings/napi.cpp
+++ b/src/javascript/jsc/bindings/napi.cpp
@@ -44,11 +44,44 @@
#include "JavaScriptCore/JSWeakValue.h"
#include "napi.h"
#include "JavaScriptCore/GetterSetter.h"
+#include "JavaScriptCore/JSSourceCode.h"
-#include <iostream>
+// #include <iostream>
using namespace JSC;
using namespace Zig;
+namespace Napi {
+
+JSC::SourceCode generateSourceCode(WTF::String keyString, JSC::VM& vm, JSC::JSObject* object, JSC::JSGlobalObject* globalObject)
+{
+
+ JSC::JSArray* exportKeys = ownPropertyKeys(globalObject, object, PropertyNameMode::StringsAndSymbols, DontEnumPropertiesMode::Include, std::nullopt);
+ auto symbol = vm.symbolRegistry().symbolForKey("__BunTemporaryGlobal"_s);
+ JSC::Identifier ident = JSC::Identifier::fromUid(symbol);
+ WTF::StringBuilder sourceCodeBuilder = WTF::StringBuilder();
+ // TODO: handle symbol collision
+ sourceCodeBuilder.append("var $$TempSymbol = Symbol.for('__BunTemporaryGlobal'), $$NativeModule = globalThis[$$TempSymbol]; globalThis[$$TempSymbol] = null;\n if (!$$NativeModule) { throw new Error('Assertion failure: Native module not found'); }\n\n"_s);
+
+ for (unsigned i = 0; i < exportKeys->length(); i++) {
+ auto key = exportKeys->getIndexQuickly(i);
+ if (key.isSymbol()) {
+ continue;
+ }
+ auto named = key.toWTFString(globalObject);
+ sourceCodeBuilder.append(""_s);
+ // TODO: handle invalid identifiers
+ sourceCodeBuilder.append("export var "_s);
+ sourceCodeBuilder.append(named);
+ sourceCodeBuilder.append(" = $$NativeModule."_s);
+ sourceCodeBuilder.append(named);
+ sourceCodeBuilder.append(";\n"_s);
+ }
+ globalObject->putDirect(vm, ident, object, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum);
+ return JSC::makeSource(sourceCodeBuilder.toString(), JSC::SourceOrigin(), keyString, WTF::TextPosition(), JSC::SourceProviderSourceType::Module);
+}
+
+}
+
// #include <csignal>
#define NAPI_OBJECT_EXPECTED napi_object_expected
@@ -233,43 +266,20 @@ static void defineNapiProperty(Zig::GlobalObject* globalObject, JSC::JSObject* t
extern "C" void napi_module_register(napi_module* mod)
{
-
auto* globalObject = Bun__getDefaultGlobal();
JSC::VM& vm = globalObject->vm();
JSC::JSObject* object = JSC::constructEmptyObject(globalObject);
auto result = reinterpret_cast<JSC::EncodedJSValue>(
mod->nm_register_func(reinterpret_cast<napi_env>(globalObject), reinterpret_cast<napi_value>(JSC::JSValue::encode(JSC::JSValue(object)))));
- auto keyString = WTF::String::fromUTF8(mod->nm_modname);
- JSC::JSString* key = JSC::jsString(vm, keyString);
-
- JSC::JSArray* exportKeys = ownPropertyKeys(globalObject, object, PropertyNameMode::StringsAndSymbols, DontEnumPropertiesMode::Include, std::nullopt);
- auto symbol = vm.symbolRegistry().symbolForKey("__BunTemporaryGlobal"_s);
- JSC::Identifier ident = JSC::Identifier::fromUid(symbol);
- WTF::StringBuilder sourceCodeBuilder = WTF::StringBuilder();
- // TODO: handle symbol collision
- sourceCodeBuilder.append("var $$TempSymbol = Symbol.for('__BunTemporaryGlobal'), $$NativeModule = globalThis[$$TempSymbol]; globalThis[$$TempSymbol] = null;\n if (!$$NativeModule) { throw new Error('Assertion failure: Native module not found'); }\n\n"_s);
+ // std::cout << "loaded " << mod->nm_modname << std::endl;
+ auto keyStr = WTF::String::fromUTF8(mod->nm_modname);
+ auto key = JSC::jsString(vm, keyStr);
+ auto sourceCode = Napi::generateSourceCode(keyStr, vm, object, globalObject);
- for (unsigned i = 0; i < exportKeys->length(); i++) {
- auto key = exportKeys->getIndexQuickly(i);
- if (key.isSymbol()) {
- continue;
- }
- auto keyString = key.toWTFString(globalObject);
- sourceCodeBuilder.append(""_s);
- // TODO: handle invalid identifiers
- sourceCodeBuilder.append("export var "_s);
- sourceCodeBuilder.append(keyString);
- sourceCodeBuilder.append(" = $$NativeModule."_s);
- sourceCodeBuilder.append(keyString);
- sourceCodeBuilder.append(";\n"_s);
- }
- auto sourceCode = JSC::makeSource(sourceCodeBuilder.toString(), JSC::SourceOrigin(), keyString, WTF::TextPosition(), JSC::SourceProviderSourceType::Module);
- globalObject->putDirect(vm, ident, object, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum);
globalObject->moduleLoader()->provideFetch(globalObject, key, WTFMove(sourceCode));
auto promise = globalObject->moduleLoader()->loadAndEvaluateModule(globalObject, key, jsUndefined(), jsUndefined());
vm.drainMicrotasks();
- promise->result(vm);
}
extern "C" napi_status napi_wrap(napi_env env,
diff --git a/src/javascript/jsc/bindings/napi.h b/src/javascript/jsc/bindings/napi.h
index 5bc11e9a5..4a9743d6e 100644
--- a/src/javascript/jsc/bindings/napi.h
+++ b/src/javascript/jsc/bindings/napi.h
@@ -18,6 +18,11 @@ class GlobalObject;
namespace JSC {
class JSGlobalObject;
+class JSSourceCode;
+}
+
+namespace Napi {
+JSC::SourceCode generateSourceCode(WTF::String keyString, JSC::VM& vm, JSC::JSObject* object, JSC::JSGlobalObject* globalObject);
}
namespace Zig {