日頃の行い

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

Laravel製マイクロフレームワークLumenを使おうとして困ったこととその解決策

この記事はLaravelアドベントカレンダーの13日目として書かれています。

www.adventar.org

最近Laravel製のマイクロフレームワークLumenを使って個人的な開発をしています。
その時にこれしたいんだけど、どうやるの?みたいなことを思ったタイミングが何度か合ったので、それをまとめようと思います。

目次

下記のことについて触れようと思います。
ほんとはLumenからLaravelに移行したい時にどうすればよいのかとかも検証したかったのですが、Laravel力が足りなかったので割愛しました。

  • lumenコマンドを使わずにプロジェクトを作成する方法
  • debugをオンにする方法
  • Laravel用のプラグイン利用時にconfigを置く場所について
  • テンプレートエンジンにtwigを使う方法
  • 自前のクラスを置く場所について

lumenコマンドを使わずにプロジェクトを作成する方法

lumenコマンドを利用せず特定のディレクトリにLumenプロジェクトを作成する方法です。
composer create-projectコマンドを利用すれば簡単でした。
Lumen - PHP Micro-Framework By Laravel

$php -r "readfile('https://getcomposer.org/installer');" | php
#!/usr/bin/env php
All settings correct for using Composer
Downloading...

Composer successfully installed to: /path/to/composer.phar
Use it: php composer.phar

$php composer.phar create-project laravel/lumen my_project_dir
Installing laravel/lumen (v5.1.4)
  - Installing laravel/lumen (v5.1.4)
    Loading from cache

Created project in my_project_dir
Loading composer repositories with package information
Installing dependencies (including require-dev)
...
$tree -L 2
.
├── composer.phar
└── my_project_dir
    ├── app
    ├── artisan
    ├── bootstrap
    ├── composer.json
    ├── database
    ├── phpunit.xml
    ├── public
    ├── readme.md
    ├── resources
    ├── server.php
    ├── storage
    ├── tests
    └── vendor

9 directories, 6 files

debugをオンにする方法

Lumenは初期状態だとデバッグがオフになっています。
なので例えば下記のようにしょうもないミスをしていたりするときにLumenを実行したとしても500ページが出るだけで、何が起こっているのか全くわかりません。

<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It is a breeze. Simply tell Lumen the URIs it should respond to
| and give it the Closure to call when that URI is requested.
|
*/

$app->get('/', function () use ($app) {
    $a = $app->welcome();
    return $b;
});

アクセスしたとしてもこのように500エラーのページが表示されるのみ。

f:id:arata3da4:20151213220445p:plain

ビルトインサーバ側も特に何も言ってくれません。

$php artisan serve
Lumen development server started on http://localhost:8000/

これを切り替えるために .envファイルを利用します。
参考 http://lumen.laravel.com/docs/errors

$cd /path/to/my_project_dir
$ls -a
.             .gitignore    bootstrap     database      readme.md     storage
..            app           composer.json phpunit.xml   resources     tests
.env.example  artisan       composer.lock public        server.php    vendor
# この.env.exampleをコピーして利用します。
$cp .env.example .env

よしこれでデバッグがオンになるぜ。って思うじゃないですか。
実はならないです。
理由はこのenvファイルを読みに行くという設定がbootstrap/app.phpコメントアウトされているからです。

$head -n 10 /path/to/my_project_dir/bootstrap/app.php
<?php

require_once __DIR__.'/../vendor/autoload.php';

// Dotenv::load(__DIR__.'/../');

/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------

このDotenv::load(__DIR__.'/../');のコメントアウトを外すと.envファイルを読みに行くようになり、APP_DEBUGがtrueとなっていればデバッグがオンになります。
こんな感じ

f:id:arata3da4:20151213221542p:plain

Laravel用のプラグイン利用時にconfigを置く場所について

Laravelのプラグイン等をインストールし、設定を上書きして変えたい時、configディレクトリにその設定を書けば良いと思うのですが、初期状態のLumenにはconfigディレクトリがありません。
Document見るとなにか書いてあります。
http://lumen.laravel.com/docs/installationConfiguration Filesあたり
なるほど、勝手に足せばよいみたいです。
次の「テンプレートエンジンにtwigを使う方法」でtwigbridgeというプラグインを使うのですが、その場合だとこんな感じになりました。

