NuxtにLazyLoadを入れてみた

2019/3/5 追記

LazyLoadを導入しましたが、サイト速度が向上したかに関して、現状測定していません。 Page Speed Insight の点数が向上したという結果のみ得ています。 そのため、実際にパフォーマンス向上に貢献できているかは不明です。

Webパフォーマンスの振り返り 2018 - Webパフォーマンスについて 上記のtakehora様の記事にあるように、<img decoding ="async">を用いる方がいいのではないかと思います。 (ただ、そこに関しても自身で測定できてないので、全体のパフォーマンス測定したら追記します。)

経緯

画像がいっぱい表示されるサイトをNuxt&SSRで、作っている。 なので、画像を読み込む時間が結構かかって困ってた。 LazyLoadすればいいことはわかってたけど、SEOへの影響がよくわからなくて、プロダクト的にNGだった...

しかし、Googleが11月にこのような実装方法を出してくれたので、Goサインがでた! developers.google.com

やったこと

まず、VueLazyLoadがめっちゃ便利なので、それをインストール

github.com

import Vue from 'vue';
import VueLazyload from 'vue-lazyload';

Vue.use(VueLazyload, {
  preLoad: 1.1,
  attempt: 1,
  observer: true,

  observerOptions: {
    rootMargin: '0px',
    threshold: 0.1
  }
});

上記のように、pluginファイル作って、nuxt.config.js に ssr: false にして、追記 observerをtrueにすることが必要で、そうすると、Googleの解説記事にある ブラウザnativeの IntersectionObserver を使ってくれる。 ただ、これだけだとIEとか動かないので、app.htmlに、直接polyfillを追加した。

<script
    async
    src="https://cdn.polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"
></script>

困ったこと

初期表示時は、SSRしたもの画像が表示されるので、vue-lazyloadのマニュアル通りに、初期画像を設定しても上手くいかなかった。 なので、下のようなコンポーネント作って、Lazyload使うときは、常にこれ使うようにしたらいい感じになった!

<template lang="pug">
  img(src="~assets/images/background/pixel.png" :alt="alt" v-lazy="src")
</template>

<script>
export default {
  props: {
    src: {
      type: String,
      required: true
    },
    alt: {
      type: String,
      required: true
    }
  }
};
</script>

LazyLoadめっちゃ便利!

追記

下記の記事を見つけた。

画像の非同期デコーディング

Webパフォーマンスの振り返り 2018 - Webパフォーマンスについて

<img decoding ="async"> とつけると、画像デコーディングが非同期で行われ、ページ表示まで早くなるらしい。
自分の環境(通信速度が早い)だと、LazyLoadした時と比べて、初期表示とかの体感では変わらなかった。
むしろ、LazyLoadしてると、表示後画像が出るまでにどうしても遅れる(特に画像が大きい時)ので、しない方が体感としては良い。

一方、audit(lighthouse)で試してみたら、点数がLazyLoadと比較して、明らかに下がっていた。
ということは、page speed insight でも点数は下がるはずで、これがSEOとかに影響与えないか(多分ないはずだけど)不安。

ただ、ユーザ体験を考えると、LazyLoadないほうがいいのかもと思った。
あとは、コストの問題だなって感じ。
大規模にならないとあんまり変わんないけど。

将来は、LazyLoadがブラウザ標準になるっぽいから、<img decoding='async' lazyload='on'>という書き方がデフォルトになっていくのかも。

Nuxtで画像ファイル名に変数を入れたい場合

地味に、変数を画像ファイル名に入れて、かつsrcsetを使いたい時悩んだので、備忘録も兼ねてメモ

画像を呼び出す時

<template lang="pug">
img(src="~assets/images/hogehoge.jpg" srcset="~assets/images/hogehoge@2x.jpg 2x")
</template>

アセット - Nuxt.js にあるように、

  • ~/assets とせずに、~assets とする。
  • 文字列として渡す

そうするとコンパイル時に、require('~assets/images/hogehoge.jpg') に変換してくれる。

変数をファイル名に入れて、画像を呼び出す時

img(:src="require('~/assets/images/hogehoge' + variable + '.jpg')" srcset="require('~/assets/images/hogehoge' + variable + '.jpg') + ' 2x")

