LoginSignup
22
22

More than 5 years have passed since last update.

gojaを使ってGoでJavaScriptの実行を試してみた

Last updated at Posted at 2016-12-03

第2のドワンゴ Advent Calendar 2016の3日目の記事です。

来年使い倒そうと思ってるgojaについて紹介しようと思います。

goja とは

gojaはEcmaScript5.1をGoで実装しているライブラリです。
GoでJavaScriptを実行するメリットとしてプラグインにJavaScriptを使えたりサーバーサイドレンダリングに使えるのではないかなと思います。

インストール

Goを入れていればgo get github.com/dop251/gojaでインストールできます。

Hello World

gojaのHello Worldです。
スクリプトで最後に実行した行の戻り値がRunStringの戻り値として取得できます。

package main

import (
    "fmt"

    "github.com/dop251/goja"
)

func main() {
    vm := goja.New()
    v, err := vm.RunString(`2+2`)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%T, %#v\n", v, v) // Output: goja.valueInt, 4
}

Goとの値のやり取り

Setを使うことでスクリプト実行前に変数を定義することができます。

package main

import (
    "fmt"

    "github.com/dop251/goja"
)

func main() {
    vm := goja.New()
    x, y := 5, 7
    vm.Set("x", x)
    vm.Set("y", y)
    v, err := vm.RunString(`x+y`)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%T, %#v\n", v, v) // Output: goja.valueInt, 7
}

関数も同じ様にセットすることができます。

package main

import (
    "fmt"

    "github.com/dop251/goja"
)

func Sum(x, y int) int {
    return x + y
}

func main() {
    vm := goja.New()
    vm.Set("sum", Sum)
    v, err := vm.RunString(`sum(9, 4)`)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%T, %#v\n", v, v) // Output: goja.valueInt, 13
}

逆にJavaScriptで定義した変数をGoに渡すこともできます。
その場合はGetを使います。

package main

import (
    "fmt"

    "github.com/dop251/goja"
)

func main() {
    vm := goja.New()
    _, err := vm.RunString(`
        var result = 8 + 7
    `)
    if err != nil {
        panic(err)
    }

    v := vm.Get("result")

    fmt.Printf("%T, %#v\n", v, v) // Output: goja.valueInt, 15
}

変数だけではなく関数もJavaScriptで定義してGoで呼び出すこともできます。

package main

import (
    "fmt"

    "github.com/dop251/goja"
)

func main() {
    vm := goja.New()
    _, err := vm.RunString(`
        function sum(x, y) {
            return x + y
        }
    `)
    if err != nil {
        panic(err)
    }

    var v goja.Value
    if sum, ok := goja.AssertFunction(vm.Get("sum")); ok {
        v, err = sum(goja.Undefined(), vm.ToValue(4), vm.ToValue(10))
        if err != nil {
            panic(err)
        }
    }

    fmt.Printf("%T, %#v\n", v, v) // Output: goja.valueInt, 14
}

モジュールの読み込み

サイドプロジェクトとしてNode.jsのrequireとconsoleを実装しているパッケージがあります。

このパッケージのrequireを使うことでモジュール読み込みができます。
インストールはgo get github.com/dop251/goja_nodejs/...でできます。

sum.js
module.exports = function sum(x, y) {
    return x + y
}

モジュールをJavaScriptから呼び出すなら以下のように。

package main

import (
    "fmt"

    "github.com/dop251/goja"
    "github.com/dop251/goja_nodejs/require"
)

func main() {
    registry := new(require.Registry)

    vm := goja.New()
    registry.Enable(vm)
    v, err := vm.RunString(`
        var sum = require('./sum.js')
        sum(10, 5)
    `)

    if err != nil {
        panic(err)
    }

    fmt.Printf("%T, %#v\n", v, v) // Output: goja.valueInt, 15
}

モジュールをGoで呼び出すなら以下のようになります。

package main

import (
    "fmt"

    "github.com/dop251/goja"
    "github.com/dop251/goja_nodejs/require"
)

func main() {
    registry := new(require.Registry)

    vm := goja.New()
    rm := registry.Enable(vm)

    var v goja.Value
    if sum, err := rm.Require("sum.js"); err != nil {
        panic(err)
    } else {
        if sum, ok := goja.AssertFunction(sum); ok {
            v, err = sum(goja.Undefined(), vm.ToValue(6), vm.ToValue(7))
            if err != nil {
                panic(err)
            }
        }
    }

    fmt.Printf("%T, %#v\n", v, v) // Output: goja.valueInt, 13
}

まとめ

gojaを使えば手軽にJavaScriptを組み込むことができました。
ただsetTimeoutなどvue.jsでサーバーサイドレンダリングをしようと思うと
実装しなければならないものが多くてちょっと間に合わなかったので
来年こそはGoでSSRしたいと思います。

あと僕がGoを触るキッカケにもなったdwanGoが復活してくれたらいいなぁ(チラチラ

22
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
22