Slide 1

Slide 1 text

doda AIジョブサーチ PWAとパフォーマンスの話 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. パーソルキャリア株式会社 サービス開発本部 吉次洋毅 2019/11/12

Slide 2

Slide 2 text

誰︖ • 吉次 洋毅(ヨシツグ ヒロキ) • 1991年⽣まれ(27歳) • 徳⼭⾼専 専攻科修了 • 経歴 – 某レストラン検索サイトでバックエンドエンジニアなど – パーソルキャリアでエンジニアをしつつ フリーランスで受託開発 & 他社さんの開発やプロジェクトマネジメントのお⼿伝い • 趣味 – ⼀⼈旅&写真&スーパー銭湯 – スマブラ(VIPに⾏けそうで⾏けない) – 筋トレ(予定) • 最近触っている技術 – Javascript(Nuxt.js / Express.js) – PWA – AWS / GCP Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 3

Slide 3 text

今⽇のお話と⽬標 1. パーソルキャリア初のPWA『doda AIジョブサーチ』のご紹介 → 前置きです 2. NuxtベースでPWAを作った話 →「これからPWA作ってみよう」という⼈向け。 3. パフォーマンスの計測と改善をした話 →Nuxtアプリケーション/PWAのフロントエンドのパフォーマンスが気になる⼈向け Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 4

Slide 4 text

スライドは後ほど公開します︕ connpassでお知らせします Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 5

Slide 5 text

doda AIジョブサーチの ご紹介 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 6

Slide 6 text

パーソルキャリア初のPWA︕ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. https://doda.jp/AiJobSearch/ ※現時点でスマホ対応のみ • 「イマイチ⾃分に合った検索条件が わからない」、「じっくり転職サイ トを使う時間がない」そんな⼈に向 けた新サービス • 検索ナシ︕ • 希望条件を⼊れて、出てきた求⼈に 対する興味の有無を選ぶだけ︕ • ⽇々賢くなってイイカンジのレコメ ンドをしてくれる というコンセプト 今は最適化されていないので精度よくない 現在内製の機械学習エンジンを鋭意開発中

Slide 7

Slide 7 text

使い⽅ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. 希望条件 の設定 求⼈の振 り分け いい感じ のレコメ ンド⽣成 求⼈への 応募

Slide 8

Slide 8 text

DEMO Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 9

Slide 9 text

転職しようかな〜と思っていて 気になった⽅は是⾮使ってみてください︕ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. ※doda会員登録が必要なので、登録後にいろいろ メールが来たり電話がかかってきたりしますのでご 了承くださいm(_ _)m

Slide 10

Slide 10 text

NuxtベースでPWAを作った話 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 11

Slide 11 text

Nuxt.jsを使っている︖ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 12

Slide 12 text

PWAを作っている or 作ったことがある︖ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 13

Slide 13 text

Vue.js×PWAの概観 • 『Vue.jsで始めるPWA』で検索︕(⼀部最新化出来てませんmm) – https://qiita.com/gyarasu/items/2f18edc4ae251180d89e • PWAでできること – ホームスクリーンへの追加(Add to Home Screen) – キャッシュ(Service Worker Caching) – プッシュ通知(Push Notification) – バックグラウンド同期(Background Sync) • 気になる制約(iOS12 Safari) – 未対応のAPI • Web Push • Background Sync – 参考: 『Whatʼs new on iOS 12.2 for Progressive Web Apps』 • https://medium.com/@firt/whats-new-on-ios-12-2-for-progressive-web- apps-75c348f8e945 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 14

Slide 14 text

PWAとして何から始める︖ • ホームスクリーンへの追加(A2HS) • キャッシュ(Service Worker Caching) • プッシュ通知(Push Notification) • バックグラウンド同期(Background Sync) Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. まずは取っ掛かりやすいところから︕ ※ただし、iOS SafariでのA2HSはcookieの扱いが 微妙かも…あとプロンプトが出ないので⼿動。

Slide 15

Slide 15 text

NuxtアプリケーションをPWA化しよう Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. https://github.com/nuxt-community/pwa-module ちょっとだけcontributeしてます

Slide 16

Slide 16 text

pwa-moduleの導⼊ 1. npmパッケージのインストール 2. nuxt.config.jsのmodulesに追加 3. .gitignoreにsw.*(=Service Workerのスクリプト)を追加 ※不要なmoduleは除外できます Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 17

Slide 17 text