$cd /path/to/my_project_dir
$mkdir config
$ls
Makefile      bootstrap     composer.phar phpunit.xml   resources     tests
app           composer.json config        public        server.php    vendor
artisan       composer.lock database      readme.md     storage
$cp ./vendor/rcrowe/twigbridge/config/twigbridge.php ./config/
$ls ./config
twigbridge.php

これでプラグインの設定を上書きすることが出来ます。

テンプレートエンジンにtwigを使う方法

よーく考えてみたら、昔記事書いてました。
わりとまじめに書いたのでこちらを参考に・・・

arata.hatenadiary.com

自前のクラスを置く場所について

自前のクラスをどこに置けば良いのかふと悩んだのでその時のメモです。
autoloaderの設定がどうなっているかがわかれば良いので、composer.jsonを見れば良さそうですね。

$cat composer.json
{
    "name": "laravel/lumen",
    "description": "The Laravel Lumen Framework.",
    "keywords": ["framework", "laravel", "lumen"],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": ">=5.5.9",
        "laravel/lumen-framework": "5.1.*",
        "vlucas/phpdotenv": "~1.0"
    },
    "require-dev": {
        "phpunit/phpunit": "~4.0",
        "fzaninotto/faker": "~1.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        },
        "classmap": [
            "database/"
        ]
    },
    "autoload-dev": {
        "classmap": [
            "tests/"
        ]
    },
    "config": {
        "preferred-install": "dist"
    }
}

autoloadの項目を見る限りappディレクトリ以下を見るようになっているので、そこに置けば良さそうです。
app/Hoge/Foo.phpというファイルを置いてみました。

<?php

namespace App\Hoge;

class Foo {
    public static function hello() {
        return "hello namespace";
    }
}

app/Http/routes.phpを編集して動くか確認してみます。

$cat app/Http/routes.php
<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It is a breeze. Simply tell Lumen the URIs it should respond to
| and give it the Closure to call when that URI is requested.
|
*/

$app->get('/', function () use ($app) {
    $m = \App\Hoge\Foo::hello();
    var_dump($m);
});
$php artisan serve &
[1] 43243
Lumen development server started on http://localhost:8000/

$curl localhost:8000
string(15) "hello namespace"

呼べている様子でした。

まとめ

Lumen使ってみて、なんか困ったことをまとめてみました。
.envファイルデフォルトで読みにいかないんかいとかconfigディレクトリ作らないといけないんかいとか思ったりしましたが、そこまでやりたいならLaravel使えよってメッセージなんですかね。
Laravelの方はあまり触ってないので、そちらの方も触っていきたいなーと思った日でした。

ScalaからBigQueryのAPI叩いてみた時の備忘録

ScalaでBigQuery叩いてた時の備忘録です。
使ったレポジトリはここ

github.com


この後の話の流れ

  1. 準備 (認証)
  2. クエリを叩く
  3. ハマったこと

1. 準備

BigQueryを外から叩くためにとりあえず認証が必要です。
今回はサービスアカウントを利用して叩いてみました。
認証周りはGoogleのコンソールから準備します。
プロジェクトは事前に作ってる前提で、ここではMySampleBQProjectというプロジェクトを作って遊んでます
下記ページの右上にConsoleとあると思うので、そこから入れます。
BigQuery | Google Cloud Platform — Google Cloud Platform

入ってメニューを開くとAPI Managerという欄があるので、そこで認証用の設定が出来ます。
方法は下のほうの画像を参考に。


f:id:arata3da4:20151109222519p:plain

f:id:arata3da4:20151109222524p:plain

「作成」ボタンを押すと、 {プロジェクト名}-{証明書フィンガープリント}.p12 がダウンロードされます。
その後「認証情報」のページに戻るとサービスアカウントとして {なんかの番号}-{長い文字列}@developer.gserviceaccount.comができていると思います。
このダウンロードしたp12ファイルとサービスアカウントを利用します。

