{"id":13430654,"url":"https://github.com/rogchap/v8go","last_synced_at":"2025-05-14T19:03:01.763Z","repository":{"id":37561548,"uuid":"204871154","full_name":"rogchap/v8go","owner":"rogchap","description":"Execute JavaScript from Go","archived":false,"fork":false,"pushed_at":"2024-08-02T10:56:01.000Z","size":527428,"stargazers_count":3317,"open_issues_count":99,"forks_count":226,"subscribers_count":34,"default_branch":"master","last_synced_at":"2025-04-03T01:47:57.794Z","etag":null,"topics":["go","godoc","golang","golang-package","hacktoberfest","javascript","v8","v8-javascript-engine"],"latest_commit_sha":null,"homepage":"https://rogchap.com/v8go","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rogchap.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"rogchap"}},"created_at":"2019-08-28T07:15:05.000Z","updated_at":"2025-04-01T20:45:54.000Z","dependencies_parsed_at":"2025-02-12T04:56:23.225Z","dependency_job_id":null,"html_url":"https://github.com/rogchap/v8go","commit_stats":{"total_commits":161,"total_committers":26,"mean_commits":"6.1923076923076925","dds":0.5465838509316769,"last_synced_commit":"cee5f84bb54338bdef150b3e43daace4669c5de2"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogchap%2Fv8go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogchap%2Fv8go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogchap%2Fv8go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogchap%2Fv8go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rogchap","download_url":"https://codeload.github.com/rogchap/v8go/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247669621,"owners_count":20976423,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","godoc","golang","golang-package","hacktoberfest","javascript","v8","v8-javascript-engine"],"created_at":"2024-07-31T02:00:56.257Z","updated_at":"2025-04-10T03:49:27.720Z","avatar_url":"https://github.com/rogchap.png","language":"Go","readme":"# Execute JavaScript from Go\n\n\u003ca href=\"https://github.com/rogchap/v8go/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/rogchap/v8go\" alt=\"Github release\"\u003e\u003c/a\u003e\n[![Go Report Card](https://goreportcard.com/badge/rogchap.com/v8go)](https://goreportcard.com/report/rogchap.com/v8go)\n[![Go Reference](https://pkg.go.dev/badge/rogchap.com/v8go.svg)](https://pkg.go.dev/rogchap.com/v8go)\n[![CI](https://github.com/rogchap/v8go/workflows/CI/badge.svg)](https://github.com/rogchap/v8go/actions?query=workflow%3ACI)\n![V8 Build](https://github.com/rogchap/v8go/workflows/V8%20Build/badge.svg)\n[![codecov](https://codecov.io/gh/rogchap/v8go/branch/master/graph/badge.svg?token=VHZwzGm3dV)](https://codecov.io/gh/rogchap/v8go)\n[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B22862%2Fgit%40github.com%3Arogchap%2Fv8go.git.svg?type=shield)](https://app.fossa.com/projects/custom%2B22862%2Fgit%40github.com%3Arogchap%2Fv8go.git?ref=badge_shield)\n[![#v8go Slack Channel](https://img.shields.io/badge/slack-%23v8go-4A154B?logo=slack)](https://gophers.slack.com/channels/v8go)\n\n\u003cimg src=\"gopher.jpg\" width=\"200px\" alt=\"V8 Gopher based on original artwork from the amazing Renee French\" /\u003e\n\n## Usage\n\n```go\nimport v8 \"rogchap.com/v8go\"\n```\n\n### Running a script\n\n```go\nctx := v8.NewContext() // creates a new V8 context with a new Isolate aka VM\nctx.RunScript(\"const add = (a, b) =\u003e a + b\", \"math.js\") // executes a script on the global context\nctx.RunScript(\"const result = add(3, 4)\", \"main.js\") // any functions previously added to the context can be called\nval, _ := ctx.RunScript(\"result\", \"value.js\") // return a value in JavaScript back to Go\nfmt.Printf(\"addition result: %s\", val)\n```\n\n### One VM, many contexts\n\n```go\niso := v8.NewIsolate() // creates a new JavaScript VM\nctx1 := v8.NewContext(iso) // new context within the VM\nctx1.RunScript(\"const multiply = (a, b) =\u003e a * b\", \"math.js\")\n\nctx2 := v8.NewContext(iso) // another context on the same VM\nif _, err := ctx2.RunScript(\"multiply(3, 4)\", \"main.js\"); err != nil {\n  // this will error as multiply is not defined in this context\n}\n```\n\n### JavaScript function with Go callback\n\n```go\niso := v8.NewIsolate() // create a new VM\n// a template that represents a JS function\nprintfn := v8.NewFunctionTemplate(iso, func(info *v8.FunctionCallbackInfo) *v8.Value {\n    fmt.Printf(\"%v\", info.Args()) // when the JS function is called this Go callback will execute\n    return nil // you can return a value back to the JS caller if required\n})\nglobal := v8.NewObjectTemplate(iso) // a template that represents a JS Object\nglobal.Set(\"print\", printfn) // sets the \"print\" property of the Object to our function\nctx := v8.NewContext(iso, global) // new Context with the global Object set to our object template\nctx.RunScript(\"print('foo')\", \"print.js\") // will execute the Go callback with a single argunent 'foo'\n```\n\n### Update a JavaScript object from Go\n\n```go\nctx := v8.NewContext() // new context with a default VM\nobj := ctx.Global() // get the global object from the context\nobj.Set(\"version\", \"v1.0.0\") // set the property \"version\" on the object\nval, _ := ctx.RunScript(\"version\", \"version.js\") // global object will have the property set within the JS VM\nfmt.Printf(\"version: %s\", val)\n\nif obj.Has(\"version\") { // check if a property exists on the object\n    obj.Delete(\"version\") // remove the property from the object\n}\n```\n\n### JavaScript errors\n\n```go\nval, err := ctx.RunScript(src, filename)\nif err != nil {\n  e := err.(*v8.JSError) // JavaScript errors will be returned as the JSError struct\n  fmt.Println(e.Message) // the message of the exception thrown\n  fmt.Println(e.Location) // the filename, line number and the column where the error occured\n  fmt.Println(e.StackTrace) // the full stack trace of the error, if available\n\n  fmt.Printf(\"javascript error: %v\", e) // will format the standard error message\n  fmt.Printf(\"javascript stack trace: %+v\", e) // will format the full error stack trace\n}\n```\n\n### Pre-compile context-independent scripts to speed-up execution times\n\nFor scripts that are large or are repeatedly run in different contexts,\nit is beneficial to compile the script once and used the cached data from that\ncompilation to avoid recompiling every time you want to run it.\n\n```go\nsource := \"const multiply = (a, b) =\u003e a * b\"\niso1 := v8.NewIsolate() // creates a new JavaScript VM\nctx1 := v8.NewContext(iso1) // new context within the VM\nscript1, _ := iso1.CompileUnboundScript(source, \"math.js\", v8.CompileOptions{}) // compile script to get cached data\nval, _ := script1.Run(ctx1)\n\ncachedData := script1.CreateCodeCache()\n\niso2 := v8.NewIsolate() // create a new JavaScript VM\nctx2 := v8.NewContext(iso2) // new context within the VM\n\nscript2, _ := iso2.CompileUnboundScript(source, \"math.js\", v8.CompileOptions{CachedData: cachedData}) // compile script in new isolate with cached data\nval, _ = script2.Run(ctx2)\n```\n\n### Terminate long running scripts\n\n```go\nvals := make(chan *v8.Value, 1)\nerrs := make(chan error, 1)\n\ngo func() {\n    val, err := ctx.RunScript(script, \"forever.js\") // exec a long running script\n    if err != nil {\n        errs \u003c- err\n        return\n    }\n    vals \u003c- val\n}()\n\nselect {\ncase val := \u003c- vals:\n    // success\ncase err := \u003c- errs:\n    // javascript error\ncase \u003c- time.After(200 * time.Milliseconds):\n    vm := ctx.Isolate() // get the Isolate from the context\n    vm.TerminateExecution() // terminate the execution\n    err := \u003c- errs // will get a termination error back from the running script\n}\n```\n\n### CPU Profiler\n\n```go\nfunc createProfile() {\n\tiso := v8.NewIsolate()\n\tctx := v8.NewContext(iso)\n\tcpuProfiler := v8.NewCPUProfiler(iso)\n\n\tcpuProfiler.StartProfiling(\"my-profile\")\n\n\tctx.RunScript(profileScript, \"script.js\") # this script is defined in cpuprofiler_test.go\n\tval, _ := ctx.Global().Get(\"start\")\n\tfn, _ := val.AsFunction()\n\tfn.Call(ctx.Global())\n\n\tcpuProfile := cpuProfiler.StopProfiling(\"my-profile\")\n\n\tprintTree(\"\", cpuProfile.GetTopDownRoot()) # helper function to print the profile\n}\n\nfunc printTree(nest string, node *v8.CPUProfileNode) {\n\tfmt.Printf(\"%s%s %s:%d:%d\\n\", nest, node.GetFunctionName(), node.GetScriptResourceName(), node.GetLineNumber(), node.GetColumnNumber())\n\tcount := node.GetChildrenCount()\n\tif count == 0 {\n\t\treturn\n\t}\n\tnest = fmt.Sprintf(\"%s  \", nest)\n\tfor i := 0; i \u003c count; i++ {\n\t\tprintTree(nest, node.GetChild(i))\n\t}\n}\n\n// Output\n// (root) :0:0\n//   (program) :0:0\n//   start script.js:23:15\n//     foo script.js:15:13\n//       delay script.js:12:15\n//         loop script.js:1:14\n//       bar script.js:13:13\n//         delay script.js:12:15\n//           loop script.js:1:14\n//       baz script.js:14:13\n//         delay script.js:12:15\n//           loop script.js:1:14\n//   (garbage collector) :0:0\n```\n\n## Documentation\n\nGo Reference \u0026 more examples: https://pkg.go.dev/rogchap.com/v8go\n\n### Support\n\nIf you would like to ask questions about this library or want to keep up-to-date with the latest changes and releases,\nplease join the [**#v8go**](https://gophers.slack.com/channels/v8go) channel on Gophers Slack. [Click here to join the Gophers Slack community!](https://invite.slack.golangbridge.org/)\n\n### Windows\n\nThere used to be Windows binary support. For further information see, [PR #234](https://github.com/rogchap/v8go/pull/234).\n\nThe v8go library would welcome contributions from anyone able to get an external windows\nbuild of the V8 library linking with v8go, using the version of V8 checked out in the\n`deps/v8` git submodule, and documentation of the process involved. This process will likely\ninvolve passing a linker flag when building v8go (e.g. using the `CGO_LDFLAGS` environment\nvariable.\n\n## V8 dependency\n\nV8 version: **9.0.257.18** (April 2021)\n\nIn order to make `v8go` usable as a standard Go package, prebuilt static libraries of V8\nare included for Linux and macOS. you *should not* require to build V8 yourself.\n\nDue to security concerns of binary blobs hiding malicious code, the V8 binary is built via CI *ONLY*.\n\n## Project Goals\n\nTo provide a high quality, idiomatic, Go binding to the [V8 C++ API](https://v8.github.io/api/head/index.html).\n\nThe API should match the original API as closely as possible, but with an API that Gophers (Go enthusiasts) expect. For\nexample: using multiple return values to return both result and error from a function, rather than throwing an\nexception.\n\nThis project also aims to keep up-to-date with the latest (stable) release of V8.\n\n## License\n\n[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B22862%2Fgit%40github.com%3Arogchap%2Fv8go.git.svg?type=large)](https://app.fossa.com/projects/custom%2B22862%2Fgit%40github.com%3Arogchap%2Fv8go.git?ref=badge_large)\n\n## Development\n\n### Recompile V8 with debug info and debug checks\n\n[Aside from data races, Go should be memory-safe](https://research.swtch.com/gorace) and v8go should preserve this property by adding the necessary checks to return an error or panic on these unsupported code paths. Release builds of v8go don't include debugging information for the V8 library since it significantly adds to the binary size, slows down compilation and shouldn't be needed by users of v8go. However, if a v8go bug causes a crash (e.g. during new feature development) then it can be helpful to build V8 with debugging information to get a C++ backtrace with line numbers. The following steps will not only do that, but also enable V8 debug checking, which can help with catching misuse of the V8 API.\n\n1) Make sure to clone the projects submodules (ie. the V8's `depot_tools` project): `git submodule update --init --recursive`\n1) Build the V8 binary for your OS: `deps/build.py --debug`. V8 is a large project, and building the binary can take up to 30 minutes.\n1) Build the executable to debug, using `go build` for commands or `go test -c` for tests. You may need to add the `-ldflags=-compressdwarf=false` option to disable debug information compression so this information can be read by the debugger (e.g. lldb that comes with Xcode v12.5.1, the latest Xcode released at the time of writing)\n1) Run the executable with a debugger (e.g. `lldb -- ./v8go.test -test.run TestThatIsCrashing`, `run` to start execution then use `bt` to print a bracktrace after it breaks on a crash), since backtraces printed by Go or V8 don't currently include line number information.\n\n### Upgrading the V8 binaries\n\nWe have the [upgradev8](https://github.com/rogchap/v8go/.github/workflow/v8upgrade.yml) workflow.\nThe workflow is triggered every day or manually.\n\nIf the current [v8_version](https://github.com/rogchap/v8go/deps/v8_version) is different from the latest stable version, the workflow takes care of fetching the latest stable v8 files and copying them into `deps/include`. The last step of the workflow opens a new PR with the branch name `v8_upgrade/\u003cv8-version\u003e` with all the changes.\n\nThe next steps are:\n\n1) The build is not yet triggered automatically. To trigger it manually, go to the [V8\nBuild](https://github.com/rogchap/v8go/actions?query=workflow%3A%22V8+Build%22) Github Action, Select \"Run workflow\",\nand select your pushed branch eg. `v8_upgrade/\u003cv8-version\u003e`.\n1) Once built, this should open 3 PRs against your branch to add the `libv8.a` for Linux (for x86_64) and macOS for x86_64 and arm64; merge\nthese PRs into your branch. You are now ready to raise the PR against `master` with the latest version of V8.\n\n### Flushing after C/C++ standard library printing for debugging\n\nWhen using the C/C++ standard library functions for printing (e.g. `printf`), then the output will be buffered by default.\nThis can cause some confusion, especially because the test binary (created through `go test`) does not flush the buffer\nat exit (at the time of writing). When standard output is the terminal, then it will use line buffering and flush when\na new line is printed, otherwise (e.g. if the output is redirected to a pipe or file) it will be fully buffered and not even\nflush at the end of a line. When the test binary is executed through `go test .` (e.g. instead of\nseparately compiled with `go test -c` and run with `./v8go.test`) Go may redirect standard output internally, resulting in\nstandard output being fully buffered.\n\nA simple way to avoid this problem is to flush the standard output stream after printing with the `fflush(stdout);` statement.\nNot relying on the flushing at exit can also help ensure the output is printed before a crash.\n\n### Local leak checking\n\nLeak checking is automatically done in CI, but it can be useful to do locally to debug leaks.\n\nLeak checking is done using the [Leak Sanitizer](https://clang.llvm.org/docs/LeakSanitizer.html) which\nis a part of LLVM. As such, compiling with clang as the C/C++ compiler seems to produce more complete\nbacktraces (unfortunately still only of the system stack at the time of writing).\n\nFor instance, on a Debian-based Linux system, you can use `sudo apt-get install clang-12` to install a\nrecent version of clang.  Then CC and CXX environment variables are needed to use that compiler. With\nthat compiler, the tests can be run as follows\n\n```\nCC=clang-12 CXX=clang++-12 go test -c --tags leakcheck \u0026\u0026 ./v8go.test\n```\n\nThe separate compile and link commands are currently needed to get line numbers in the backtrace.\n\nOn macOS, leak checking isn't available with the version of clang that comes with Xcode, so a separate\ncompiler installation is needed.  For example, with homebrew, `brew install llvm` will install a version\nof clang with support for this. The ASAN_OPTIONS environment variable will also be needed to run the code\nwith leak checking enabled, since it isn't enabled by default on macOS. E.g. with the homebrew\ninstallation of llvm, the tests can be run with\n\n```\nCXX=/usr/local/opt/llvm/bin/clang++ CC=/usr/local/opt/llvm/bin/clang go test -c --tags leakcheck -ldflags=-compressdwarf=false\nASAN_OPTIONS=detect_leaks=1 ./v8go.test\n```\n\nThe `-ldflags=-compressdwarf=false` is currently (with clang 13) needed to get line numbers in the backtrace.\n\n### Formatting\n\nGo has `go fmt`, C has `clang-format`. Any changes to the `v8go.h|cc` should be formated with `clang-format` with the\n\"Chromium\" Coding style. This can be done easily by running the `go generate` command.\n\n`brew install clang-format` to install on macOS.\n\n---\n\nV8 Gopher image based on original artwork from the amazing [Renee French](http://reneefrench.blogspot.com).\n","funding_links":["https://github.com/sponsors/rogchap"],"categories":["Go","开源类库","Open source library","Repositories"],"sub_categories":["解释器","Interpreter"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogchap%2Fv8go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frogchap%2Fv8go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogchap%2Fv8go/lists"}