A2HSの設定 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. ウェブアプリマニフェスト(manifest.json)に書 くべき内容をそのままnuxt.config.jsに記載すれば OK https://developers.google.com/web/fundamentals/web-app-manifest/?hl=ja

Slide 18

Slide 18 text

Workboxの設定 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. workboxの設定もnuxt.config.jsに記述

Slide 19

Slide 19 text

Service Worker Cacheについて • Service WorkerによるCacheは2種類 – Pre Cache – Runtime Cache • Pre Cache – 静的なアセットをキャッシュする • nuxt buildしたときのバンドルファイル – Workboxモジュールが有効化されていれば⾃動的にやってくれる • Runtime Cache – 動的なHTTPリクエストをキャッシュする – フロントエンドから⾮同期で呼び出すAPI • Runtime Cacheの戦略 – リソースの特性(更新頻度など)に応じて戦略や保持する期間を設定する – https://speakerdeck.com/gyarasu/pwaji-chu-3?slide=7 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. v3で挙動変わったかも 調査中

Slide 20

Slide 20 text

Service Workerライフサイクル Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. これ、何︖

Slide 21

Slide 21 text

Service Workerライフサイクル • https://developer.mozilla.org/ja/docs/Web/API/ServiceWorker_API /Using_Service_Workers • skipWaiting – “Use self.skipWaiting() anytime before activation to skip installed stage and directly jump to activating stage without waiting for currently controlled clients to close.” – すでにページをコントロールしているSWがある場合も、waitingをスキップしてactive に移⾏する(SWを新しいものに上書きする) • clientsClaim – “Use self.clients.claim() in the active handler to start controlling all open clients without reloading them.” – SWがページをコントロールするようになるのは、activate後に再度ページが読み込まれ たタイミング。初回のページロードのタイミングでコントロールを開始する。 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 22

Slide 22 text

【まとめ】 NuxtのWebアプリをPWA化するのはとっても簡単︕ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 23

Slide 23 text

doda AIジョブサーチ パフォーマンス改善の歴史 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 24

Slide 24 text

Performance Audit Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. ※Simulated Fast3GでのAudit

Slide 25

Slide 25 text

これって良いの︖ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 26

Slide 26 text

パフォーマンスの良し/悪しの観点 • 基本的には、スコアが⾼いほど良いと思っておく – パフォーマンスはUXやコンバージョンに⼤きく貢献する • ⼀⽅で、本来Webサービスが提供すべき価値を忘れないようにする – 実際には、スコアが⾼ければ⾼いほど良いとは⼀概には⾔えない… – 例えば、スコアを伸ばすために本来に必要なコンテンツを削ったりしたら本末転倒… Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 27

Slide 27 text

パフォーマンスの良し/悪しの観点 • 基本的には、スコアが⾼いほど良いと思っておく – パフォーマンスはUXやコンバージョンに⼤きく貢献する • ⼀⽅で、本来Webサービスが提供すべき価値を忘れないようにする – 実際には、スコアが⾼ければ⾼いほど良いとは⼀概には⾔えない… – 例えば、スコアを伸ばすために本来に必要なコンテンツを削ったりしたら本末転倒… Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. 読み込み時間が0.1秒減ると、売上が1%増加 by amazon.com

Slide 28

Slide 28 text

パフォーマンスの良し/悪しの観点 • 基本的には、スコアが⾼いほど良いと思っておく – パフォーマンスはUXやコンバージョンに⼤きく貢献する • ⼀⽅で、本来Webサービスが提供すべき価値を忘れないようにする – 実際には、スコアが⾼ければ⾼いほど良いとは⼀概には⾔えない… – 例えば、スコアを伸ばすために本来に必要なコンテンツを削ったりしたら本末転倒… Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. (パフォーマンス)×(本来提供したい価値)の最⼤化を⽬ 指すのが基本的な指針

Slide 29

Slide 29 text

Lighthouseで確認できるパフォーマンス指標 • First Contentful Paint – 初回のテキストもしくは画像が表⽰されるまでにかかった時間 • First Meaningful Paint – 主要コンテンツが表⽰されるまでにかかった時間 • Speed Index – ページのコンテンツが⽬に⾒える状態になるまでにかかった時間 • First CPU Idle – メインスレッドでの処理が終わってCPUがアイドル状態になるまでにかかった時間 • Time to Interactive – ユーザ操作が可能になるまでにかかった時間 • Estimated Input Latency – ユーザの⼊⼒に対するアプリの応答速度 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 30

Slide 30 text

