WEB上だと空のプロジェクトとかでLighthouseの高得点を目指す記事はあるけど、実用的なPWAアプリでの情報は少ないので試したことをまとめてみる。
履歴書をスマホで入力できてPDFで出せる新サービスyagish履歴書。
まだまだ改良の余地はあるけど使える状態。
まず結果。
5日ぐらいがんばった後のレポートはこれ。
Chrome拡張でLihghtHouseのバージョンは3.0.1。
ユーザーの第一印象となるトップページだけがんばった。
実行のたびに結果は変わる(Peformance 50~77点ぐらい)
Performance以外の100点は意外と簡単だった。
ただ足りないのを追加したり、よくないのを変えていく感じ。
Performanceはコード量とか処理を減らせというので難しい。
でも45点だった最初と比べると、スマホでも初回5秒以上かかっていた読み込みが体感できるほど早くなり、やってよかったと思っている。
緑(75点)以上で妥協するのも全然いいと思う。
Vueは下記PWAテンプレートをもとに開発している。
GitHub - vuejs-templates/pwa: PWA template for vue-cli based on the webpack template
これは現在すでにメンテモードになってしまい、下記プラグイン形式に移るので今からはじめるならこっち。
大きいところだとWebpackが3だったのが4になったりして、そのままは移せない。
vue-cli/packages/@vue/cli-plugin-pwa at dev · vuejs/vue-cli · GitHub
いろいろ試行錯誤したけど、効果が大きかったのは下記3つ。
1.画像は可能な限り小さくする
最初は履歴書のサムネがjpgで60KBあったけど、PhotoshopでPDFを開き、幅480pxに縮小、PNGで保存し、さらに下記サービスで圧縮したところ、10KB前後まで削減でき、文句言われなくなった。
色が少なく、はっきりしている画像はやっぱりPNGが強い。
ロゴやヤギなど他の画像はVGを使っているため、この手法は使えなかった。
2. vue-routerで遅延評価
js側だとこれが一番効いた気がする。
公式ドキュメント通り、ページで使うVueコンポーネントをPromise返しにするだけでおk。
動作もほとんど影響しないが、これまでトップページでも読み込まれていた他のページのファイルが分割されて20点ぐらいあがった。
formatList はトップページで使うコンポーネントのため、直接importのままにした。どっちにしても数字的にはたいして影響しなかった気がする。
router/index.js
before
import Vue from 'vue' import Router from 'vue-router' import formatList from '@/components/FormatList' import formatDetail from '@/components/FormatDetail' import formatEdit from '@/components/FormatEdit' import notFound from '@/components/NotFound' import helpPage from '@/components/pages/Help' import termsPage from '@/components/pages/Terms' import serviceInfoPage from '@/components/pages/ServiceInfo' const router = new Router({ mode: 'history', routes: [ { path: '/', component: formatList, name: 'formatList', meta: { title: SITE_TITLE } }, { path: '/format/:id', component: formatDetail, props: true, beforeEnter: formatExistsOr404, name: 'formatDetail', meta: { title: '書式詳細 - ' + SITE_TITLE } }, // 省略
after
import Vue from 'vue' import Router from 'vue-router' import formatList from '@/components/FormatList' import formatsData from '@/assets/formats/index' const formatDetail = () => import('@/components/FormatDetail') const formatEdit = () => import('@/components/FormatEdit') const notFound = () => import('@/components/NotFound') const termsPage = () => import('@/components/pages/Terms') const serviceInfoPage = () => import('@/components/pages/ServiceInfo') const helpPage = () => import('@/components/pages/Help') // 省略
router以外でも動的コンポーネントを使っている箇所も遅延にしてみたけど、大して変わらなかった。
WEBフォントは必須にしない
今回のサービスの特質上、ユーザーとPDFサーバーでフォントをそろえる必要があった。
GoogleのWEBフォントを使っており、サイト上でもメインで使っていたけど、読み込まれるまで文字が表示されないため、大きく減点されていた。
そこでWEBフォントはどうしても必要な履歴書のプレビュー画面だけにして、他の箇所では優先順位をさげた。
あと原因が分かったけど改善が難しいもの。
vendorファイルのサイズ削減
つかってるjsのライブラリがまとまるvendorファイル。
これが3MBありビルド中もtoo Large的な警告が出ていた。
中身を確認するには下記コマンド(Webpack Bundle Analyzer)がいいらしく、今回のPWAテンプレートにも入っていたので実行してみた。
How to troubleshoot a large vendor file? · Issue #1297 · vuejs-templates/webpack · GitHub
Webpack Bundle Analyzerについて詳しくはこれ。今回ホスト名、ポート番号は設定で変えた。
www.npmjs.com
絶望の結果がこれ。
element-uiとfirebaseが2大巨頭だがどっちも深く使っているため大きく削れない。
elementは使ってないものは省けるが、commonがでかすぎて、他を削ったところで数十kb削減にしかならず、効果は薄かった。
firebaseは公式にある通り使っているものだけrequireしている。
Firebase を JavaScript プロジェクトに追加する | Firebase
でもPerformanceには1点も効果がなかった。
あと小さいけどlodashも使っている機能が限られているので、下記のように個別に読み込んでサイズを小さくできたが、これも結果はほぼ変わらなかった。
const MyLodash = { forEach: require('lodash/forEach'), compact: require('lodash/compact'), debounce: require('lodash/debounce'), orderBy: require('lodash/orderBy'), defaultsDeep: require('lodash/defaultsDeep') } module.exports = MyLodash
トップページの高速化ならPWA +AMP
というわけで、Vueなどを使ったSPAではライブラリの容量が大きくロード時間などで100点は難しい。
そのため、これ以上の高速化となるとAMPを組み合わせるしかない。
詳しくは公式ドキュメント
www.ampproject.org
これを使えばAMPで高速に表示して、その間にService Workerでロードしつつ、リンク先ではSPAが動くという形にでき、最初の画面表示を爆速にできるはず。