フロントエンド初心者がVueで作ったブログをNuxtのSSGで作り直した時につまずいたこと
概要
業務で触れる技術はバックエンド関連が主で、フロントエンドを関連の技術に触れることが少ないのですが、勉強を兼ねてVue.jsとContentfulで作成したブログをSPAで、Netlifyにホスティングしていました。
その後、パフォーマンスの向上+OGPの設定を目的として、Nuxt.jsのSSG機能を使って書き換えてみました。
リンク
リプレイス後
使用技術は以下です。
Nuxt.js or Next.js + Contenful + Netlify or Vercelの構成でブログを作成する記事はたくさんあるので、それらを参考にしてます。
リプレイス前
リプレイス時のつまづき
リプレイスする際に、いくつかつまづきがありました。その内容と解決策を羅列します。
もっと別のいいやり方があれば、コメントしていただけると嬉しいです><
ページネーションについて
静的ページの場合、ページネーションをどのように実装するかという問題が発生します。
他の記事をみると以下のように実装しているものが多く、参考にさせていただきました。
SSGでページネーションを作成する場合は、SSRと違って/page/1、/page/2のようにして、各ページ毎にコンテンツを取得するのがベターです。
記事の件数が少ない場合、記事の一覧情報を全件HTMLにセットしておいて、クエリの指定で表示/非表示を制御する方法もあるようです。
ちなみにページネーションコンポーネントの実装は、
vuetifyのv-paginationコンポーネントを元に作成し、数字のボタンが押されて切り替わったら、${this.base_path}/${new_page}
に遷移する、というようにしています。
<template>
<v-container>
<ul class="pagenation">
<li>
<nuxt-link :to="getTargetRoute(current_page-1)" :class="{'is-disabled':current_page-1<1 }" >
<button class="page-btn" ><</button>
</nuxt-link>
</li>
<li v-for="page in last_page" :key="page">
<nuxt-link :to="getTargetRoute(page)">
<button class="page-btn" :class="{'selected':page==current_page }">{{page}} </button>
</nuxt-link>
</li>
<li>
<nuxt-link :to="getTargetRoute(current_page+1)" :class="{'is-disabled':current_page+1>last_page }">
<button class="page-btn">></button>
</nuxt-link>
</li>
</ul>
</v-container>
</template>
<script>
export default {
props:{
current_page: {
type: Number,
required: true
},
last_page: {
type: Number,
required: true
},
base_path: {
type: String,
required: true
},
},
methods:{
getTargetRoute(page){
// pageが不正だったら空文字を返す。現在のパスを指定
if(page<1 || page>this.last_page) return "";
if(page == 1){
return `${this.base_path}`;
} else {
return `${this.base_path}/${page}`;
}
},
},
}
</script>
https://github.com/shira79/nuxt-blog/blob/main/components/Pagination.vue
generateしたページをどうやって確認するか
npm run generate
で生成したページをどうやって確認するのがいいんだろうと思ってました。
初期は/dist下
のhtmlファイルをブラウザで表示してみるというIQ低めの方法でやってましたが、流石になんとかせねばと思って調べました。
現在はnuxt serve
というコマンドを使っています。
上記を知らなかった時は少し前は、http-serverというパッケージ使って確認していました。
markdown関連のライブラリ選定
過去Vueで作っていたときに、markdownのパースにはmarked.jsを使っていました。
実装の途中で見出しの機能を追加したいと考えるようになりました。その場合、markdown-it
というライブラリであれば、楽に実装できることがわかったため、切り替えました。
こちらの記事を参考にしました。
markdown関連では、結果的に以下のライブラリにお世話になっております。
- @nuxtjs/markdownit :本体
- markdown-it-table-of-contents : 見出し作成
- markdown-it-anchor:見出しに移動
- highlight.js:コードのハイライト
nuxt.config.js
markdownit: {
breaks: true,
use: [
['markdown-it-table-of-contents', {
includeLevel: [2, 3],
}],
['markdown-it-anchor'],
],
highlight: (str, lang) => {
const hljs = require('highlight.js');
return '<pre class="hljs"><code>' + hljs.highlight(lang, str).value + '</code></pre>';
},
},
asyncDataはpageコンポーネントでしか使えない
Twitter、GithHubといったソーシャルリンクはContentfulからデータを取得しています。
複数箇所で使っているので、VueではSocials.vue
というコンポーネントを作り、その内部からapiを叩いていました。
しかし、NuxtのSSGで使用するasyncDataはpageコンポーネントからしか使えません。
このフックはページレベルのコンポーネントのためだけに使うことができます。
各pageコンポーネントでデータ取得して、取得したデータをSocials.vue
に渡すという実装に変えて対応しました。
TwitterでOGPが表示されない
静的ページに切り替えるにあたって、同時にOGPを設定したいと思いましたが、TwitterのOGPがうまくいかずハマりました。
twitter:card
はちゃんとhtmlのheadに記載しているのになぜ??と困っていましたが、デバックの手段はしっかり用意されていて、以下を使用すればすぐ原因が特定できます。
やってみたところ、og:title
が不正だとと言われました。
titleがあれば十分なのかなと勝手に思い、追記しておりませんでしたが、og:title
も必須なようです。
404ページ
何も設定しないと、Nuxtで用意した404ページではなく、Netlify自体の404ページが表示されてしまいました。
nuxt.config.js
のgenerateプロパティでfallbackオプションを設定することで、不明なルートもNuxtを介すようになります。つまりエラーページを表示できます。
フォールバックとは、 情報通信の世界では「(障害などに起因する)代替手段への切り替え」を意味します。
終わりに
もっと別のいいやり方があれば、コメントしていただけると嬉しいです><
Discussion