日頃の行い

個人的な日頃の行いをつらつら書いてます\\\\ ٩( 'ω' )و ////

Vue.jsに入門しようと思ってScala.jsでVue.jsのサンプル書いてみた。

会社のインターンでVue.jsを利用するんですが、去年も触ったけど、やっぱりちゃんとサンプルを動かしてみないといけないなと思って写経してみました。
サンプルはこちらのページを利用しました。
日本語ページ去年はなかった気がしますが、今は日本語で読めてとても楽です。

jp.vuejs.org

ところで、最近altJSというのが流行ってますね。
TypeScriptやCoffeeScript色々ありますね。
せっかくなので今回はScala.jsを使いました。

Scala.jsとは -> http://www.scala-js.org/

やっぱScalaは型があっていいですよね。
コンパイル時にコーヒー飲めるしすばらしい。

概要

この後の流れ
1. Vue.jsをScala.jsで使うための準備
2. マークダウンエディタサンプル写経
3. マークダウンエディタサンプルを動かしてみる

利用したライブラリたち

  • Scala 2.11.5
  • Vue.js 0.12.9
  • Scalajs 0.6.4

1. Vue.jsをScala.jsで使うための準備

Scala.jsにjQueryのクラスなどは用意されていますが、それ以外は自前でインターフェイスを定義してあげる必要があります。
どうやればいいんだろうと思ってググっていたらこちらにたどり着きました。takezoe.hatenablog.com

Aceライブラリのインターフェイスの定義

scalajs-ace/Ace.scala at master · scalawarrior/scalajs-ace · GitHub

自前とかむりぽ
そこでscala-js-ts-importerです。
これはTypeScriptの型定義を元にScalaのコードに変換してくれるライブラリです。

github.com

Vue.jsの型定義ファイルはこちらにまとまっていたものを利用させていただきました。

github.com

$cd /path/to/scala-js-ts-importer
$cp /path/to/DefinitelyTyped/path/to/vue.d.ts ./
$sbt 'run vue.d.ts Vue.scala'

これでVue.scalaができ・・・ない!

$sbt 'run vue.d.ts Vue.scala'
[info] Loading project definition from /Users/a-tanaka/.ghq/github.com/sjrd/scala-js-ts-importer/project
[info] Set current project to TypeScript importer for Scala.js (in build file:/Users/a-tanaka/.ghq/github.com/sjrd/scala-js-ts-importer/)
[info] Running org.scalajs.tools.tsimporter.Main vue.d.ts Vue.scala
Parse error at 166.1
``interface'' expected but 'import' found
import Vue = vuejs.Vue;

^
java.lang.RuntimeException: Nonzero exit code: 2
	at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last compile:run for the full output.
[error] (compile:run) Nonzero exit code: 2
[error] Total time: 3 s, completed 2015/08/07 20:50:31

# importがダメなようです
# とりあえず消して動かすことにしました
# これによってビルドされるVue.scalaのJSNameアノテーションも少し修正しないといけなくなります。

$vim vue.d.ts
# importが2つあったので削除
$sbt 'run vue.d.ts Vue.scala'
[info] Loading project definition from /Users/a-tanaka/.ghq/github.com/sjrd/scala-js-ts-importer/project
[info] Set current project to TypeScript importer for Scala.js (in build file:/Users/a-tanaka/.ghq/github.com/sjrd/scala-js-ts-importer/)
[info] Running org.scalajs.tools.tsimporter.Main vue.d.ts Vue.scala
[success] Total time: 1 s, completed 2015/08/07 20:51:06

これでできたVue.scalaを利用すればVue.jsをScalaでかけます!!!!111

2. マークダウンエディタのサンプル写経

写経してみた結果が下記の通りです。

tips
  • jsのobjectを定義するには scala.scalajs.js.Dynamic.literalを利用すると良いみたいです。
  • また、ここの markedは他ライブラリのmarked.jsのグローバル変数になるのですが、marked.jsのインターフェイス定義をまたscala-js-ts-importerで行うのはめんどうなのでここではそのままグローバル変数を入れるようにしています。
  • jsのグローバル変数を利用するためにはscala.scalajs.Dynamic.globalを利用すると良いみたいです。
package vu

import scala.scalajs.js.Dynamic.{global => g}
import scala.scalajs.js
import scala.scalajs.js.JSApp
import scala.scalajs.js.annotation.JSExport
import scala.scalajs.js.Any._
import scala.scalajs.vuejs.Vue

object VueSample extends JSApp {

  @JSExport
  def main():Unit = {
    val option = js.Dynamic.literal(
      "el" -> "#editor",
      "data" -> js.Dynamic.literal(
        "input" -> "# hello"
      ),
      "filters" -> js.Dynamic.literal(
        "marked" -> g.marked
      )
    )

    val app = new Vue(option)
  }
}

htmlはサンプルと全く同じです

<html>
    <head>
        <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.9/vue.js"></script>
        <script type="text/javascript" src="../target/scala-2.11/scala-js-tutorial-fastopt.js"></script>
        <script type="text/javascript" src="./app.js" async></script>
        <style>
            html, body, #editor {
                margin: 0;
                height: 100%;
                font-family: 'Helvetica Neue', Arial, sans-serif;
                color: #333;
            }

            textarea, #editor div {
                display: inline-block;
                width: 49%;
                height: 100%;
                vertical-align: top;
                -webkit-box-sizing: border-box;
                -moz-box-sizing: border-box;
                box-sizing: border-box;
                padding: 0 20px;
            }

            textarea {
                border: none;
                border-right: 1px solid #ccc;
                resize: none;
                outline: none;
                background-color: #f6f6f6;
                font-size: 14px;
                font-family: 'Monaco', courier, monospace;
                padding: 20px;
            }

            code {
                color: #f66;
            }
        </style>
    </head>
    <body>
        <div id="editor">
            <textarea v-model="input" debounce="300"></textarea>
            <div v-html="input | marked"></div>
        </div>
    </body>
</html>

app.js

(function() {
    vu.VueSample().main()
})();

ここまで書いたコードを置いたレポジトリがこちらです。

github.com

動かしたい場合は

$git clone git@github.com:ara-ta3/scalajs-vuejs-getting-started.git
$cd scalajs-vuejs-getting-started
$sbt fastOptJS
# ↓はMacのみです。単にresources/index.htmlをブラウザで開けば問題無いです。
$open resources/index.html

また、Vue.scalaはJSNameアノテーションの部分を少し変えています。

// @JSName("vuejs.Vue")
@JSName("Vue")
class Vue protected () extends js.Object {
...

こうしないとブラウザ(chrome)で怒られてしまったので、変更しました。
さて、動かして見た結果がこちらです。(jsで書いた時と何も変わらないですw)

f:id:arata3da4:20150807214153p:plain

これでVue.jsもScalaでかけます!
JavascriptもサーバサイドもScalaで・・・!
あとはCSSだけですね!

github.com