2. クエリを叩く

SELECT *  FROM [publicdata:samples.wikipedia] limit 10

というふっつうのクエリをScalaから叩いてみました。
利用させていただいたライブラリはこちら

github.com

  • build.sbt
libraryDependencies += "com.github.seratch" %% "bigquery4s" % "0.3"
package vu

import bigquery4s.BigQuery

object BigQueryDemo {

  val bq = BigQuery.fromServiceAccount(
    "{なんかの番号}-{長い文字列}@developer.gserviceaccount.com", // サービスアカウント
    "/path/to/{プロジェクト名}-{証明書フィンガープリント}.p12" // 鍵ファイルへのPATH 
  )

  val projectId = "mysamplebqproject" // プロジェクト名

  def main(args: Array[String]) {
    val sql = "SELECT *  FROM [publicdata:samples.wikipedia] limit 10"
    val jobId = bq.startQuery(projectId, sql)
    val result = bq.await(jobId)
    bq.getRows(result).foreach(println)
  }
}

これを叩くとこんな感じになります。

> run
[warn] Multiple main classes detected.  Run 'show discoveredMainClasses' to see the list

Multiple main classes detected, select one to run:

 [1] vu.BigQueryDemo
 [2] vu.BigQueryDemo2

Enter number: 1

[info] Running vu.BigQueryDemo
11 09, 2015 10:42:12 午後 com.google.api.client.googleapis.services.AbstractGoogleClient <init>
警告: Application name is not set. Call Builder#setApplicationName.
WrappedTableRow({"f":[{"v":"User talk:Sonicrazy"},{"v":"1303993"},{"v":""},{"v":"3"},{"v":null},{"v":"59222308"},{"v":null},{"v":"1063944"},{"v":"DJ BatWave"},{"v":"1150604342"},{"v":null},{"v":null},{"v":null},{"v":"hey"},{"v":"4442"}]})
WrappedTableRow({"f":[{"v":"Sit Down, Shut Up (U.S. TV series)"},{"v":"17446266"},{"v":""},{"v":"0"},{"v":null},{"v":"278080927"},{"v":null},{"v":"1862829"},{"v":"Magioladitis"},{"v":"1237376427"},{"v":"true"},{"v":null},{"v":null},{"v":"new television template"},{"v":"7042"}]})
WrappedTableRow({"f":[{"v":"Talk:Homestead, Florida"},{"v":"2387164"},{"v":""},{"v":"1"},{"v":null},{"v":"20382857"},{"v":null},{"v":"28438"},{"v":"Altenmann"},{"v":"1123295494"},{"v":null},{"v":null},{"v":null},{"v":"/* Page protection */"},{"v":"10354"}]})
WrappedTableRow({"f":[{"v":"Big Brother 9 (U.S.)"},{"v":"14549699"},{"v":""},{"v":"0"},{"v":null},{"v":"193263045"},{"v":"71.225.199.168"},{"v":null},{"v":null},{"v":"1203685970"},{"v":null},{"v":null},{"v":null},{"v":"[[WP:AES|←]]Replaced page with 'Yauman CAhan'"},{"v":"12"}]})
WrappedTableRow({"f":[{"v":"Talk:Pashtun people"},{"v":"273006"},{"v":""},{"v":"1"},{"v":null},{"v":"9212968"},{"v":null},{"v":"28107"},{"v":"Jmabel"},{"v":"1105225046"},{"v":null},{"v":null},{"v":null},{"v":"/* jambel please give reference to your text */ Lost Tribes of Israel"},{"v":"57553"}]})
WrappedTableRow({"f":[{"v":"Sprint Nextel"},{"v":"2380393"},{"v":""},{"v":"0"},{"v":null},{"v":"20820941"},{"v":"69.134.50.153"},{"v":null},{"v":null},{"v":"1123811750"},{"v":null},{"v":null},{"v":null},{"v":null},{"v":"5696"}]})
WrappedTableRow({"f":[{"v":"User:TheBigJagielka/Samuel Galindo"},{"v":"25455636"},{"v":""},{"v":"2"},{"v":null},{"v":"337561555"},{"v":"203.112.84.138"},{"v":null},{"v":null},{"v":"1263372806"},{"v":null},{"v":null},{"v":null},{"v":null},{"v":"2291"}]})
WrappedTableRow({"f":[{"v":"User talk:129.12.200.49"},{"v":"1211489"},{"v":""},{"v":"3"},{"v":null},{"v":"111561147"},{"v":null},{"v":"3315117"},{"v":"Qxz"},{"v":"1172665180"},{"v":"true"},{"v":null},{"v":null},{"v":"Level 1 warning re. [[Apollo]]"},{"v":"19031"}]})
WrappedTableRow({"f":[{"v":"Bhutan"},{"v":"2421391"},{"v":""},{"v":"0"},{"v":null},{"v":"212949166"},{"v":null},{"v":"96159"},{"v":"Riyehn"},{"v":"1210984268"},{"v":null},{"v":null},{"v":null},{"v":"fixed per capita income in economy"},{"v":"49647"}]})
WrappedTableRow({"f":[{"v":"Messiah"},{"v":"19616"},{"v":""},{"v":"0"},{"v":null},{"v":"188055849"},{"v":null},{"v":"1796696"},{"v":"Noobeditor"},{"v":"1201743987"},{"v":"true"},{"v":null},{"v":null},{"v":"Reverted edits by [[Special:Contributions/162.83.159.167|162.83.159.167]] to last version by Steven J. Anderson"},{"v":"26802"}]})
[success] Total time: 4 s, completed 2015/11/09 22:42:14

