Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁

Post on 21-Jan-2018

1.523 views 0 download

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 に悩んでいる

ありがとうございました �ありがとうございました �