MicroAd Developers Blog

マイクロアドのエンジニアブログです。インフラ、開発、分析について発信していきます。

JavaScriptフレームワーク(Vue.js)を導入して

マイクロアドでアプリケーションエンジニアをしているNです。
日々、バッチを作ったりWEBアプリケーションを作ったりしています。

今回はライトにJavaScriptフレームワークを導入したお話を書いていきたいと思います。

導入のきっかけ

その1~きっかけのきっかけ~

マイクロアドではいろいろな用途でWEBアプリケーションを利用しています。
当然ではありますが一部特殊な用途ではない限りJavaScriptでの実装が含まれています。
これらのいくつかにはjQueryが使われており、現在も運用されています。

そんな中、
あるWEBアプリケーションを刷新する機会があり改めてjQueryを多用したコードを見返すことに、、、

その2 ~jQueryって非常に強力~

jQueryを多用した実装を見返して、改めて思ったのが jQueryって非常に強力。
一方で、この強力なライブラリになんでもお世話になっていいのかと個人的には思うところがあります。

その代表例としては要素の削除や追加が行われるようなDOM操作。
以下に、たまーに見かけそうなjQueryでの例を示します。(ちょっとわるい例)

[HTML]

<select name="hoge" id="hoge">
    <option value=""></option>
    <option value="a">A</option>
    <option value="b">B</option>
</select>
<div id="choice_area"></div>

[JS]

var $hoge = $("#hoge");
$hoge.on('change', function(){ hugaChange($hoge.val()); });

function hugaChange(param) {
    var $area = $("#choice_area");
    // 要素をごっそり削除。当該要素の子要素にhidden値などを記載していたら大問題。
    $area.empty();
    $.ajax({
        /** 大事じゃないところは、いろいろ省略 */
        data: {a: param},
        success: function(json){
            // json の内容例): [{label: "オプション1", value: 1, }, 
            //                 {label: "オプション2", value: 2, }, ]
            for(var i in json){
                var row = json[i],
                     // こんなところでstyle指定することはあまり無いと思いますがわるい例として
                    $div = $("<div style='border: dashed 1px; margin: 3px;'>"),
                    $checkbox = $("<input type='checkbox'>").val(row.value);
                $div.append($checkbox).append(row.label);
                $area.append($div);
            }
        }
    });
}

[上記ソースコードをブラウザで表示した例] f:id:microad-developer:20180704182635p:plain

ごっそり子要素を空にするような実装や、JavaScript内で追加する要素にstyle属性まで持たせちゃう様な実装をここではあえて記載しました。
過去の経験上メンテナーが同じ人ではない場合、バグに繋がりやすかったり実装が追いづらかったりした一例で「少数でもいいので共感を得たいなぁ」という気持ちからサンプルコードに含めています。
このサンプルコードが少し大げさな例だとしてもjQuery(やjQueryのプラグイン)だけでリッチな画面を作成すると上記に近いソースコードも珍しくないのではないかと思われます。

ただ、 メンテナンス性は決して良くない と個人的に思ってます。

今回刷新したWEBアプリケーションは前述した通りjQueryを多用したもので、 ある程度リッチに作っていたこともありDOM操作が多少含まれていたので、
これはこの機会に HTML , JavaScript をきちんと棲み分けさせてコードの見通しを良くしよう! JavaScriptフレームワークの導入をしよう! という流れなどなどでフレームワークの検討が始まりました。

JavaScriptフレームワーク選定

ここは宗教戦争がおきるので細かい理由は割愛します。結果的にはVue.jsを選定しました。 f:id:microad-developer:20180705144249p:plain

Vue.jsを導入して

結果、非常に良かったと思います。

何が良かったかは後述として1点だけ気になった事があるので先に記述しますと、 jQuery全盛時代に学んだ「HTMLからふるまい(イベントの発火なども含めて)を分けよう。」という考えが逆転しました。(180°とまでは行きませんが)

具体的には画面操作により発火するイベントは一律HTML側に埋め込むことがVue.jsとしての正式なルールとなります。

この点を踏まえてjQueryで示した例をVue.jsで書き直したものがこちらです。

[HTML]