一方、変数をファイル名に使いたい場合は、

  • ~assets とせずに、~/assets とする。
  • Javascriptとして渡し、かつrequireで囲んであげる

これでOKなはず。

React Native & Firebase 勉強メモ

Expoとは?

tech.maricuru.com ざっくりメリット:React Natvieの開発が簡単になる!

ざっくりデメリット:Expoが提供していないNativeのAPIが利用できない。
SDK API Reference - Expo Documentation

React Nativeで動かす。

Android使ってます。

facebook.github.io

  1. 上記チュートリアル通り、expo-cli をインストール。選択肢はblankじゃないと、なんかnativebaseが上手く動かなかった...
  2. AndroidにもExpoアプリをインストールする。
  3. QRコードが、ブラウザ上に表示されると思うので、それをExpoアプリで読み取る。(Androidは開発者モードにする必要があるっぽい)
  4. editorでなんか修正してみる
  5. 反映されてる!!

実機持ってない場合は、 docs.expo.io こちらを参考にしたらエミューレータでできるはず。(試してはない)

Firebase

動画を主に参考にした。

www.youtube.com

流れとして、

  1. NativeBase という UIコンポーネント集を使って、レイアウトを組む。
  2. Firebase のアカウント作る。
  3. ログイン、登録関数を作る。 って感じで簡単にできた...すごい...

他人に見せる

expo-cli で、 publish or repulish project とすると、QRコードが発行されて、expoアプリで読み取ると、作成したアプリが確認できる...すごい...

gRPC調査

gRPC調査

特性

  • API仕様を強制的に明文化
  • 違う言語での高速で堅牢な通信を可能にする。

マイクロサービスとの相性

James Lewis/Martin Fowlerの"Microservices"日本語訳

  • サービスが切り分けられている。
    • サービス間の結合部分は疎にする必要がある。
    • そして、その結合部分の仕様は明確に定義したい => gRPC!!
    • サービス間は高速に通信したい => gRPC!!
  • サービスによって目的が違う

REST とか GraphQL じゃだめなの?

gRPCはルールが明確に決まっている。 マイクロサービスを構築する時に、連携部分が明確なのはメリット! また、通信速度は一番早い。 ちなみに、双方向通信が可能!

gRPCの大きな問題点

HTTP2通信でないといけない。 ALB(AWS) => EC2 間の通信は、HTTP2は使えないので無理

マイクロサービスの大きな問題点

監視、管理の複雑性が増す

どうする?

最近流行ってそうなのが、Kubernetes + Envoy + Istio

Kubernetes

  • コンテナ環境を本番運用する際に必要な機能を提供してくれる。
  • アプリのスケーリングや、デプロイを容易にしてくれる。
  • NATS(queueサービス)などの、CNCFのプロジェクトと相性がいい。
  • これやりたいなーと思ったら誰かが実装してくれてる!

Envoy

nginxをマイクロサービス用に使いやすくしたみたいな認識でOKっぽい。 https://speakerdeck.com/mpon/envoywofen-kariyasukuli-etutuapp-meshfalsehua-wosimasu いろいろ機能持ってる。 - HTTP2のサポート - URLによって振り分け先のサーバを切り替えられる - 自動リトライ, CircuitBreaker, リクエスト制限 - ヘルスチェック - 動的な設定変更、サービスディスカバリー

Istio

Pod間の通信にEnvoyを挟むことで、トラフィックのモニタリングや、コントロールを行う。 - トラフィックの90%をAで、10%をBに送るとかできる。 - カナリヤリリースや、ABテストもできる! - 特定の端末だけ、違うサービスに送るとかもできる! - サービスや、URL毎にリクエストのエラーレート / レイテンシ / コネクション数のモニタリング - サービス間の通信を暗号化できる。

個人的なまとめ

