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がめっちゃ便利なので、それをインストール
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使ってます。
- 上記チュートリアル通り、
expo-cli
をインストール。選択肢はblankじゃないと、なんかnativebaseが上手く動かなかった... - AndroidにもExpoアプリをインストールする。
- QRコードが、ブラウザ上に表示されると思うので、それをExpoアプリで読み取る。(Androidは開発者モードにする必要があるっぽい)
- editorでなんか修正してみる
- 反映されてる!!
実機持ってない場合は、 docs.expo.io こちらを参考にしたらエミューレータでできるはず。(試してはない)
Firebase
動画を主に参考にした。
流れとして、
- NativeBase という UIコンポーネント集を使って、レイアウトを組む。
- Firebase のアカウント作る。
- ログイン、登録関数を作る。 って感じで簡単にできた...すごい...
他人に見せる
expo-cli で、 publish or repulish project とすると、QRコードが発行されて、expoアプリで読み取ると、作成したアプリが確認できる...すごい...
gRPC調査
gRPC調査
特性
- API仕様を強制的に明文化
- 違う言語での高速で堅牢な通信を可能にする。
マイクロサービスとの相性
James Lewis/Martin Fowlerの"Microservices"日本語訳
- サービスが切り分けられている。
- サービス間の結合部分は疎にする必要がある。
- そして、その結合部分の仕様は明確に定義したい => gRPC!!
- サービス間は高速に通信したい => 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とkubernetesのyamlファイルを書いて、CI/CD実行時にDocker build して、kubectl apply を行う感じになるのかなと思う。
docker で、go + gRPC 開発環境構築
protoc ファイルは、一旦Localで生成するとする。
利用したサンプルは、
こちら参照。
リモートでやること
$ 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 mod init
は、githubとかで、remote origin を設定しなければエラーが起きてハマってしまった。- proto ファイルから、ファイル生成時に、バージョンエラーが起きた。 - こちら参考にした。 goでprotobufやgrpc-ecosystemを最新にしたらエラーが出るようになった件の対処 - Qiita
参考
go_playground/hot_reload_docker at master · po3rin/go_playground · GitHub
GitHub - yoshi42662/go-grpc: Minimum dockerized gRPC application with go.
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の勉強も兼ねて。
開発用
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だけで良いのでは?と思ったりもする。