astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

PageSpeed Insightsのスコアを上げるために具体的にやったこと

f:id:astamuse:20171206103549p:plain こんにちは。デザイン部でフロントエンドエンジニアをしているkitoです。今回は、Webサイトの高速化を行う際にひとつの基準になりえるPageSpeed Insights について、主にフロントエンドで行える具体的な施策とともにご紹介したいと思います。

PageSpeed Insightsとは?

PageSpeed Insightsは、Googleが提供しているWebサイトのパフォーマンスをスコア化して具体的な改善案を提案してくれるサービスです。スコアの範囲は0~100ポイントで、85ポイント以上が良好とされています。85ポイント以上のスコアであったとしてもPageSpeed Insightsは継続的に改良されているので、定期的にチェックすることをお勧めします。試しにhttps://developers.google.com/speed/pagespeed/insights/に行き、任意のサイトのURLを入力してパフォーマンスを計測してみてください。何の対策もされていないサイトであればスコアが85以下で、ステータスが「Poor」か「Needs Work」になっているかと思います。このスコアは、体感的なサイトパフォーマンスとは必ずしも一致しませんが、PageSpeed Insightsで提案される改善案は具体的で取り組みやすく、筋が良いものが多いのでスコア改善に取り組む価値はあると思います。
スコア下に「適用可能な最適化」という具体策が下記のように列記されているはずです。(対応済み項目は下部にある「適用済みの最適化」に表示されます)

  • 画像を最適化する
  • ブラウザのキャッシュを活用する
  • スクロールせずに見えるコンテンツのレンダリングをブロックしている JavaScript/CSS を排除する
  • 表示可能コンテンツの優先順位を決定する
  • 圧縮を有効にする
  • JavaScript を縮小する

各項目にある「修正方法を表示」をクリックするとプルダウンで、修正すべきコンテンツが表示されます。
例えば、「画像を最適化する」だと圧縮すべき画像の一覧が「〜.jpg を圧縮すると 154.4 KB(71%)削減できます。」という形で表示されるので具体的なアクションが取りやすいです。 私が開発・運営に関わっているサイトでは、対策以前はモバイル・パソコンのスコアはそれぞれ60前後でしたがPageSpeed Insightsに提案された対策を可能な範囲で行うことで、85~90以上のスコア「Good」で安定するようになりました。 では具体的に何をしたのかを見ていきたいと思います。

画像を最適化する

「画像を最適化する」は要するに画像を圧縮しましょうということです。画像圧縮は、gruntやgulpのようなタスクランナーに任せるのが最適だと思います。
ただ、grunt-imageのようなプラグインを使った場合、何も考えずにjpeg画像を圧縮すると、PageSpeed Insightsが求める圧縮率に達しないことがあります。また過度に圧縮して画像が潰れてしまわないように注意したいです。optimizerでjpegRecompressを追加し、色潰れが起きないように目視でクオリティーを調整する必要があると思います。

ブラウザのキャッシュを活用する

「ブラウザのキャッシュを活用する」は、Expiresヘッダーを指定してブラウザキャッシュを活用することが主になりますが、長期間開発・運用されているサイトだと、それ以前に不要なファイルを削除するプロセスが必要かもしれません。私が運用に関わっているサイトでは、使われていない広告タグが複数あり削除するだけでスコアは上がりました。その上でサーバーサイドでExpiresを1週間以上に設定し、画像やJS、CSSファイルの末尾にパラメータをつけアセットの更新を確実に行えるようにしなければなりません。
インライン画像やCSSにパラメータを付与するのはサーバーサイドのスニペットで対応して頂き、フロントエンド側では、htmlにロードされているJSとCSS内の画像URL末尾にパラメータを付与しました。その際使ったのが、grunt-asset-cachebusterというgruntプラグインです。gruntでbuildするタイミングでgetTimeからパラメータを作成し、CSS内の画像URLにパラメータを付与しました。弊社の開発体制では、ステージング環境にdeployされるタイミングでgruntがbuildされるので、そのときパラメータが付与されることになります。

