Go项目中使用Goja执行含其他JS文件引用的JS代码的方法
Goja执行含import的JS代码报错的解决办法
Goja默认不支持ES模块的import语法,也不会自动加载依赖的JS文件,直接用RunCode执行包含import的代码必然报错。以下是几种可行的解决方式:
方法1:手动合并依赖文件(适合简单场景)
如果依赖文件数量不多,可以手动读取所有依赖的JS内容,拼接成完整的JS字符串后再执行。示例代码:
package main import ( "os" "github.com/dop251/goja" "log" ) func main() { // 读取依赖文件 lodashBytes, err := os.ReadFile("./lodash.js") if err != nil { log.Fatalf("read lodash.js err: %v", err) } formulaBytes, err := os.ReadFile("./formula.js") if err != nil { log.Fatalf("read formula.js err: %v", err) } // 读取主文件 calculateBytes, err := os.ReadFile("./calculate.js") if err != nil { log.Fatalf("read calculate.js err: %v", err) } // 拼接代码:先注入依赖变量,再执行主逻辑 fullJS := ` // 注入lodash导出的方法 const { get, cloneDeep } = ` + string(lodashBytes) + `; // 注入formula导出的函数集合 const functions = ` + string(formulaBytes) + `; ` + string(calculateBytes) // 注意:需要修改calculate.js,删除原来的import语句,直接使用上面注入的变量 vm := goja.New() _, err = vm.RunString(fullJS) if err != nil { log.Fatalf("run code err: %+v", err) } }
方法2:实现Goja的ModuleLoader接口(推荐,支持自动加载)
Goja提供ModuleLoader接口,可自定义模块加载逻辑,让它自动解析import路径并读取对应文件。示例代码:
package main import ( "os" "path/filepath" "github.com/dop251/goja" "github.com/dop251/goja/parser" "log" ) type FileModuleLoader struct { baseDir string // JS文件所在的基础目录 } func (l *FileModuleLoader) LoadModule(vm *goja.Runtime, moduleName string) (*goja.Object, error) { // 拼接完整文件路径 filePath := filepath.Join(l.baseDir, moduleName) if !filepath.IsAbs(filePath) { filePath = filepath.Join(l.baseDir, filePath) } // 读取文件内容 code, err := os.ReadFile(filePath) if err != nil { return nil, err } // 编译模块代码 program, err := parser.ParseFile(nil, filePath, code, parser.Mode(0)) if err != nil { return nil, err } // 运行模块并返回导出对象 return vm.RunProgram(program) } func main() { vm := goja.New() // 设置自定义模块加载器 vm.SetModuleLoader(&FileModuleLoader{ baseDir: "./", // 你的JS文件所在目录 }) // 读取主文件 calculateBytes, err := os.ReadFile("./calculate.js") if err != nil { log.Fatalf("read calculate.js err: %v", err) } // 以模块模式解析并运行代码 program, err := parser.ParseFile(nil, "calculate.js", calculateBytes, parser.Mode(parser.Module)) if err != nil { log.Fatalf("parse code err: %v", err) } _, err = vm.RunProgram(program) if err != nil { log.Fatalf("run program err: %+v", err) } }
注意:此方式要求JS代码符合ES模块规范,且使用较新版本的Goja。
方法3:用打包工具合并成单文件
使用webpack、esbuild等工具,将所有依赖的JS文件打包成一个不含import的单文件,再用Goja执行。比如用esbuild的命令:
esbuild calculate.js --bundle --outfile=bundle.js
之后在Go代码中读取bundle.js内容,直接用RunCode执行即可。
内容的提问来源于stack exchange,提问作者wanghao
相关产品推荐
相关产品推荐