<div id="app">
    <!-- Vue.jsでのイベントは基本v-onというカスタム属性で発火させます -->
    <select name="hoge" id="hoge" v-model="hoge" v-on:change="renewChoice">
        <option value=""></option>
        <option value="a">A</option>
        <option value="b">B</option>
    </select>
    <div id="choice_area">
        <div v-for="data in choiceDatas" style="border: dashed 1px; margin: 3px;">
            <input type="checkbox" v-bind:value="data.value">{{ data.label }}
        </div>
    </div>
</div>

[JS]

var app = new Vue({ 
    el: '#app', 
    data: { 
        hoge: null,
        choiceDatas: [],
    },
    methods: {
        renewChoice: function () {
            // ajaxリクエスト用のライブラリVue.jsには含まれないので別途必要
            request.get("http://hogehuga")
                    .query({a: this.hoge}).end(function (err, res) {
                this.choiceDatas = res.body;
            })
        }
    }
});

如何でしょうか。内容を知るにはVue.jsとしての知識が若干必要にはなりますが、
HTMLとJavaScriptが綺麗に分離された事はVue.jsの知識がなくてもなんとなく読み取れますよね。

良かったこと

HTML, JavaScriptが思ったよりも強く分離できた!

先述のサンプルコードを見ていただいても、御察し頂けるかと思いますが、
HTML, JavaScriptが想像以上に強く分離できました。
狙いはここだったので、その通りうまくいって良かったというところです。
コードの見通しもかなり良くなったと思えます。

ViewModel機能が強力でコード量が減った

Vue.jsの目玉機能といえばViewModel!
これまでの話の流れとサンプルコードから察しがつくかもしれませんが、
JavaScript側にDOM操作を行うようなコードが全く必要なくなりました。
こちらViewModelという機能によるものです。

詳しい話はWikipediaに任せるとして、
(間違いを恐れず)簡単に説明をするとModelとView(HTML)のデータバインディングをしてくれる機能です。
つまりはModelを変更するとデータバインディングされているView(HTML)側もViewModelの機能により描画を変更してくれます。
こちらにより、DOM操作を行うような実装をわざわざ行う必要がなくなりました。 (よってコード量が減りました!)

(Wikipedia) Model View ViewModel - Wikipedia

JavaScriptのユニットテストコードが書きやすくなった

Vue.jsではコンポーネントと呼ばれる単位で画面の部品を作っていきます。
今回のサンプルコードでは比較しづらいですが、 Vue.jsを使って実装した際の副作用としてコンポーネントの区分けやfunctionの区分けが重要になり、 Vue.jsを使う前に比べ開発メンバ全員が自然に小さい単位で実装する様になりました。

これまでは1つのfunctionが大きくなりがちで、それにより確認項目も多くなりテストコードも煩雑になる傾向があったので、
オペレーションによるテストで確認する方が多かったのですが、
先述の通りfunctionを小さく作る事が多くなり、テストコードが非常に書きやすくなりました。

わるかったこと

色々良い面の方が多かったのでしいてあげればレベルです。

学習コストが若干ある

公式ドキュメントもしっかりしていて少し読めばほとんど困ることもないですが、
それでも学習が0というわけでもないので一応というところで上げています。

コンポーネント間のデータ受け渡しが少し大変

コンポーネントは独立した単位でデータを保持していて、
細かく分けた上でコンポーネント間のデータ受け渡しが発生すると、
少し手間が掛かる上にデータの流れが追いづらくなるデメリットがあります。

おわりに

最後にどうしても書きたいことを少し、
今回「jQueryをやめてVue.jsを採用した」という記述になっていますが、
jQueryとVue.jsは競合するライブラリではないので共存することは出来ます。
ただVue.jsを使うことで、これまでjQueryにまかせていた大部分(DOM操作)が無くなるので、 マイクロアドではこの2つの共存を基本行っていません。
*1

この記事の内容はだいぶライトですが、社内ではそれなりにハードにVue.jsを利用しているつもりです。
興味を示して頂き何らかの反応をいただければ、きっと別の社員がもう一歩踏み込んだVue.jsのお話を書いてくれるんじゃないかと期待しています。
最後まで読んでいただきましてありがとうございます。

*1:jQueryにあってVue.jsには存在しない機能については別途のライブラリを入れて解決しています。