スクロールせずに見えるコンテンツのレンダリングをブロックしているJavaScript/CSSを排除する

この項目は、JavaScript/CSSを出来るだけひとつまとめる and JavaScriptを非同期で読み込むように対策することになります。 JavaScript/CSSをひとつまとめるのは、webpackやgrunt/gulpで基本的に対応できると思います。

CSSファイルを出来るだけひとつにまとめることが大事ですが、まとめきれないCSSが小さいサイズ(具体的には14KB以下)であるなら、htmlにインライン化する方法もあります。
だだし、たとえCSSをひとつにまとめたとしても、その最後のCSSがレンダリングをブロックしている状況は変わりありません。このCSSを非同期で読み込めば良いと考えるかもしれませんが、そうするとCSSが読み込まれる前にhtmlがレンダリングされるのでCSSがあたっていないhtmlが一瞬ちらつくことになってしまいます。
この対策として考えられるのが「クリティカルCSS」という考え方です。ちらつきがおきないようにファーストビューの小さなCSSだけをインライン化して先に読み込み、その他のCSSは非同期で読み込みます。grunt-critical を使えば自動的にクリティカルCSSを作成できます。しかし、留意すべきなのはファーストビューに必要なCSSだけだとしても、サイトによっては巨大になることがしばしばあるでしょう。また、クリティカルCSSの作成を自動化したとしても、レイアウトの異なるページが複数あるとbuildタイムが肥大化するのも厄介な点です。弊サイトでは、他の対策をしてスコアが85以上になったのでクリティカルCSSを採用するまでに至りませんでした。

JavaScriptの非同期読み込みに関しては、まずscriptタグにasync属性やdefer属性をつけて読み込む対策が考えられます。async属性やdefer属性をscriptタグにつけると、JavaScriptを非同期に読み込むようになりレンダリングをブロックしません。注意点としては、scriptタグを読み込む順番を担保する必要があるときはasync属性でなくdefer属性をつける必要があります。 またasync属性やdefer属性に対応していないブラウザを考慮する必要がある場合は、下記のようにcreateElementでscriptオブジェクトを作成してDOMに追加する方法もあります。

var s = document.createElement('script');
s.type = 'text/javascript';
s.src = 'https://◯◯.js';
document.getElementsByTagName('head')[0].appendChild(s);

ライブリを使いJavaScriptファイルを非同期で読み込む方法もあります。LABjsを使えばIE8以下の対応が必要なサイトでも問題なく非同期読み込みを実現できます。

JavaScriptを非同期に読み込むうえでひとつネックになるのは、広告タグのような外部サーバーにあるJavaScriptを読み込んでいる場合です。管理外にあるのでできる対策は限定的です。広告タグを発行しているベンダーが非同期読み込み対応のタグを再発行している場合があるので調べてみるとよいでしょう。 あまりお勧めしませんが、PageSpeed Insightsのユーザーエージェントをみて弾くという方法もあります。

if(navigator.userAgent.indexOf("Speed Insights") == -1) {
  //外部サーバーにあるJavaScriptをここで読み込む
}

PageSpeed Insightsのみ狙い撃ちで対応する方法なので、弊サイトでは導入しませんでした。繰り返しになりますがあまりお勧めではありません。

html圧縮

htmlの圧縮は、インデントや空白の削除を行います。これもタスクランナーなどで自動化することをお勧めします。ローカル開発環境でhtmlを圧縮してしまうと開発時の可読性が大幅に下がるので、ステージングでbuildするタイミングでhtml圧縮するタスクを動かすとよいと思います。個人的にはhtmlを圧縮するのは好みではなく最低限の圧縮にしたかったので、grunt-contrib-htmlminを使いスコアを上げるために空白やインデントを削除するなど最低限かつ効果のある設定にしました。下記のようなオプションの設定でPageSpeed Insightsからは合格点を貰えるはずです。

    htmlmin: {
        dist: { 
            options: { 
                removeComments: false,
                collapseWhitespace: true,
                preserveLineBreaks: true,
                minifyCSS: true,
                minifyJS: false,
                keepClosingSlash: true
            },
            〜省略〜
        }
    },

