https://gyazo.com/16d80e1c81b69d507e1f8210a9993035
Takepepe.icon
規約を儲けて型推論の恩恵あるようにつとめる
nolmplicitThis, nolmplicitAnyをfalseにするとよい
any + assertion で事故るパターンを実践してみて注意することを体験する
potato4d.icon
昔は厳格な型定義したい人向けのツール
現場の導入事例が増えてきた
あんまり any は使わないようにする
いきなりJS => TS に変えたら痛い目にあう
nolmplicitThisをfalseにするとエラーになる
ユーティリティから型定義しやすい
1からだったらstrictにやれる
Takepepe.icon
状態管理に興味がある
公式ガイドがリリース
2.9から型定義のpackageが分割
セマンティックバージョニングを信じていたが… potato4d.icon
custom server 利用しないならnuxt-ts押し takepepe.icon
vue-nextからみるTSサポートの将来(現状判断)
コードサイズが小さくなるkazupon.icon
templateのTS推論対応は確認できず
TSXサポートがデフォルトなので主流になりそう?
Vueらしさが失われることを懸念 takepepe.icon
今からできるVueらしいTSX実装
@vue/composition-apiを試す
冒険しないならvue-tsx-support
kazupon.icon
React書いてる人にはやりやすそう
SFCとは…
potato4d.icon
Alt-Reactみたいな使い方ができるのではないか?
デザイナーとの付き合い方
Scoped CSS 周りの倒し方は公式のオピニオンが出揃ってなさそうな印象 potato4d.icon https://www.youtube.com/watch?v=ANtSWq-zI0s
takepepe.icon
templateの型解釈に興味ある・注力したい
kazupon.icon
それでいいんだっけ?を考えよう
potato4d.icon
現場を救いたい
コアのコードベースで救う気はあまりない
ライブラリ・プラグインに寄付・支援して相互ハッピーになりたい
Material Designんい準拠
propsやevent emit, slotが多い
スピード重視で採用
初期から最高のデザインはできなくともコンポーネントの雰囲気は揃えたい
実際の運用
Form
持つべき機能:入力、検証、送信
まとめたComponentを内製化した
子に使用を渡す
送信時に入力値を$emit
pros
挙動を共通化できる
慣れてない開発メンバーでも
cons
混みったものは作りづらい
Breadcrumbs
asyncDataで受け取る
Pagination
@clickしたときに$emitしたものをrouter.push
watchQuery["page"]
pros
Laravelとの相性がいい
cons
SEO管理の処理とアプリが密結合しがち
watchQuery["page"]忘れる被害が定期的に
前提
export, Import
pros
難しいことを考えなくていい
cons
ただのJSモジュールなので特別なことはできない
使い所
Mixin
pros
複数コンポーネントで同じような機能を提供したい場合など有効
グローバルな適用もできるので全コンポーネントで使いたい場合も対応可能
cons
使い方を誤るといちいちコンポーネントそのものが拡張される
勝手にメソッドが生えてるようにみえるので初見は困る
使い所
コンポーネントの機能として共通化したい場合
Plugins
pros
一箇所変更すればアプリケーション何処からでも参照できる
cons
部分適用できないので肥大化しがち
使い所
アプリケーション全体で使うような大規模な共通処理
Middleware
画面のレンダリング前に実行される機能を定義
routerで設定すれば全体
レイアウトやコンポーネントで設定すれば個別
実行順は router > layout > page
pros
認証など常時遷移時に実行させたいものを定義できる
cons
コンポーネントのライフサイクルが始まる前なのでコンポーネントのthisが使えない
使い所
いろんな画面に表示前に同じようにチェックしておきたい項目がある
Composition API
概要
Vue3から組み込まれる
Vue2の現時点でも公式ライブラリを使えば使える
Vue.jsが抱える型問題の大部分を解決するapi
参考
useCounter
code:sample-react.js
import { useState } from 'react'
const add = value => prev => prev + value
const useCounter = (initial = 0) => {
return {
count,
set,
inc: (number = 1) => set(add(number)),
dec: (number = 1) => set(add(-number)),
reset: () => set(initial),
}
}
export default useCounter
code:sample-vue.js
import { computed, reactive } from "@vue/composition-api";
export function useCounter(initial = 0) {
const state = reactive({ count: 0 });
return {
count: computed(() => state.count),
set: (count: number) => {
state.count = count
},
inc: () => {
state.count++;
},
dec: () => {
state.count--;
},
reset: () => {
state.count = initial
}
} as const;
}
code:sample.js
import {
reactive,
onMounted,
onUnmounted,
computed
} from "@vue/composition-api";
export function useMouse() {
const pos = reactive({ x: 0, y: 0 });
const update = (e: MouseEvent) => {
pos.x = e.pageX;
pos.y = e.pageY;
};
onMounted(() => {
window.addEventListener("mousemove", update);
});
onUnmounted(() => {
window.removeEventListener("mousemove", update);
});
return {
x: computed(() => pos.x),
y: computed(() => pos.y)
} as const;
}
mountされたらイベントをアタッチして、マウント解除されるタイミングで解除
x, yはsourceがマウスカーソルなので代入禁止の意味を込めてcomputed
code:sample-component.js
<template>
<div>
<h2>mouse pointer</h2>
<div>x: {{ x }}</div>
<div>y: {{ y }}</div>
<button @click="setDummyPos">setDummyPos</button>
</div>
</template>
<script lang="ts">
import { createComponent } from "@vue/composition-api";
import { useMouse } from "@/hooks/useMouse";
export default createComponent({
setup() {
const { x, y } = useMouse();
return {
x,
y,
};
}
});
</script>
再利用性
code:sample.js
import {
onBeforeMount,
onMounted,
onBeforeUnmount,
onUnmounted,
onActivated,
onBeforeUpdate,
onDeactivated,
onErrorCaptured,
onUpdated
} from "@vue/composition-api";
export function useLifeCycleLog() {
onBeforeMount(() => console.log("onBeforeMount"));
onMounted(() => console.log("onMounted"));
onBeforeUnmount(() => console.log("onBeforeUnmount"));
onUnmounted(() => console.log("onUnmounted"));
onActivated(() => console.log("onActivated"));
onBeforeUpdate(() => console.log("onBeforeUpdate"));
onDeactivated(() => console.log("onDeactivated"));
onErrorCaptured(() => console.log("onErrorCaptured"));
onUpdated(() => console.log("onUpdated"));
}
Mixin
Vuetifyのコードはmixinでコードの共通化と再利用を上手くやっています。 しかし、これは宣言的ではない為、使い方が直感的ではなく、読み解くのに体力が必要です。
composition apiの利点は独立したネームスペースと宣言的なプログラミングができるため、使う側のコードも読みやすく、ロジックがバラけない3点かと思います。
Class
Vuexの標準的なapiであるmapStateでmapしたものをclassの中等で参照すると型エラーがでる
Decoratorはあくまでも暗黙的に拡張してくれるだけで、標準的な型システムでは拡張されていることを認識できない
導入タイミング
現在まだrfc段階だが、この段階まで進めばもうほぼ仕様は変わらないらしい 多少多少関数名や使用感等が変わってもdry
そんなになければ追従コストもそこまでではないんじゃないか
なので、Vue Tsで型に困っているプロダクトにはもう組み込んでもいいかなと思います
留意点
composition apiはあくまでもVue.jsのリアクティブシステムの上に乗かっているapi
reactのhooksと同じ使用感ではない。かなりシンプルなApi
composition apiが出たからと言って必ず使わないといけないわけではない
あくまでも型を守ったりロジック再利用の開発したい際の有力な選択肢が1つ増えるだけ
ユーザー数1500万人のサービスにNuxtを導入して嬉しかったこと
導入について
問題
フロントとサーバサイドが密結合
サーバーサイドの保守性を重視
jQueryでのDOM操作が大変
UXデザインに力を入れている
ユーザビリティテストを実施して反映
導入で嬉しかったこと
サーバがAPIのみなので疎結合な開発に
ドキュメントが優しい、メンバーの経験がある
デザイナーとの連携で嬉しかったこと
コンポーネントを意識したデザイン
解釈と認識合わせが難しい
SketchのSymbol === Atomsという共通認識 バックエンドとの連携で嬉しかったこと
BEとの連携や情報共有に時間がかかる
UIが便利
嬉しいこと
ドキュメントの共有しやすい
YAMLやjsonでスキーマ記述ができる
チーム内連携
大規模なプロジェクト
Atomic Designの解釈違い
コンポーネントでのルールを設定
コードの安全性
TypeScriptの導入