やったねたえちゃんプログラムから動かせたよ。
たかがSELECT *なのになんか楽しいですね!そんな気持ちを忘れちゃいけないんだと思います。

3.ハマったこと

強くハマったわけではないんですけど、TIMESTAMP型を扱うときにうーんってなったのでメモ。
joda.time.DateTime型に変換しようとしたらちょっとめんどかったという話です。
これ書こうと思ってpublicdata見たらTIMESTAMP型なかったので generatedata.com で用意しました。
テーブルfooとか雑過ぎですね。

スキーマはこんな感じ。

f:id:arata3da4:20151109224443p:plain

  • build.sbt
libraryDependencies += "com.github.seratch" %% "bigquery4s" % "0.3"

libraryDependencies += "joda-time" % "joda-time" % "2.9"
package vu

import bigquery4s.BigQuery
import org.joda.time.DateTime

object BigQueryDemo2 {
  val bq = BigQuery.fromServiceAccount(
//略
  )

  val projectId = "mysamplebqproject"

  def main(args: Array[String]) {
    val sql = "SELECT created FROM [dummy.foo] LIMIT 10"
    val jobId = bq.startQuery(projectId, sql)
    val result = bq.await(jobId)
    bq.getRows(result).foreach(r => println(r.cells.head.value.getOrElse("")))
  }

}

これを実行すると

> run

 [1] vu.BigQueryDemo
 [2] vu.BigQueryDemo2

Enter number: 2

[info] Running vu.BigQueryDemo2 
11 09, 2015 11:02:12 午後 com.google.api.client.googleapis.services.AbstractGoogleClient <init>
警告: Application name is not set. Call Builder#setApplicationName.
1.436453925E9
1.433881786E9
1.448222214E9
1.463913534E9
1.419150889E9
1.430968225E9
1.436388839E9
1.465884312E9
1.450501949E9
1.440506521E9

となり、指数表記になり、数字として扱うならDouble型で受け取って、toFloatとかしてDateTimeに変換とかまどろっこしいことをしなければいけません。
それ以外無いのかなぁって思って探したらBQに関数があるのでそれを利用出来るみたいです。

Query Reference - BigQuery — Google Cloud Platform

FORMAT_UTC_USEC とか TIMESTAMP_TO_MSECとか使えば良さそうな感じが出てます。

package vu

import bigquery4s.BigQuery
import org.joda.time.DateTime

object BigQueryDemo3 {
  val bq = BigQuery.fromServiceAccount(
// 略
  )

