Vue.jsをブラウザゲーム(のデバッグ画面)に取り入れてみた

初めまして、株式会社ORATTAでサーバーエンジニアをしている、自称Vue宣教師のりんです(?
Vue.jsはいいぞ!

私は社内のブラウザゲームのうちの1つを保守しているのですが、Vue.js大好きなんですよ。

ということで治外法権の社内イントラ的な画面なら
「たとえVueで作ったって何も問題なかろう。使い勝手こそ正義である」ということで勝手にいくつか作ってみました。

マスタービューア(イントラ内)

1つはマスタービューアといって、ゲームのマスターデータをブラウザから閲覧するためのツールです。

弊社ではマスターデータがDBではなくphp生ファイルに巨大な連想配列を作っておいて、
それをよしなに扱うというという仕組みになってました。
(開発中のプロダクトではDBに入れるみたいです。)

なんですが、それのビューアがとんでもなくレガシー。

  1. ページングはID100区切り(連番で並んでないと1ページに1個しかないとかザラにある)
  2. 検索不能
  3. インポート/アウトポート機能はあるからExcelに持っていって絞り込んでね(はぁと

ジーザス……😱

ということでVue.js + vue-router + element-ui でごにょごにょーっと作りました。

  1. ページ遷移を挟まないので体感表示が早くなったと好評
  2. ヘッダ行の固定ができる、任意の列の固定ができる
  3. 絞り込み機能(一致だけでなく以上や以下、含む含まないなど、AND条件で複数可)
  4. 列を隠す機能
  5. ほぼ同じ画面をURLで他の人と共有できる(vue-routerで現在表示している状態をURL化している)

基本的にはphpMyAdminとかAdminerとかあのへんの操作感++自分のほしい機能を盛々に盛った感じです。

前述の通り、バックエンドにあるのがDBではなくPHPの配列なので、
画面に表示する分だけ都度ajax通信で取ってくる作りにはあえてしていません。
(別のマスタを表示しにいく時にAjaxで取りに行く)

アクセスのあったマスタのデータは一度に全部とってきて一度メモリにぶちこんでおいて、
Vue.jsの算出プロパティとして実際に表示する配列を別途生成、
よしなに表示できるtable-componentに流し込んで表示ということをやっています。

こちらはゲームの外側で動作していたので、webpackでビルド前のコードのリポジトリを新設して、
ビルド後のコードを今までのイントラのリポジトリにコミットする形にしています。

今のところ完全にビューアなので、CRUDのR機能しかありません。

更新処理もそのうち作りたいなーと思いつつ、自分があまり使わない機能なので一旦棚上げになってます。

まぁ、Excelとのインポート/アウトポートで全て賄われている気もするんですが

デバッグ用カード検索/付与機能(インゲーム内)

もう1個はインゲームのデバッグ画面のカード検索/付与機能です。
今までのものは

  1. そもそも名前での検索機能などない
  2. 付与する際はID直接打ち込むか、セレクトボックスから選んでね!

つらい 😇

ってことで、名前やその他属性から絞りこみ検索できるようにしました。

ここまでは、普通にVue.jsじゃなくてもよかったんですけど、
どうせだったら複数のタイトルで横断的に使えるようにしたら気持ちいいわけですよ。

  • タイトルによって表示したい項目が違うはず
  • タイトルによって値によるデータの意味(属性とか)が違うはず
  • この辺をタイトル毎にちまちま設定したくない

この辺を解決するために、これらをそれぞれJSのオブジェクトとしてコンポーネントの外から渡してやって、いい感じにそれっぽい画面を生成できたら
「あたいったら最強ね!」って気持ちになれそうだと思ったのでやってみました。

まあなんというかVue.jsでやりたいじゃんという強い気持ちです。反省はしてない。

ということで出来上がったのが検索結果をJSONにして、データセットと実際に表示したい構造をVue.jsのインスタンスに渡すと
コンポーネントがよしなに表組みでデータを表示してくれるという代物です。

どうせイントラなので、他のエンジニアが触りそうな場所から Vue.js を可能な限り隠匿した代わりに、
インジェクションとかそういうのは気にせず string をめちゃくちゃ eval するという evil 素敵なコードです。

Gist – Oratta Framework Vue Components
うーん、好き勝手やってますね。
これ作ったあとに <template is=”〜”> を知ったので、表組みのタグ出力がおかしいところ直せるかもしれませんがそのままになってます。
コンポーネントの基本 — Vue.js

こちらは(ユーザーからはアクセスできませんが)ゲームのリポジトリ内にあったため、
ビルド前ビルド後のコードを両方含めるのは微妙だなーと思ったため、
ビルドしないVue.jsを試してみることにしました。

そのあたりでいくつかハマったところがあるのでそれらのメモをば。

vueインスタンスの生成はターゲットのDOMのより下に置かないとエラーになる

 

[Vue warn]: Cannot find element: #app

Vue.jsのインスタンスを生成するとき、そのインスタンスにel: #app とか入れておくと思うんですけど、
この時に対象のDOMが先に書き出されていないと何もレンダリングされません。
ちゃんと調べていませんが、インスタンス生成時にこのDOMを querySelector してるんだと思います。
そこで捕まえられないとエラーになってしまい当然のように動きません。

インスタンス初期化時に初回レンダリングに必要なパラメータがUndefiendだとエラーになる

Vue.jsのコンポーネントを今回の箇所以外でもどこでも使いまわせるように、ということで、
インスタンスの初期化ロジックは利用するテンプレートと別口において、
必要なパラメータはあとからインスタンスに渡すという作りにしてみました。

<div id="vueEnabled">
  <v-table :data="weapons" :struct="template" width="100%">
</div>
//vue_components.html.php
//インスタンス初期化
let vue = new Vue({
  el: "#vueEnabled",
  data: {ready: false}
});
weaopn_list.html.php
//初期化後にあとから
/* ルートテンプレートはvueにくっつける */
vue.template = template;
/* 定数変換をアサイン、セレクトボックス生成用にselectorOptionsに詰める */
vue.enums = enums;
/* weaponsとformの値を詰める */
vue.weapons = <=json_encode($weapons)?> //突然のPHP!
vue.form = <?=json_encode($requested)?>

ところがこのままだとインスタンスの一番最初のレンダリング時に必要なパラメータがないとそこでエラーになってしまって
あとからパラメータを渡しても動いてくれないんですね。

vue.js:584 [Vue warn]: Property or method "form" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
(found in <Root>)

そういうときは、 v-if をつかって必要なパラメータを渡し終えるまでレンダリングしないという力技で解決しました。
うーん、まったくスマートじゃない気がする😇

weapon_list.html.php
<div id="vueEnabled" v-if="ready">
<!-- #vueEnabled の中だけvueコンポーネントは有効 ->
</div>
//weapon_list.html.php
/* 最後にvue.ready = true にしたときに初回のレンダリングがされる */
vue.ready = true;

とりあえずやってみた感想としては、普通にHTMLの中にVue.jsのコンポーネントタグを書き込むだけでよしなにやってくれるので、
既存のサイトにVue.jsをあとから足したいなんてときにも使えるよ!という触れ込みは本当なんだなと実感しました。

とはいえ、仮想DOMを扱うVue.jsと、実際のDOMをガシガシ書き換えまくるコード(そう、jQueryお前だ)との相性は最悪なので、
その辺の世界観が融合してキメラ化すると無限にパワーアップして倒せない魔物と化すと聞いています。
本当はVueだけの世界観を構築しないとひどい目に遭いますが、
今回に関しては画面そのものは新設だったので特にそのあたりで困ることはありませんでした。

ともあれ私はVue.jsが大好きです。
LaravelもVue.jsのコンポーネントを最初から持っているし、時代はVueだ!Vue.jsはいいぞ!
なんたってLaravelでVueを使うにはたった3ステップだ!

手前味噌→LaravelからVue.jsを使う最短レシピとTips – Qiita

余談ですが、壮大なドッキリとか、事務手続き上のうっかりをやらかしていなければ
PHPカンファレンス関西2018でもVue.jsはいいぞしてきます。
白昼夢でも見ていなければどうやら登壇枠受かっちゃったみたいなんだよね……

その前に次は社内で大々的にVue.jsはいいぞしなくてはいけませんかね?
わたなべさーん、スケジュールに予定つっこんでー!


フラグ回収しました!
Vue.js ハンズオン! nakameguro.php #03 (2018/05/25 20:00〜)