Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁
-
Upload
yutaro-miyazaki -
Category
Engineering
-
view
1.523 -
download
0
Transcript of Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁
Vue.js Tokyo v‑meetup #5
秋
Q. 秋といえば?
A. 読書の秋 �
Q. Vue.js で作られた SPA SSR な
電子書籍 (マンガ) 配信サービスは?
A. マンガZERO
Nuxt 無しで作ってしまった
恨み辛み妬み
Vue.js Tokyo v‑meetup #5
Nuxt less SPA SSR で乗り越えるべきnの壁Nuxt less SPA SSR で乗り越えるべきnの壁
const n = 5;
構成構成
SPA of Vue.js + Vuex
SSR by Express
Device switching between PC/SP
Backend as API by Go
vue‑hackernews‑2.0 頼み
1の壁: メタタグ1の壁: メタタグ
SSR 対応
Fetch の結果から動的に扱えること
手間がかからないこと
declandewet/vue‑metadeclandewet/vue‑meta
メタタグ吐く
SSR 対応
公式ドキュメントにも載ってる
export default { metaInfo() { let metaBase = { title: this.title, meta: [ { vmid: 'og:title', property: 'og:title', content: this.title }, { vmid: 'description', name: 'description', content: this.description }, ... ], link: [ { vmid: 'canonical', rel: 'canonical', href: this.canonical } ] };
if (this.prev) { metaBase.link.push({ rel: 'prev', href: 'https://manga-zero.coroco3.com' + this.prev }); }
// server.js .on('beforeStart', () => { const { title, link, meta } = context.meta.inject(); context.head = (context.head || '') + title.text() + meta.text() + link})
Nuxt にも入ってる �
2の壁: Google Analytics2の壁: Google Analytics
非 SPA の PV と同じになること
手間がかからないこと
MatteoGabriele/vue‑analyticsMatteoGabriele/vue‑analytics
SSR 対応
vue‑router と同期し自動で PV を送ってくれる
// router.js Vue.use(Router); Vue.use(Meta);
if (process.env.VUE_ENV === 'client') { Vue.use(VueAnalytics, { id: 'UA-xxxxxxxx-xx', router, ready() { const ga = window.ga || {}; ga('require', 'linkid'); ga('set', 'dimension1', val); } }); }
export default router;
イベントとか送るのもちょっと楽
this.$ga.event('グローバル', 'メニュータップ', '', 0, { nonInteraction: true });
App analytics を使うなら ScreamZ/vue‑analytics
あるのかよ �
3の壁: デバイス切り替え3の壁: デバイス切り替え
同一 Express から配信したい
Store とか共通で使いたい
手間がかからないこと
デバイス切り替ェ �
Webpack の MultiCompile でいける...
デバイス切り替ェ �
// webpack.config.server.js { ... plugin: [ ... new VueSSRServerPlugin({ filename: 'sp/vue-ssr-server-bundle.json' }) ] ... }, { ... plugins: [ ... new VueSSRServerPlugin({ filename: 'pc/vue-ssr-server-bundle.json' }) ] ... }
デバイス切り替ェ �
const template = { pc: fs.readFileSync(resolve('./src/app/templates/pc.html'), 'utf-8'), sp: fs.readFileSync(resolve('./src/app/templates/sp.html'), 'utf-8') };
デバイス切り替ェ �
// srever.js if (!isDevelop) { const bundle = { sp: require('./dist/sp/vue-ssr-server-bundle.json'), pc: require('./dist/pc/vue-ssr-server-bundle.json') }; const clientManifest = { sp: require('./dist/sp/vue-ssr-client-manifest.json'), pc: require('./dist/pc/vue-ssr-client-manifest.json') }; renderer = { sp: createRenderer(bundle.sp, { clientManifest: clientManifest.sp }, pc: createRenderer(bundle.pc, { clientManifest: clientManifest.pc }, }; } else { readyPromise = setupDevServer(app, (bundle, options) => { renderer = { sp: createRenderer(bundle.sp, options, template.sp), pc: createRenderer(bundle.pc, options, template.pc) }; }); }
webpack.config.client.js も同様
dev‑middleware と hot‑middleware も同様
デバイス切り替ェ �
// server.js function render(req, res) { ... const device = (req.useragent.isMobile) ? 'sp' : 'pc'; const context = { url: req.url, device };
renderer[device].renderToStream(context) ... }
流石に無いよな... � ?
4の壁: 他民族4の壁: 他民族
国内ではまだ若干弱め
1.0 の時のイケてない印象
手間がかからないこと
☝ � Angular ぽく書けるよ �☝
vue‑class‑componentvue‑class‑component
TS でいい感じに書ける
ES でも使える
Angular ぽく書けるイメージ
import Vue from 'vue'; import Component from 'vue-class-component';
@Component({ name: 'component-hoge', metaInfo: { ... }, proprs: { ... } }) export default class ComponentHoge extends Vue { // initial data msg = 123;
// lifecycle hook mounted () { this.greet(); }
// computed get computedMsg () { return 'computed ' + this.msg; }
// method greet () { alert('greeting: ' + this.msg); } }
他民族においても他民族においても
直帰率の低下 ⬆⬆⬆
リテンションの底上げ ⬆⬆⬆
布教にも貢献 ���
親クラス作って継承したり
vue‑class‑component/createDecoratorvue‑class‑component/createDecorator
デコレータを作れる
例えば PC/SP 間で
殆ど同じだけど微妙に異なる (Props とか)
コンポーネントを沢山作る時
同じ: Template, Style, Props
違う: Method, Computed
import Vue from 'vue'; import createDecorator from 'vue-class-component';
function ComponentTopDefault() { return createDecorator((options) => { options = object.assign({}, { name: 'view-top', props: { hoge: { ... } } }, options); }); }
@Component() @ComponentTopDefault() export default class ViewTop extends Vue {}
metaInfo とか proprs とか
Mixin はちょっと違うなってものを
createDecrator で定義した
v5.0.2 でこの使い方はできなくなった
次の日には PR できてた
���
Nuxt 関係ない �
5の壁: HTTP Status5の壁: HTTP Status
状況に合わせた HTTP ステータスが打てる
404 デザインが Vue でレンダリングできる
手間がかからない
vue‑hackernews‑2.0 の 404 は
さすがにこれはない �
のでやってみた �
Router にマッチしなかった時Router にマッチしなかった時
/unkounko
Router にマッチしなかった時Router にマッチしなかった時
/unkounko
// router [ ... { path: '*', name: 'not-found', component: notFound } ]
// server.js .once('data', () => { if (context.state.route.name === 'not-found') res.status(404); })
API のステータスからAPI のステータスから
/product/999999
// store/action.js export const FETCH_ITEMS = ({ commit }, { path, key, type }) => { return fetchItem(path, key).then((result) => { if (result.status === 200) { ... } else if (result.mainQuery) { /* ↑ メインクエリに値する API のレスポンスが200 じゃない時 ↑ */ /* ↓ state に error コードをセットする ↓ */ commit(types.SET_STATUS, { key: 'error', value: result.status }); } else { ... } }).catch((error) => { console.error('catch FETCH_ITEMS', error); }); };
API のステータスからAPI のステータスから// server.js .once('data', () => { const termState = (context.state.error && context.state.error !== 0);
if (context.state.error !== 0) { res.status(context.state.error); } })
Nuxt だと
でいいらしい �
async fetch({ store, route, app, error }) { let url = `/api/${route.params.id}` let data = await app.$axios.$get(url) if (data.items.length === 0) { // there's no data this should be a 404 // No! there is no Content so throw `204 No Content` response: // https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Succes error({statusCode: 204, message: "The server successfully processed t } store.commit('item', data.Items[0]) }
結論結論
色々頑張ったけど...
もしかして Nuxt 使えば楽なの �?
最後に最後に
お前誰?
Yutaro Miyazaki (@vwxyutarooo)Yutaro Miyazaki (@vwxyutarooo)
ニート ↓
フリーの Web 屋 ↓
アプリ屋のフロントエンド
Dvorak + Vim に悩んでいる
ありがとうございました �ありがとうございました �