  val projectId = "mysamplebqproject"

  def main(args: Array[String]) {
    val sql = "SELECT FORMAT_UTC_USEC(created) as a, TIMESTAMP_TO_MSEC(created) as b FROM [dummy.foo] LIMIT 10"
    val jobId = bq.startQuery(projectId, sql)
    val result = bq.await(jobId)
    bq.getRows(result).foreach(r => println(r.cells.head.value.getOrElse("")))
    bq.getRows(result).foreach(r => println(r.cells(1).value.getOrElse("").toString.toLong))
  }

}

これを実行すると

> run

 [1] vu.BigQueryDemo
 [2] vu.BigQueryDemo2
 [3] vu.BigQueryDemo3

Enter number: 3

[info] Running vu.BigQueryDemo3 
11 09, 2015 11:13:53 午後 com.google.api.client.googleapis.services.AbstractGoogleClient <init>
警告: Application name is not set. Call Builder#setApplicationName.
2015-07-09 14:58:45.000000
2015-06-09 20:29:46.000000
2015-11-22 19:56:54.000000
2016-05-22 10:38:54.000000
2014-12-21 08:34:49.000000
2015-05-07 03:10:25.000000
2015-07-08 20:53:59.000000
2016-06-14 06:05:12.000000
2015-12-19 05:12:29.000000
2015-08-25 12:42:01.000000
1436453925000
1433881786000
1448222214000
1463913534000
1419150889000
1430968225000
1436388839000
1465884312000
1450501949000
1440506521000

見慣れた感じになりました。
もっといい方法ありそうだけど、今日は眠いのでとりあえずここまで。
また色々遊ぼうと思います。あと3日で無料枠切れるけど。

(だいたい)新卒エンジニア向け技術交流会vol.4 を実施して話したという話

9/19(土)にこんなイベントがありました。

ngineerxiv.doorkeeper.jp

今回シルバーウィーク前だし、そんなに人来ないかもしれないから発表するって言っておこうって思ったら結構発表者多くなってびっくりでしたw
今回はScala.jsがネタにあふれて面白そうだったので、使ってみた感じの話をしました。

■自分の発表

資料はこんな感じです。

www.slideshare.net

やったのはVue.jsのExampleにもあるTODOアプリ(?)をScala.jsで書いてみた感じのことです。
レポジトリはこちら

github.com

そして、感想にも書いたのですが、Dom周りと密接に関わるライブラリを使ってScala.jsでJavaScriptを書くのはDynamicを利用する部分が多く、Scalaの良さを活かしきれない感じがしました。
あとコンパイルの速度の話はしませんでした。

■他の方の発表

@petitviolet 氏による 「初めての関数型プログラミング

speakerdeck.com

名前初め読めませんでしたが、覚えました←w
もなどについてよくわかってないのですが、理解が少し深まった気がします。

@__papix__ 氏による「キラキラ技術に群がる俺達お前達に物申す」

資料は見当たらなかったのですが、タイトルから変更して、YAPC::EUに発表者として参加してきた時の話をしてくれました。
スペインのエレベータは閉じるボタンが無く、閉じるだと思って押すとブザーがなるというつらいインターフェースの話が心に残ってますw
インターフェース大事ですね

YAPC::Europe 2015


@YAMITZKY 氏による「Alfred Workflowで業務効率化してみた」

Alfredの無料のものを使っている、コミットメントが足りない我々に対する熱いメッセージが伝わりましたww
ライセンスを買った有料版だと色々カスタマイズしたスクリプトをターミナルから起動したり出来るみたいですね。
興味はわいたのでお金に余裕があるときに買ってみてもいいかなぁ・・・って思って・・・ます。

www.alfredapp.com

■次回予告とか

一度参加していただけた方をSlackチームに招待して色々他のイベントとかもやってたりします
今度は中で結成したチームでIsuconに出るつもりです。
(チーム名は「Dark」です)
このイベント自体はまた3ヶ月後の12月にやろうと思います。
気になる方々は是非参加してください〜

Dark - Developers at Real Kommunity | Doorkeeper

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