diff --git a/internal/jsbuiltin/src/00_module.js b/internal/jsbuiltin/src/00_module.js index 5d49ae9..a542bf0 100644 --- a/internal/jsbuiltin/src/00_module.js +++ b/internal/jsbuiltin/src/00_module.js @@ -193,4 +193,25 @@ return module; require.cache = {}; jssh.require = require; jssh.requiremodule = requiremodule; + + const importModuleCallbacks = []; + + const registerImportModuleCallback = (callback) => { + if (typeof callback !== "function") { + throw new TypeError("callback must be a function"); + } + importModuleCallbacks.push(callback); + }; + + const callImportModuleCallbacks = (name, dir) => { + for (const callback of importModuleCallbacks) { + const result = callback(name, dir); + if (result) { + return result; + } + } + }; + + jssh.registerImportModuleCallback = registerImportModuleCallback; + jssh.callImportModuleCallbacks = callImportModuleCallbacks; } diff --git a/internal/jsexecutor/jsexecutor.go b/internal/jsexecutor/jsexecutor.go index fe4efd7..18b79b3 100644 --- a/internal/jsexecutor/jsexecutor.go +++ b/internal/jsexecutor/jsexecutor.go @@ -15,7 +15,9 @@ type JSFunction = func(ctx *JSContext, this JSValue, args []JSValue) JSValue // // NewJSRuntime 创建新的JSRuntime实例 func NewJSRuntime() JSRuntime { - return quickjs.NewRuntime() + runtime := quickjs.NewRuntime() + runtime.SetModuleLoader(moduleLoader) + return runtime } // IsGoFunction 判断是否为Go的函数类型 @@ -238,3 +240,10 @@ func anySliceToJSValue(ctx *quickjs.Context, v reflect.Value, vt reflect.Type) q } return arr } + +// RegisterModuleLoader 注册模块加载器 +func RegisterModuleLoader(loader func(ctx *JSContext, moduleName string) (string, error)) { + moduleLoader = loader +} + +var moduleLoader func(ctx *JSContext, moduleName string) (string, error) diff --git a/quickjs/quickjs.go b/quickjs/quickjs.go index deaebb6..157f47a 100644 --- a/quickjs/quickjs.go +++ b/quickjs/quickjs.go @@ -21,7 +21,8 @@ import ( import "C" type Runtime struct { - ref *C.JSRuntime + ref *C.JSRuntime + moduleLoader func(ctx *Context, moduleName string) (string, error) } func NewRuntime() Runtime { @@ -42,7 +43,26 @@ func (r Runtime) NewContext() *Context { C.JS_AddIntrinsicOperators(ref) C.JS_EnableBignumExt(ref, C.int(1)) - return &Context{ref: ref} + ctx := &Context{ref: ref} + + if r.moduleLoader != nil { + // typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx, const char *module_name, void *opaque); + moduleLoaderFunc := func(_ *C.JSContext, cModuleName *C.char, opaque unsafe.Pointer) *C.JSModuleDef { + moduleName := C.GoString(cModuleName) + source, err := r.moduleLoader(ctx, moduleName) + if err != nil { + panic(err) + } + return C.JS_Eval(ctx.ref, C.CString(source), C.size_t(len(source)), cModuleName, C.JS_EVAL_TYPE_MODULE) + } + C.JS_SetModuleLoaderFunc(r.ref, nil, *C.JSModuleLoaderFunc(moduleLoaderFunc), unsafe.Pointer(ctx)) + } + + return ctx +} + +func (r *Runtime) SetModuleLoader(loader func(ctx *Context, moduleName string) (string, error)) { + r.moduleLoader = loader } func (r Runtime) ExecutePendingJob() (Context, error) {