Lighthouseのまとめ情報 • 『Lighthouse によるウェブアプリの監査』で検索 – https://developers.google.com/web/tools/lighthouse/ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 31

Slide 31 text

開発途中に計測したもともとの姿… Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. しかも、本来出したいコンテンツも完全に⼊ってない状態…

Slide 32

Slide 32 text

どれだけ良くなった︖ 4.3 5.9 5.4 5.9 16.7 3.8 3.8 4.3 5 5.8 0 2 4 6 8 10 12 14 16 18 First Contentful Paint First Meaningful Paint Speed Index First CPU Idle Time to Interactive ms パフォーマンス指標の⽐較 Before After Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 33

Slide 33 text

開発過程でコンテンツのリッチ化と パフォーマンスの改善を両⽴出来た︕ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 34

Slide 34 text

パフォーマンス改善でやったこと • バンドルサイズの縮⼩ • 画像の遅延ロード • 必要なリソースのみ読み込み(計測タグ関連) • APIレスポンスの圧縮 • CDNの利⽤ • 計測対象画⾯のAPIリクエストの最適化 などなど Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 35

Slide 35 text

バンドルサイズの縮⼩ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. • Nuxtでは、内包されいてるwebpack-bundle-analyzerを使ってバンドル サイズを可視化することができる • やり⽅は簡単。nuxt.config.jsでbuild.analyzeをtrueで指定してあげる – https://ja.nuxtjs.org/api/configuration-build/#analyze • UIライブラリとしてVuetifyでA-la-carteを利⽤していたが、使⽤するコ ンポーネントやディレクティブのみ読み込むように変更した – https://ja.nuxtjs.org/api/configuration-build/#analyze 1.4MB → 556KB

Slide 36

Slide 36 text

A-la-carteの罠…︖ • Vuetify⾃体のサイズは⼩さくなったが、pagesのファイルが少しずつ⼤き くなってしまった… • 全体としては30KBの削減にとどまった • pagesのファイル数が増えるとVuetifyを全部読み込む場合よりもむしろ全 体のバンドルサイズが⼤きくなってしまうかも…︖ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. 特定のライブラリを⼩さくする場合に副作⽤がある可能性も 考えておくのが良い。 ご存知の⽅いらっしゃいましたらご教⽰くださいm(_ _)m

Slide 37

Slide 37 text

画像の遅延ロード • vue-lazyloadを使ってファーストビューに含まれない画像は遅延ロード – https://github.com/hilongjw/vue-lazyload Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. 横スクロールしたら初めて⾒える ようになる画像は遅延ロードする (3枚⽬以降)

Slide 38

Slide 38 text

