blog

DeNAのエンジニアが考えていることや、担当しているサービスについて情報発信しています

2016.12.02 技術記事

レガシーなwebページをAngularで書き換えてみて良かったこと

by shunsuke.hirano

#javascript

この記事は DeNA Advent Calendar 2016 3日目の記事です。

はじめまして。DeNAでエンジニアをしています。平野です。 かつては大規模プラットフォーム決済システムのサーバーサイドを、 今は"マンガボックス"のサーバー/クライアントサイドを担当しています。

この記事では、 マンガボックスのアプリ内webviewで展開している機能をブラウザにも展開するために、 クライアントサイドをAngularで、サーバーサイドもそれに即すように作り変えた時の基本的な構成の紹介とちょっとしたTipsを記載しています。

自分と同じAngular初学者の方や、既存のサービスをAngularで書き換えるとなんかいいことあるんか?的な方の参考になれば幸いです。

背景

結論に行く前に軽く背景の説明です。レガシーなwebページという若干煽り気味な名前ですが、自サービスの構成のことを指しました。 マンガボックスのiOS/Androidアプリ上で提供している機能のうち、一部はアプリ内webviewで動いており、 とあるURLを叩けばHTMLが返ってくる、たまにAJAXで動的にHTMLを組み換え最終的にwebviewがレンダリングするといういわば普通のwebサイトな構成になっています。

今回その部分をアプリ外のSafariやChromeなどのブラウザでも使えるようにしたいということで、 既存のwebviewが叩いてるURLをブラウザからも叩けるように改修するという方針ではなく、このご時世だしクライアント側にMVCの概念を持たせる構成で再実装してみようというワリとTRY的な位置づけでプロジェクトがはじまりました。

結果的に良くなったこと

  • サーバーとの通信量が減ったことで体感速度が向上した
    • 旧構成では表示する分のHTMLを常にレスポンスとして要していた
    • angularでは表示に必要なデータ部分のみをレスポンスとして受け取り、事前に取得したHTMLにバインドする
  • アプリのwebview部分のネイティブ化への足がかりができた
    • アプリ側が今回用意したAPIを叩くように改修をすれば理屈上ネイティブ化が可能

以上の理由を今回のAngularの構成を紹介しつつ以下で説明していきます。

システムの構成

まず旧構成です。 以下の概念図のように、1画面1エンドポイントになっており、サーバー内で必要な情報をかき集めて最終的にHTMLを返しています。

angularではこれが以下のようになります。

まず `/` へのアクセス時にangularのコードが返ってきますので、これをクライアント側が実行することになります。 その後 `/#/top/` にアクセスすると対応したangularのcontrollerが必要な情報毎にサーバーに対してリクエストを送ります。 そして返ってきたJSONをすでに取得済みのHTMLにバインドしてレンダリングを行います。

またこのような構成にすることで、旧構成ではHTMLが返ってくるために困難だったサーバー側のend to endのテストもイメージしやすくなるはずです。

逆に改善したいこと

  • リリース時の考慮ポイントが増える
    • クライアント側またはサーバー側の挙動が変わるリリースの場合、クライアント側の状態を保証できないため
    • 後方互換性を意識した実装が必要
  • seo対策
    • クローラーがjavascriptを認識できない
    • 仮のHTMLを返す等の対応が必要

Tips

ブラウザバックの検知

静的なデータを扱う場合はブラウザバックで戻ってきたときに再度サーバーにデータを問い合わせる事は不要です。 AngularではAPIのレスポンスをキャッシュすることができるのですが、通常の設定では任意のAPIのキャッシュを常にするorしないのどちらかしか設定することはできません。 なのでブラウザバック等で戻ってきた時とそれ以外の時を以下のコードで判別して、その都度APIのキャッシュをするしないを設定しています。


myApp.run(function($rootScope, $state, $location, $document){
    $rootScope.$on('$locationChangeStart', function() {
        $rootScope.use_cache = ($rootScope.newLocation == $location.path()) ? 0 : 1;
    });

    $rootScope.$watch(function () { return $location.path(); }, function (newLocation, oldLocation) {
        $rootScope.oldLocation = oldLocation;
        $rootScope.newLocation = newLocation;
    });
});

おわりに

Angular化における良かった事悩ましい事をいくつか紹介させていただきました。 クライアント側にMVCモデルの概念を持ち込むことで実装上の役割が明確になり、非常にスッキリとコードを書けたことが印象的でした。 Javascript界隈は次から次へとトレンドが移り変わるイメージがありますが、このタイミングに乗れてよかったと思いました。と同時にこれからはもっと早めに乗っかろうとも思いました。

明日は4日目、key-amb さんです。 お楽しみに!

最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。

recruit

DeNAでは、失敗を恐れず常に挑戦し続けるエンジニアを募集しています。