[秋葉原] Vue.js入門 輪読会 10章 中規模・大規模向けアプリケーション開発 (実装)
自己紹介
- 名前
- 杉田寿憲(@toshi0607)
- 仕事
- Go + k8sのマイクロサービスのバックエンドエンジニア
- 趣味
- 『Goで学ぶAWS Lambda』 技術書典
- Serverless Advent Calendar 2018 ①、②
- モチベーション
- フロントがVue.js + Nuxt.jsのでバックエンドがどういう感じだと嬉しいか・困るのか知りたい
- サーバーレスSPAの文脈でのVue.jsの盛り上がりに乗りたい
10章の位置付け
中規模・大規模向けのアプリケーション開発
- 8章: ①開発環境のセットアップ
- 9章: ②設計
- 10章: ③実装
8章でやったこと
- アプリケーションの仕様確認
- アプリケーションの雛形(vue init)
- webpack向けテンプレート
- ESLint: Standard
- unit test: true
- test runner: karma
- e2e: Nightwatch
- APIサーバー用のExpressの雛形準備
など
9章でやったこと
- コンポーネント設計
- 状態モデリング
- Vuexを利用する前提のデータフロー設計
- アクションの雛形作成
- API通信用モジュール雛形作成
- routerの仮定義
など
10章の様子
- 10.1 開発方針の整理 p350〜351
- 10.2 コンポーネントの実装 p351〜370
- 10.3 データフローの実装 p370〜375
- 10.4 ルーティングの実装 p375〜379
- 10.5 開発サーバーとデバッグ p379〜388
- 10.6 E2Eテスト p388〜390
- 10.7 アプリケーションのエラーハンドリング p390〜398
- 10.8 ビルドとデプロイ p398〜400
- 10.9 パフォーマンス測定・改善 p401〜410
凡例
- 概要
- 本の内容をまとめたもの
- 仕様
- 本で使われている技術の仕様を確認するもの
- 議論
- 本で論点が提示されていて意見を聞いてみたいもの
- 質問
- 読んでてよくわからなかったので助けてください
- 感想
- 僕が感じたこと
10.1 開発の方針整理[概要]
- テスト駆動でやっていく
p350〜351
10.1 開発の方針整理 [感想]
- フロントもテストから先に書いていくのやったことない
- この本もフロント開発はテストから書いてた
- 『サーバーレスシングルページアプリケーション ―S3、AWS Lambda、API Gateway、DynamoDB、Cognitoで構築するスケーラブルなWebサービス』
- jQueryを使っていながら頑張って構造を持たせようとしている
p350〜351
10.2 コンポーネントの実装 [概要]
- ログインページ、ボードページ、タスク詳細ページのうちログインページに関連するコンポーネントを実装する。
- テスト・本体の順で粒度の小さいものから実装していく。
- atoms -> molecules -> templates
- 粒度の大きいものから実装するとスタブしながら進めなければならない。
p351〜370
10.2 コンポーネントの実装 [概要]
実装するファイル
- src/components/atoms/KbnButton.vue
- test/unit/specs/components/atoms/KbnButton.spec.js
- src/components/molecules/KbnLoginForm.vue
- test/unit/specs/components/molecules/KbnLoginForm.spec.js
- src/components/templates/KbnLoginView.vue
- test/unit/specs/components/templates/KbnLoginView.spec.js
※ソースコードはサポートページに!
p351〜370
10.2 コンポーネントの実装 [概要]
- 仕様(KbnButtonコンポーネントのAPI p332〜333)を満たしたら全て通るテストを先に書く
- 仕様をテストで表現している
KbnButtonコンポーネントの仕様
- プロパティ
- type: ボタンの種別、文字列、text/button
- disabled: ボタンが有効かどうか、真偽値、false/true
- イベント
- click: ボタンのクリックイベント
- スロット
- ボタンのコンテンツ
p351〜370
10.2 コンポーネントの実装 [感想]
-
npm run unit
の実行結果がインデンと含め見やすかった - 見やすくなるように秩序立った
describe
、it
、expect
を書くとテストケース漏れなど気付きやすくできそう - この節はどちらかというとふおおおテスト…!みたいなイメージが強かった
p351〜370
10.2 コンポーネントの実装 [仕様]
import { mount } from '@vue/test-utils'
- マウントされて描画された Vue コンポーネントを含む Wrapper を生成する
-
オプションはたくさんあるが本でも
propsData
、slots
、mocks
、stubs
、localVue
などが使用されている - ドキュメントは日本語版も提供されていてとても親切!!!
vue-test-utils/docs/ja/api/mount.md
p351〜370
10.2 コンポーネントの実装 [質問]
Vue.nextTick( [callback, context] )
- callbackを延期し、DOMの更新サイクル後に実行する
- たとえば、ボタンを押すとフィールドが表示されてフォーカスがあたるようにしたいが、フォーカスするためのフィールドのDOM表示を待ちたいなど?
- ライフサイクルを1つ待つ?
p351〜370
10.3 データフローの実装 [概要]
- loginアクションハンドラ
- AUTH_LOGINミューテーションハンドラ
- AuthAPIモジュール
p337の図
p370〜375
10.4 ルーティングの実装 [概要]
- ガードフックを利用してログイン済みでなければログインページに遷移させる実装
- ログイン済みかどうかは認証トークンの有無で判定する簡易実装
- 本番運用時には認証トークンをバックエンドAPI経由などで検証すべき
- ログインが必要なページかどうかはマッチしたルートのレコードのメタフィールドのrequiresAuthの有無で判定
p375〜379
10.4 ルーティングの実装 [仕様]
グローバルルートガード
- リダイレクト、キャンセルによって遷移をガードする
- 作られた順番で呼び出される
- ルート単位ガード、コンポーネント内ガードもある
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
p375〜379
10.5 開発サーバーとデバッグ [概要]
開発サーバー
- ログイン確認にあたってはローカル環境の開発サーバーに該当エンドポイントのモックを実装する
-
build/dev-server.js
にauth/login
のハンドラーを実装する - 認証できるユーザー情報をメモリにもつ簡易実装
- 'foo@domain.com': { password: '12345678', userId: 1, token: '1234567890abcdef'
p379〜388
10.6 開発サーバーとデバッグ [概要]
デバッグ
- Vue DevToolsはChromeであればエクステンションを登録
- 本のバージョン(2.5.8)と現行のバージョン(2.5.17)ではデザインに差異
p388〜390
10.6 開発サーバーとデバッグ [仕様]
デバッグ
- Components
- ツリー構造
- データの中身
- Vuex
- コミット履歴
- ステート確認
- ペイロードの中身
- タイムトラベルデバッグ などなど
- Events
- $emit発行したイベントがトリガーされた履歴
p388〜390
10.6 E2Eテスト [概要]
- NightWatchのbrowserのコマンドAPIを使用してWebブラウザを操作
- アプリケーショントップ画面にアクセスしてログインが成功しボードページに遷移するまでのケースを実装
npm run e2e
p388〜390
10.7 アプリケーションのエラーハンドリング [概要]
- 子コンポーネントのエラーを補足するために
errorCaptured
フックを利用- エラーハンドリング用のユーティリティコンポーネントを実装し、src/main.js、src/App.vueで読み込む
- グローバルなエラーをハンドリングするために
Vue.config.errorHandler
フックを利用-
errorCaptured
フックと組み合わせる
-
p390〜398
10.7 アプリケーションのエラーハンドリング [仕様]
Sentry × Vue
import * as Sentry from '@sentry/browser'
Sentry.init({
dsn: 'https://<key>@sentry.io/<project>',
integrations: [new Sentry.Integrations.Vue({ Vue })]
})
- Additionally, the Vue integration will capture the name and props state of the active component where the error was thrown. This is reported via Vue’s config.errorHandler hook.
- リアルタイムにエラー検知するだけなら無料
- Slack 連携や分析ができる有料プランも
p390〜398
10.8 ビルドとデプロイ [概要]
-
npm run build
でビルドしたファイル群がdist
ディレクトリに出力される - HTTPサーバーのドキュメントルートに配置すると動作する
p398〜400
10.9 パフォーマンス測定・改善 [概要]
パフォーマンス測定
-
Vue.config.performance = true
に設定 - Chrome DevToolsのPerformanceタブの
vue<コンポーネント名>処理
を確認する- init
- compile
- render
- patch
- renderは実際にライブラリの利用者が触ることが多く、改善の余地が生まれやすい
p401〜410
10.9 パフォーマンス測定・改善 [概要]
パフォーマンス改善
- v-ifとv-showを使い分ける
- データバインドはメソッドより算出プロパティを利用する
- 算出プロパティとウォッチャを使い分ける
- v-forによるリストのレンダリングではなるべくkey属性を利用する
- v-onceでコンポーネントのコンテンツをキャッシュする
- 関数型コンポーネントを利用する
- テンプレートを事前コンパイルする
- テンプレートのコンパイラオプションを利用する
p401〜410
10.9 パフォーマンス測定・改善 [概要]
パフォーマンス改善
算出プロパティとウォッチャを使い分ける
- 算出プロパティでなくウォッチャを使うべき例外的ケース
- ループのような処理コストが高い処理
- 非同期が伴う処理
p401〜410
10.9 パフォーマンス測定・改善 [概要][議論]
パフォーマンス改善
v-forによるリストのレンダリングではなるべくkey属性を利用する
-
リストの内容がガラリと変わる更新が頻繁に起こるようなものにおいては性能向上はそこまで期待できない
- あえてkeyを指定せずin-place patchアルゴリズムに任せるとよくなることがある
- 他に方法はある?
p401〜410
10.9 パフォーマンス測定・改善 [仕様]
パフォーマンス改善
関数型コンポーネントを利用する
- 状態を持たない(リアクティブデータが無い)でインスタンスを持たない(thisのコンテキストが無い)
- コンポーネントが必要とするものは
context
を通して渡される
p401〜410
10.9 パフォーマンス測定・改善 [概要]
パフォーマンス改善
テンプレートを事前コンパイルする
- webpackテンプレートを使っていればビルド時(実行時でなく)にテンプレートをVue Loaderが描画関数にコンパイルしてくれる
p401〜410
10.9 パフォーマンス測定・改善 [概要]
パフォーマンス改善
テンプレートのコンパイラオプションを利用する
- 基本的にアプリケーション向けでなくプラグインやUIライブラリ開発向け
参考資料
- テンプレートのコンパイルからレンダリングまで
- テンプレートのコンパイラによる拡張
- テンプレートコンパイラで最適化した記事