必要なリソースのみ読み込み(計測タグ関連) • doda AI JobSearch(https://doda.jp/AiJobSearch/)はdoda (https://doda.jp/)の括りに含まれるサービス • ⼀⽅でAI JobSearchはターゲットを絞って運⽤しており、dodaで導⼊し ている広告タグや各種ツール系のタグ等は不要。 • GTMでそれらを設定しているが、AI Job Search側では読み込みたくない ので、GTMのコンテナを分け、必要最低限のタグのみを設定することで対 応。 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 39

Slide 39 text

APIレスポンスの圧縮 • 求⼈情報を取得するためのAPIのレスポンスに、多くの情報を含めている のでレスポンスサイズが⼤きくなってしまっていた • バックエンドのAPIサーバは現在Express.jsで構築しているので、 compressionを使⽤して、APIレスポンスをgzip圧縮した。 – https://github.com/expressjs/compression – levelの設定は6(=デフォルト)くらいで圧縮率が頭打ちになったので6にした • 20件程度の求⼈情報を含むAPIのレスポンス • 求⼈⼀覧表⽰⽤と、詳細表⽰⽤でエンドポイントを分けて最適化するよう な対応は別途検討する必要がある Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. 192KB → 59KB

Slide 40

Slide 40 text

CDNの利⽤ • バンドルファイルや求⼈画像の静的アセットはCDNに置く • dodaではAkamaiを利⽤中 • CDNの恩恵 – 距離が近くなる(dodaの場合国内向けサービスなのでそこまで恩恵はないかも) – デバイスに最適化した画像の配信 – トラフィック分散 – 可⽤性の向上 • Nuxt.config.jsのbuild.publicPathにCDNのURLを指定すると、nuxt build実⾏後、クライアント側のバンドルファイルをCDNをアップロード する – https://ja.nuxtjs.org/api/configuration-build/#publicpath Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 41

Slide 41 text

PWAでCDNを使うときの注意点 • CDNにクロスオリジンでアクセスする場合は要注意 • Service WorkerからCDNにアクセスできない問題が発⽣する • 『Nuxt × PWA × CDNでハマった件について』 – https://qiita.com/gyarasu/items/005e4c74fa166d048dbe – scriptタグのsrc属性でのクロスオリジン指定はOK(HTML5の仕様) – Service Workerは内部的にjsによってHTTPリクエストを⾶ばしているので、この部分 で引っかかる Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 42

Slide 42 text

APIリクエストの最適化 • 計測対象画⾯では初期表⽰時に複数のAPI を呼び出している – いいねサマリ取得API – Yes/Noチェック⽤の求⼈リスト取得API – レコメンドリスト取得API×2 計4リクエスト • レンダリングは2種類 – SSR: URLに直接アクセスした場合 – CSR: 画⾯下部のタブを押した場合(router.push で移動したとき) • 改善ポイントは2つ – 並列に複数のAPIを呼び出す – SSR/CSRそれぞれに合わせたデータの取得⽅法 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 43

Slide 43 text

APIリクエストの最適化 • もともとは、mounted()内で直列にAPIを呼び出していた – SSR時にコンテンツが⼊った状態で表⽰されない – クライアントサイドでマウントされたあとにAPI呼び出して結果を表⽰するまで待つ必要 がある • fetchの活⽤で解決 – モチベーションは「SSR時にコンテンツを⼊れた状態で表⽰したい」 →レンダリングされる前にデータをストアに⼊れる必要がある – https://ja.nuxtjs.org/api/pages-fetch/ • 複数APIを並列実⾏ – API呼び出しはvuexのactionsに書いているので、actionsの関数はPromiseを返却する ようにする – 必要なAPI分Promiseを⽣成し、Promise.allで並列実⾏ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 44

Slide 44 text

APIリクエストの最適化 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 45

Slide 45 text

SSR時に表⽰されない…︕ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 46

Slide 46 text

“fetch メソッドを⾮同期にするためには Promise を返却し てください。そうすれば nuxt.js はコンポーネントがレンダリ ングされる前に promise が解決されるまで待機します。” Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 47

Slide 47 text

“fetch メソッドを⾮同期にするためには Promise を返却し てください。そうすれば nuxt.js はコンポーネントがレンダリ ングされる前に promise が解決されるまで待機します。” Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. SSR時にPromiseの解決を待たずに画⾯を返してしまう = コンテンツ部分が空になってしまう

Slide 48

Slide 48 text

APIリクエストの最適化 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. Promise返してみた。

Slide 49

Slide 49 text

SSR時に表⽰されるようになった︕ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 50

Slide 50 text

でもタブで切り替えしたとき(CSR)に 引っかかりが⽣じてしまうようになった… Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 51

Slide 51 text

“fetch メソッドを⾮同期にするためには Promise を返却し てください。そうすれば nuxt.js はコンポーネントがレンダリ ングされる前に promise が解決されるまで待機します。” Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. CSR時にもPromiseが解決されるまで待機してしまう

Slide 52

Slide 52 text

CRS時はPromiseの解決を待たずに とにかく画⾯を切り替えたい Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 53

Slide 53 text

CRS時はPromiseの解決を待たずに とにかく画⾯を切り替えたい Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved. 快適なインタラクションを優先したい

Slide 54

Slide 54 text

【解決策】 SSRとCSRで処理を分ける Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 55

Slide 55 text

SSR/CSRに応じたfetch最適化 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 56

Slide 56 text

その他TIPS • ChromeのAuditでパフォーマンス測定する場合はシークレットモードで ⾏う。通常のモードで⾏うと、インストールしているChrome拡張が邪魔 して、スコアに影響することがある。 – 実⾏後にこれが出てたら要注意。シークレットモードでやり直そう。 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 57

Slide 57 text

今後のパフォーマンス関連の展望 • 定期的にパフォーマンスを計測する仕組みづくり – バンドルファイルサイズの可視化をCI/CDに組み込む – フロントエンドの各指標を可視化する仕組みづくり Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 58

Slide 58 text

最後に1つだけ… Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 59

Slide 59 text

パーソルキャリアでは ⼀緒に働く仲間を募集しています︕ Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.

Slide 60

Slide 60 text

終 Copyright © PERSOL CAREER Co., Ltd. All Rights Reserved.