最後に

今回はフロントエンドの対策を中心に書きましたが、データベースのパフォーマンスチューニングは当然必要になると思われます。またPageSpeed Insightsのスコアへの貢献度は不明確でも重要な項目はあります。例えば、HTTP/2への切り替えなどがそうでしょう。HTTP/2対応したことでサイトパフォーマンスは明白に向上しましたが、PageSpeed Insightsのスコアが向上したかどうかは定かではありません。PageSpeed Insightsはあくまでひとつのベンチマークであることを意識しつつ、UX向上への道標として活用を考えてみてはいかがでしょうか。
アスタミューゼでは、エンジニア・デザイナーを募集中です。ご興味のある方は遠慮なく採用サイトからご応募ください。お待ちしています。

システムテスト自動化カンファレンス2017に登壇します。

こんにちはnishikawaです。唐突ですが、今週日曜日に開催されるシステムテスト自動化カンファレンス2017にて、夕方16:00のセッションで登壇いたします。

タイトルは「TypeScript + PhantomJSを利用した効率的なテスト実施」と題しまして、転職ナビ開発チームで実施したTypeScriptとPhantomJSを使用したテストの事例を紹介させていただきます。

転職ナビチームがどういう活動をしているかを、みなさまに少しでも知っていただければ幸いです。

どうぞよろしくお願いいたします。

パパ(ママ)エンジニア必見!?オープンソースのツールは家庭内でどこまで使えるか検証してみた。〜動画編〜

f:id:astamuse:20171129013328j:plain

お久しぶりでございます。scalaでバックエンドを開発しているaxtstar(@axtstart)です。

今回は、趣向を変えまして、エンジニアは家にかえってもやっぱり エンジニア だと思うので、 ご家庭にいらっしゃる時によくIT系の頼まれごとなんかをママ(パパ)からされたりすると思います。

特に、お子さんのいらっしゃる家庭ではだいたい、お子さんの動画の管理とか、ITに詳しいパパ(ママ)の役目であることが多いかと思います。

うちもご多分に漏れず、子供の動画が結構あって、samba上に置いて私が管理しています。

そんな管理の中で、まぁ私的に役に立ったアレコレを紹介してみます。

今回使うツールは動画を扱うならこれしかないツールの FFMpegOpenCV です。

サンプルで以下の動画を使います

はい。娘が昔作った、自由工作みたいなやつです。。。

※本人の公開許諾済み

動画の時間切り取り

これは何に使うかというと、一連の長い動画を必要な部分だけ、切り取って扱いやすくします。

ffmpeg -ss 01:00 -i input.mp4 -t 05:00 -vcodec copy -acodec copy output.mp4

input.mp4を入力として、1:00から05:00間切り取ってoutput.mp4に出力する video audioのコーデックはコピー

こちら切り取りが早く終わる方法です。

どうも-ssと-iの位置関係には意味があるようで、逆にすると切り取られる場所がずれたりします。

コーデックの指定が異なると(デフォルト設定でも)、再デコード・エンコードが走るせいか、処理時間が長くなります。

運動会や音楽会など、とりあえず1ファイルで撮影していたが、それを分割して保存する場合など活躍するシーンが多いです。

動画の圧縮

これは何に使うかというと、ストレージ容量を節約するために動画の圧縮に使います。

ffmpeg -analyzeduration 30M -probesize 30M -i input.mp4 -c:v libx264 -crf 22 -c:a copy output.mp4

-crf 22・・・22の部分で品質を固定した圧縮を行なっています。

うちもなんだかんだいって、子供の動画のファイルで10年分ほどたまっていて、

生データのまま置いておくのは馬鹿にならない容量なので重宝しています。

動画のクロップ+水平反転

これは何に使うかというと、お遊戯や、劇を撮影したものを、注目する部分のみを拡大し、左右反転することで、子供がそれを見て同じ動作で練習するのに使います。

