nuxt なしで vue app 作る時に乗り越えるべき5つの壁
TRANSCRIPT
![Page 1: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/1.jpg)
Vue.js Tokyo v‑meetup #5
![Page 2: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/2.jpg)
秋
![Page 3: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/3.jpg)
Q. 秋といえば?
![Page 4: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/4.jpg)
A. 読書の秋 �
![Page 5: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/5.jpg)
Q. Vue.js で作られた SPA SSR な
電子書籍 (マンガ) 配信サービスは?
![Page 6: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/6.jpg)
A. マンガZERO
![Page 7: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/7.jpg)
Nuxt 無しで作ってしまった
恨み辛み妬み
![Page 8: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/8.jpg)
Vue.js Tokyo v‑meetup #5
Nuxt less SPA SSR で乗り越えるべきnの壁Nuxt less SPA SSR で乗り越えるべきnの壁
![Page 9: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/9.jpg)
const n = 5;
![Page 10: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/10.jpg)
構成構成
SPA of Vue.js + Vuex
SSR by Express
Device switching between PC/SP
Backend as API by Go
![Page 11: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/11.jpg)
vue‑hackernews‑2.0 頼み
![Page 12: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/12.jpg)
1の壁: メタタグ1の壁: メタタグ
SSR 対応
Fetch の結果から動的に扱えること
手間がかからないこと
![Page 13: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/13.jpg)
declandewet/vue‑metadeclandewet/vue‑meta
メタタグ吐く
SSR 対応
公式ドキュメントにも載ってる
![Page 14: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/14.jpg)
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 }); }
![Page 15: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/15.jpg)
// server.js .on('beforeStart', () => { const { title, link, meta } = context.meta.inject(); context.head = (context.head || '') + title.text() + meta.text() + link})
![Page 16: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/16.jpg)
Nuxt にも入ってる �
![Page 17: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/17.jpg)
2の壁: Google Analytics2の壁: Google Analytics
非 SPA の PV と同じになること
手間がかからないこと
![Page 18: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/18.jpg)
MatteoGabriele/vue‑analyticsMatteoGabriele/vue‑analytics
SSR 対応
vue‑router と同期し自動で PV を送ってくれる
![Page 19: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/19.jpg)
// 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;
![Page 20: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/20.jpg)
イベントとか送るのもちょっと楽
this.$ga.event('グローバル', 'メニュータップ', '', 0, { nonInteraction: true });
![Page 22: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/22.jpg)
あるのかよ �
![Page 23: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/23.jpg)
3の壁: デバイス切り替え3の壁: デバイス切り替え
同一 Express から配信したい
Store とか共通で使いたい
手間がかからないこと
デバイス切り替ェ �
![Page 24: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/24.jpg)
Webpack の MultiCompile でいける...
![Page 25: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/25.jpg)
デバイス切り替ェ �
// webpack.config.server.js { ... plugin: [ ... new VueSSRServerPlugin({ filename: 'sp/vue-ssr-server-bundle.json' }) ] ... }, { ... plugins: [ ... new VueSSRServerPlugin({ filename: 'pc/vue-ssr-server-bundle.json' }) ] ... }
![Page 26: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/26.jpg)
デバイス切り替ェ �
const template = { pc: fs.readFileSync(resolve('./src/app/templates/pc.html'), 'utf-8'), sp: fs.readFileSync(resolve('./src/app/templates/sp.html'), 'utf-8') };
![Page 27: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/27.jpg)
デバイス切り替ェ �
// 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) }; }); }
![Page 28: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/28.jpg)
webpack.config.client.js も同様
dev‑middleware と hot‑middleware も同様
![Page 29: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/29.jpg)
デバイス切り替ェ �
// server.js function render(req, res) { ... const device = (req.useragent.isMobile) ? 'sp' : 'pc'; const context = { url: req.url, device };
renderer[device].renderToStream(context) ... }
![Page 30: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/30.jpg)
流石に無いよな... � ?
![Page 31: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/31.jpg)
4の壁: 他民族4の壁: 他民族
国内ではまだ若干弱め
1.0 の時のイケてない印象
手間がかからないこと
![Page 32: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/32.jpg)
☝ � Angular ぽく書けるよ �☝
![Page 33: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/33.jpg)
vue‑class‑componentvue‑class‑component
TS でいい感じに書ける
ES でも使える
Angular ぽく書けるイメージ
![Page 34: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/34.jpg)
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); } }
![Page 35: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/35.jpg)
他民族においても他民族においても
直帰率の低下 ⬆⬆⬆
リテンションの底上げ ⬆⬆⬆
布教にも貢献 ���
![Page 36: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/36.jpg)
親クラス作って継承したり
![Page 37: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/37.jpg)
vue‑class‑component/createDecoratorvue‑class‑component/createDecorator
デコレータを作れる
![Page 38: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/38.jpg)
例えば PC/SP 間で
殆ど同じだけど微妙に異なる (Props とか)
コンポーネントを沢山作る時
![Page 39: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/39.jpg)
同じ: Template, Style, Props
違う: Method, Computed
![Page 40: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/40.jpg)
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 {}
![Page 41: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/41.jpg)
metaInfo とか proprs とか
Mixin はちょっと違うなってものを
createDecrator で定義した
![Page 42: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/42.jpg)
v5.0.2 でこの使い方はできなくなった
![Page 43: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/43.jpg)
次の日には PR できてた
![Page 44: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/44.jpg)
���
![Page 45: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/45.jpg)
Nuxt 関係ない �
![Page 46: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/46.jpg)
5の壁: HTTP Status5の壁: HTTP Status
状況に合わせた HTTP ステータスが打てる
404 デザインが Vue でレンダリングできる
手間がかからない
![Page 47: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/47.jpg)
vue‑hackernews‑2.0 の 404 は
![Page 48: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/48.jpg)
![Page 49: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/49.jpg)
さすがにこれはない �
![Page 50: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/50.jpg)
のでやってみた �
![Page 51: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/51.jpg)
Router にマッチしなかった時Router にマッチしなかった時
/unkounko
![Page 52: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/52.jpg)
![Page 53: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/53.jpg)
Router にマッチしなかった時Router にマッチしなかった時
/unkounko
// router [ ... { path: '*', name: 'not-found', component: notFound } ]
// server.js .once('data', () => { if (context.state.route.name === 'not-found') res.status(404); })
![Page 54: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/54.jpg)
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); }); };
![Page 55: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/55.jpg)
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); } })
![Page 56: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/56.jpg)
Nuxt だと
![Page 57: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/57.jpg)
でいいらしい �
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]) }
![Page 58: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/58.jpg)
結論結論
色々頑張ったけど...
もしかして Nuxt 使えば楽なの �?
![Page 59: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/59.jpg)
最後に最後に
![Page 60: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/60.jpg)
お前誰?
![Page 61: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/61.jpg)
Yutaro Miyazaki (@vwxyutarooo)Yutaro Miyazaki (@vwxyutarooo)
ニート ↓
フリーの Web 屋 ↓
アプリ屋のフロントエンド
Dvorak + Vim に悩んでいる
![Page 62: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/62.jpg)
![Page 63: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/63.jpg)
![Page 64: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/64.jpg)
![Page 65: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/65.jpg)
![Page 66: Nuxt なしで Vue App 作る時に乗り越えるべき5つの壁](https://reader034.vdocuments.net/reader034/viewer/2022052117/5a6478a77f8b9a40568b45f9/html5/thumbnails/66.jpg)
ありがとうございました �ありがとうございました �