Vue.jsのサーバーサイドレンダリングをGAE/Goでやる #vuejs #golang

  • 41
    いいね
  • 2
    コメント

メリークリスマス!(昨日) これはVue.jsアドベントカレンダーの記事です。
代打です。

僕は初日にサーバーサイドレンダリングについて書きましたが 今回もサーバーサイドレンダリングです。

今回の内容は本当は初日に書きたかったのですがずっとうまくいかずに悩んでいたけどつい昨日できたGoサーバでのSSR(サーバーサイドレンダリング)です。

GoでSSRをするメリットとしてまず一つにポータビリティです。
Node.jsもポータビリティはありますが、Goであればアセットもワンバイナリにまとめることができるのでバイナリを配置するだけでWebUIがあるツールも作ることもできるかもしれません。

そして、僕にとって1番のメリットであるApp Engine(GAE)でSSRができるようになります!

SSRについては初日の記事を見てください!

サンプルの実行

https://github.com/k2wanko/appengine-ssr-example

サンプルのコードはGitHubにあげてあります。
これをベースにGoでSSRを実現するためにやったことを書いていきます。

動かし方は以下の手順です。

$ git clone https://github.com/k2wanko/appengine-ssr-example.git
$ npm install # or yarn
$ go get -v ./...
$ npm run dev

npm run devを実行するとで開発サーバが立ち上がります。http://localhost:8080にアクセスすると確認ができます。

webpack.config.js

まずはwebpackの設定です。
基本は初日の記事のやつと同じですがGoで動かすために少し変えています。

まずGoでJSを実行するランタイムはgojaを使いました。
gojaはottoのようにGo実装のJavaScriptパーサです。
ottoよりもGoとのやり取りがやりやすいので使いました。
gojaについてはドワンゴのアドベントカレンダーに書いたのでそっちを見てください。
gojaを使ってGoでJavaScriptの実行を試してみた - Qiita

まずコードをgojaで動かせるようにする必要があります。
gojaはES5.1を実装しているのでそこの変換はbabelでやります。
次にNode.jsを前提にしているコードのためにwebpackのNodeSourcePluginを利用します。
webpackではtarget: 'node'にするとNodeSourcePluginが使われないのでwebpack.config.jsに追加します。
でもそれだけではまだだめでNodeTargetPluginの効果を無効にする必要があります。
NodeTargetPluginはnativeモジュールを外部から取ってくるようにするためのプラグインです。
process.bindingを置き換えて対処しました。
もっとスマートなやり方があればいいのですが... そのためにはPRが必要かもしれません。

以下がserver用のコードの設定です。

var NodeSourcePlugin = require('webpack/lib/node/NodeSourcePlugin')
webpackModule.rules[1].exclude = null

var binding = process.binding
process.binding = function (name) {
  if (name === 'natives') return {}
  return binding.apply(process, arguments)
}
var server = Object.assign({}, client, {
  entry: './src/server.js',
  target: 'node',
  devtool: false,
  output: Object.assign({}, client.output, {
    filename: 'server-build.js',
    libraryTarget: 'commonjs2'
  }),
  plugins: [
    new NodeSourcePlugin(
      {
        console: true,
        process: true,
        global: true,
        Buffer: true,
        setImmediate: true,
        module: 'empty',
        __filename: 'mock',
        __dirname: 'mock'
      }),
  ],
  module: webpackModule,
})

setTimeout

ES5の仕様にはsetTimeoutの仕様が含まれていないのでgoja_nodejsのeventloopを使いました。

https://github.com/dop251/goja_nodejs/tree/master/eventloop

今後の予定

  • VuexとVue Routerを使う
  • 実践的なアプリケーションを作ってみる

まとめ

というわけで、GAE/GoでSSRができました!

この投稿は Vue.js Advent Calendar 201620日目の記事です。