サービスが拡大していくに連れて、マイクロサービス化の流れになり、スキル毎でなく、プロダクト毎にチームが分かれていきそう。 その際に、データの結合部分は明確であるべきで、そこにgRPCはぴったり。 ただ、マイクロサービスを進めると、デプロイやスケーリング、モニタリング等が別の問題が出てくる。 そこで、効果的なのがDocker & Kubernetes。 ただ、それだけだとシステム全体の監視(どこで障害がおきたのかとか)や、サービス間のルーティング制御が難しい。 そこを解決してくれるのが、サービスメッシュ(Istion、Envoy)であって、これらを適切に利用していくこと複雑なマイクロサービスを管理できそう。

多分今までだと、準備として、ansible使ってAMI作って、それをAutoScalingGroupに登録して、それをALBに紐づける。その後、CodePipeline & CodeDeployに登録して、githubのpushをhookにして、CodeDeployを実行する。これを環境毎に行っていた。 それが、DockerFileとkubernetesyamlファイルを書いて、CI/CD実行時にDocker build して、kubectl apply を行う感じになるのかなと思う。

docker で、go + gRPC 開発環境構築

protoc ファイルは、一旦Localで生成するとする。

利用したサンプルは、

gRPC

こちら参照。

リモートでやること $ git remote add origin git@github.com:<repository>.git $ go mod init

Dockerfile

FROM golang:1.11.1

WORKDIR /go/src/app
ADD . /go/src/app

ENV GO111MODULE=on

CMD ["go", "run", "main.go"]

docker-compose.yml

version: '3'
services:
  app:
    build: .
    volumes:
      - .:/go/src/app
    ports:
      - "50051:50051"

とりあえず、動くところまではできた! https://github.com/okadak/godocker

はまったこと

参考

go_playground/hot_reload_docker at master · po3rin/go_playground · GitHub

GitHub - yoshi42662/go-grpc: Minimum dockerized gRPC application with go.

gRPCについて調査

gRPCとか使って、マイクロサービスを構築したかった。 調査メモ。

grpc /

grpc /

ruby と go のtutorial やって、ruby のクライアント側と、goのサーバー側立てて連絡させてみた。 tutorial 通りやれば簡単だった。

要は、同じ.protoファイルを元に、それぞれの言語毎にクラス(rubyだったら)生成して、それを普通に使えば良いって感じだった。 調べてたらめっちゃ難しそうだったけど、やってみると簡単だった。

最終的には、Railsをクライアント側にしたいので、Railsに入れてみようとしたが、libフォルダに、protoファイルから作ったクラスをおいて、必要なところでそのクラスを呼べば良いだけだった。

で、Go部分は普通にAPI作るイメージで、チュートリアル通りやればできた。

今後の流れとしては、 1. Goを触ったことないので、勉強して、GoでgRPCサーバ作る 2. Envoy を用いて、ルーティングをいい感じにできるようにする。 3. ECSにあげてみる ところまではとりあえず頑張りたい。

最初は、gRPC gateway が必要なのかなって思ってたけど、BFF構成だと、rubyはgRPC読めるし必要なさそう。

Nuxt + Rails の開発構成考えてみた

考えたきっかけ

新規サービス作るにあたって、構成考えてみた。
将来的にはアプリ化するということで、それを見越して、API + SPA の形にしてみた。 下の画像のイメージ。 正直、静的ファイルはCDNに置いた方がよくない?って感じだけど、Dockerの勉強も兼ねて。

f:id:okadak1990:20181212233035p:plain

開発用

version: '2'
services:
  app:
    build: .
    image: rails_dev
    volumes:
      - .:/app
    ports:
      - "3000:3000"

  nginx:
    build: nginx
    image: nginx_dev
    ports:
      - "80:80"
    volumes_from:
      - app
    depends_on:
      - app

  # railsディレクトリの中に、frontendというフォルダ名で、nuxtをぶっこんでる。
  nuxt:
    image: nuxt_dev
    build: frontend
    ports:
      - '4000:4000'
    volumes:
      - ./frontend:/frontend
      - node-modules-data:/frontend/node_modules

volumes:
  node-modules-data:

本番用

version: '2'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile_dev
    image: rails

  nginx:
    build: nginx
    image: nginx
    ports:
      - "80:80"
    volumes_from:
      - app
    depends_on:
      - app

docker-compose 一回で開発環境も、本番環境も起動できるようになった。 dockerすごい...けど、少人数開発ならlocalだけで良いのでは?と思ったりもする。