Skip to content
vic

mcuadros/go-candyjs

fully transparent bridge between Go and the JavaScript

mcuadros/go-candyjs.json
{
"createdAt": "2015-06-03T16:36:48Z",
"defaultBranch": "master",
"description": "fully transparent bridge between Go and the JavaScript",
"fullName": "mcuadros/go-candyjs",
"homepage": "",
"language": "Go",
"name": "go-candyjs",
"pushedAt": "2017-10-05T05:18:55Z",
"stargazersCount": 451,
"topics": [],
"updatedAt": "2025-08-03T11:23:05Z",
"url": "https://github.com/mcuadros/go-candyjs"
}

CandyJS is an intent of create a fully transparent bridge between Go and the JavaScript engine duktape. Basicly is a syntax-sugar library built it on top of go-duktape using reflection techniques.

build extensible applications that allow to the user execute arbitrary code (let’s say plugins) without the requirement of compile it.

asciicast

Embeddable Ecmascript E5/E5.1 compliant engine (duktape).

ctx := candyjs.NewContext()
ctx.EvalString(`
function factorial(n) {
if (n === 0) return 1;
return n * factorial(n - 1);
}
print(factorial(10));
`) //3628800

Call Go functions from JavaScript and vice versa.

ctx := candyjs.NewContext()
ctx.PushGlobalGoFunction("golangMultiply", func(a, b int) int {
return a * b
})
ctx.EvalString(`print(golangMultiply(5, 10));`) //50

Transparent interface between Go structs and JavaScript.

type MyStruct struct {
Number int
}
func (m *MyStruct) Multiply(x int) int {
return m.Number * x
}
...
ctx := candyjs.NewContext()
ctx.PushGlobalStruct("golangStruct", &MyStruct{10})
ctx.EvalString(`print(golangStruct.number);`) //10
ctx.EvalString(`print(golangStruct.multiply(5));`) //50

Import of Go packages into the JavaScript context.

//go:generate candyjs import fmt
...
ctx := candyjs.NewContext()
ctx.EvalString(`
var fmt = CandyJS.require('fmt');
fmt.printf('candyjs is %s', 'awesome')
`) // 'candyjs is awesome'

The recommended way to install go-candyjs is:

go get -u github.com/mcuadros/go-candyjs/...

CandyJS includes a binary tool used by go generate, please be sure that $GOPATH/bin is on your $PATH

In this example a gin server is executed and a small JSON is server. In CandyJS you can import Go packages directly if they are defined previously on the Go code.

Interpreter code (main.go)

...
//go:generate candyjs import time
//go:generate candyjs import github.com/gin-gonic/gin
func main() {
ctx := candyjs.NewContext()
ctx.PevalFile("example.js")
}

Program code (example.js)

var time = CandyJS.require('time');
var gin = CandyJS.require('github.com/gin-gonic/gin');
var engine = gin.default();
engine.get("/back", CandyJS.proxy(function(ctx) {
var future = time.date(2015, 10, 21, 4, 29 ,0, 0, time.UTC);
var now = time.now();
ctx.json(200, {
future: future.string(),
now: now.string(),
nsecs: future.sub(now)
});
}));
engine.run(':8080');

Due to an incompatibility with Duktape’s error handling system and Go, you can’t throw errors from Go. All errors generated from Go functions are generic ones error error (rc -100)

MIT, see [LICENSE]!(LICENSE)