ffmpeg -i input.mp4 -vf crop=w=640:h=400:x=300:y=0,"hflip" output.mp4

開始位置x(よこ)=300、y(たて)=0、w(幅)=640、h(高さ)=300で切り取って、それを水平に反転(つまりミラー状態に)します。

画像がミラーになるので、画面の左手の動きに合わせて、左手、右手に合わせて右手を動かすというように、左右を対称で考える必要が無くなります。

こんな感じです。

OpenCVの前準備

OpenCVをContribと共にソースからビルドします。

cmakeのファイルを以下におきましたがバージョン・環境でどうもいろいろ試行錯誤した後なのでもしかしたらこれだけではダメかもしれません。

※実はこのビルドが一番苦労したところです。苦労しすぎて何が正解だったかまとめきれていません。。。

また、説明を簡単にするため、以下の雛形を用意しました。これはただ単に、動画のコピーを行うだけの処理ですが、

この下の説明で54行目のところの処理を変更することで、続く各処理をできるようにしています。

使い方: カラー動画が期待される場合

python opencv_simple.py -i input.mp4 -o output.mp4 -c

白黒動画が期待される場合(今回だと、画像のエッジ検出)

python opencv_simple.py -i input.mp4 -o output.mp4

上記の出力は動画のモーションのみのため、音声を別途抜き出し、

出力のoutput.mp4と音声ファイルを結合して再エンコードする必要があります。

これは下記のようにffmpegで作成してます。

ffmpeg -i input.mp4 -ab 128k sound.mp3
ffmpeg -i output.mp4 -i sound.mp3 output_w_sound.mp4

※今回のサンプルではこの処理はやっていません。

画像のエッジ検出

これは何に使うかというと、撮影した動画のエッジを検出して、輪郭のみの動画を作り、お遊戯や劇の練習に役立てようというのに使います。

conv_frame = cv2.Canny(frame, 100,200)

こんな感じです。

実は娘が劇団に入っており、そのダンスの練習に活用してもらおうかと画策中です。

動画のテキスト検出

これは何に使うかというと、タイトルのついた動画を文字認識し、例えばメタ情報として記録する、あるいは動画ファイルのタイトルにしてしまおうというのに使います。

文字認識にtesseract-ocrを使用しているため、ディレクトリに認識したい言語に応じた、学習済みのデータが必要です。

    import pytesseract
    from PIL import Image#
    img = Image.fromarray(frame)
    text = pytesseract.image_to_string(img, lang='jpn')
    print(text)
    conv_frame = frame

今回の動画だとあまりいい結果ではなかったです。

一部貼り付けると、

ダ & に っ て ( く な ぅ し た と こ ろ . % て g し ぃ と こ ろ な ど

作 々 ミ テ ロ ェ ッ ま /
| m&c っ u て < ぁ ぅ し と =a、 見 て mLu と こ ぁ な ら

佳 沼 ミロ ( に ェ ュ こ) ま り ェ ラ |
s ズ は ⑧ Se
_a〝哨麟}}〟 |
縄 い G 体 い い

何書いているかわからない。。。

うーん。手書き文字が結構入っているため、そのあたりかなり不利な動画を選んでしまったかもしれません。

動画の特徴点抽出(Akaze)

こちらは画像のエッジを検出してその場所を判定しています。

    akaze = cv2.AKAZE_create()
    # find and draw the keypoints
    kp = akaze.detect(frame,None)

    cv2.drawKeypoints(frame, kp, frame) 
    conv_frame = frame

何に使うかというと、、、現在試行中です。。

こちらAkazeは使用する際は作者の方が連絡をしてほしいとのことですのでここにもその旨記載しておきます。

最後の方はどんどん自分の興味のある方向に走ってしまい、 家庭の雑用をやっているというより遊んでるようにしか見られなくなるかもしれないのでそこは注意した方がいいですね。

最後になりましたが、弊社ではデザイナー・エンジニアを募集しております。 以下の採用サイトからご応募いただければと思います。

Copyright © astamuse company, ltd. all rights reserved.