技術・Web 3年前

Nuxt.js&Firebase で WordPressブログをフルリニューアルしたまとめ

2020年2月に、WordPressブログ(このサイト)をFirebaseでフルリニューアルしました。  現在このサイトはFirestoreのデータを取得してFirebase Hostingから配信されています。  今年2月よりFirebaseでの運用を開始し、3ヶ月ほどかけて少しずつ調整を加えつつ、ようやく費用感などの実態を掴むことができたので、記事としてまとめることにしました。 ※FirebaseやNuxt.jsのことをある程度わかっている方に向けて書いていますのでご了承ください。  サイト更新からデプロイ、表示までの全体像はこのようになっています。  (※細かい処理の流れ・役割は後で詳しく説明します) スライド4  見ての通りFirebaseフル活用です。ここまで全部使っているサイトは珍しいのではと思います。  よく、「WP REST API + Nuxt.jsでリニューアルしました」とか、「WordPressを捨ててContentful + Netlifyに移行しました」という記事はそれなりに目にしますが、そのどちらでもなく、  「WordPress上にある記事データが、常にFirestoreに同期され、そのデータを元にNuxt.jsで生成された静的サイトがFirebase Hostingから配信される」という形を取っています。  一見すると無駄の多い構成に見えますが、これによって

    Firebaseの豊富な機能と、最適化されたクラウドサーバー Vue.js / Nuxt.jsによるUX向上と、PWA・静的化などの最新技術への対応しやすさ WordPressの優秀な管理画面・データベース・プラグイン
 というそれぞれのいいとこどりができています。  実運用を開始して2ヶ月半ほど経過しましたが、特に大きな問題もなく、多くの恩恵を受けられています。  典型的なWordPressブログ(約3500ページ)を、URLや機能・使用感などを一切変えることなくFirestoreに丸ごと移行して静的化運用するというのは、あんまり前例がないと思うので、参考になれば良いなと思います。

技術選定の理由

WordPressからFirebaseへの移行

 このブログは2016年から今年1月までWordPress(ロリポップ!レンタルサーバー)で運用していました。そこからの脱却を考え始めたのが1年前。当時考えていた理由は下記の4つでした。
サイトの速度が明らかに遅いため、Lighthouseなどのスコアが上がらないのがSEO・利便性の両面で不利。jQueryやPHP・サーバー応答速度といったボトルネックは、WordPressを使っている限り解消することができない ②NetlifyやFirebaseなどの無料で使えるサービスが充実してきている中、レンタルサーバーを使っているのはコスパも悪い ③今後のことを考えると、記事データはMySQLではなくJSON形式の方がバックアップしやすく安全 ④Vue.js、CSSフレームワーク、PWA・AMPなどといった新しい技術とWordPressの相性が致命的に悪すぎる WordPressからFirebase+Nuxt.jsのHeadless CMSに完全移行するまでの記録 ①導入・技術選定 | Our Story's Diary
 最終的には、記事データはWP依存のままだし費用も下がっていないので、当初の想定とは若干ズレていますが、  とにかくメインの理由は、速度改善のボトルネックになっていたことと、Vue.jsを使いたい(=PHPを使いたくない)という2点。  以前は会社でよくWordPressを使っていたのですが、昨年6月に転職し、ほとんどNuxt.jsしか書かなくなったため、スキルアップとしても脱却したいという気持ちがますます強くなりました。

なぜWordPressを使い続けるのか

 サーバーレス・静的サイト化・Firestoreに魅了されると「WordPressは要らない!オワコン!」という短絡的な結論に辿り着きやすいです。私も最初は「WordPressをどうやって捨てるか」という方向で考えていました。  しかし、WordPressからの移行先として考えると、NoSQLである現状のFirestoreには足りない機能も多いです。  連番機能、全文検索、カテゴリー・タグ・月別アーカイブの件数カウント。この記事で使っている目次やなどもWordPressプラグインで実現されていますし、管理画面もCMSとしては貧弱。私が数年前から愛用しているOpen Live Writerのようなエディターソフトとの連携も厳しいです。  もちろん、個々の機能を一つずつ見ていけばCloud FunctionsやFirestoreクエリハック、Algoriaなどの外部サービス連携を使って実装する方法はあるのでしょうが、  それらを全部やってくれているWordPressというシステムが既にあって動いているのに、わざわざ自分で作り直す理由はどこにあるのでしょうか?  考えれば考えるほど単なる車輪の再発明にしかなっていないことに気づき、WordPressでデータが更新されるたびにFirestoreにPUTするだけで十分だと考えるようになりました。  もちろん、将来的にはWordPressへの依存度を段階的に下げていくのが理想です。特に、画像・コメント・検索といった、フロントからWordPressにアクセスしている部分は、セキュリティ観点からもなくしていきたいですし、最終的に管理画面まで不要になれば  ただ、セキュリティと表示速度というデメリットを回避した上であれば、¥270/月で使える高機能エディター&データ管理ツール&画像ストレージとして、WordPressは十分に有用であると思います。

Nuxt.jsを使う理由

 自分がVue.js / Nuxt.jsをずっと使っていて好きだから、ということに尽きるのですが。  Nuxtは静的サイト化の機能が組み込まれているためFirebase Hostingとの相性が良いこと、Google Adsense、Google Analytics、PWA Moduleなどの豊富なプラグインが公式に提供されていることなどから、WordPressの機能を維持したまま移行する際にはベストな選択肢なのではないかと思います。  また、この記事の主題ではありませんが、Vueのv-forv-ifでテンプレートに直接ロジックを書いていく感覚はPHPに近いところがあるので、コードを移植しやすいというメリットがあります。  例えば、WordPressのトップページで記事一覧とサムネイルを表示する場合、 <?phpif (have_posts()) : while (have_posts()) : the_post();?> <article id="post-<?php the_ID(); ?>" <?php post_class('box ...

comment  0
favorite  0
技術・Web 3年前

Firestoreのデータからブログのサイドバーを表示する

WordPressブログをNuxt+Firebaseに移行するシリーズ。  前回の記事で、記事一覧および記事本文を表示できるようになりましたが、  サイドバー、関連記事、コメントフォームなどの共通パーツがまだです。

サイドバー

 このブログの場合、サイドバーに必要な機能は以下の通り。
    最新記事 最新コメント カテゴリー一覧 タグ一覧 アーカイブ カレンダー 人気の記事 広告
 意外と多くてしんどいのですが、そもそもこのあたりの必要データ構造は↓の記事で整えたので、  この記事ではあんまり書くことがなさそうです。
WordPressのカテゴリー・タグなどのデータをFirestoreに同期する | Our Story's Diary  サイドバーを共通パーツ化することで、ページ遷移時に再読み込みしなくて良くなります。  これをいい感じに差分更新してくれるのがNuxt化の最大のメリットであり、WordPressだとajaxとかで無理やり遷移させることになりますが、どこを書き換えてどこを残すかを人間の頭で管理するのは不可能です

サイドバー

最新記事

 これはトップページのメインループと同じ関数なので割愛。limitを5にするくらい。

最新コメント

 これもWordPressからWP REST API経由で取るので割愛。

カテゴリー一覧

 カテゴリー一覧の取得クエリは async categories() { const query = db.collection('categories').orderBy('name') // タグはtags const data = await query.get().then(querySnapshot => { return querySnapshot.docs.map(doc => doc.data()) }) return data }  実際に出力する際は <ul class="menu-list"> <li v-for="category in categories" :key="category.id"> <n-link :to="`/category/${category.slug}`"> {{ category.name }} </n-link> </li> </ul>  で前回作ったカテゴリーページにリンクできます。  ちなみにこのブログでは、サイドバーにはアスタリスクから始まるカテゴリーのみを表示するようにしています。(最近使っていないカテゴリーが無駄に多いので) const data = await db .collection('categories') .orderBy('name') .startAt('*') .endAt('*' + '\uf8ff') .get() .then(querySnapshot => { return querySnapshot.docs.map(doc => doc.data()) })  Cloud FirestoreでLike検索する方法|shogo yamada|note の記事を

タグ一覧

 タグは上位20件をcountで並べます。 const query = db .collection('tags') .orderBy('count', 'desc') .limit(20) const ...

comment  0
favorite  1
技術・Web 3年前

Firestoreのデータからブログを表示する

WordPressブログをNuxt+Firebaseに移行するシリーズ。  WordPressに存在する記事データの必要な情報は全てFirestoreに同期させたので、次はいよいよ表示。  現在のブログ表示で行っていることを、Firestoreからデータを取得するクエリに置き換えていきます。  前回も書きましたが、そもそもブログごとに必要・不必要な部分がたくさんあるので難しいんですよね。  ルーティング自体は書きますが、JSONデータをどう扱うかは完全に個々のブログのデザインの話になるので。

初期設定

 Firebaseの初期設定やNuxtとの連携の話はもういろいろなところにあると思うのでざっくり。
    yarn add firebase する ダッシュボードから「アプリを追加」でWEBアプリを追加 表示されるJS情報をplugin/firebase.ts ファイルに入れてnuxtで読み込む
import firebase from 'firebase/app'import 'firebase/firestore'if (!firebase.apps.length) { const config = { apiKey: process.env.firebaseApiKey, authDomain: process.env.firebaseAuthDomain, databaseURL: process.env.firebaseDatabaseURL, projectId: process.env.firebaseProjectId, storageBucket: process.env.firebaseStorageBucket, messagingSenderId: process.env.firebaseMessagingSenderId } firebase.initializeApp(config)}export default firebase  ここでは@nuxt/dotenvを使って環境変数化していますが、面倒な方は表示されるIDなどを直接書いてもそんなに問題はないと思います。(そもそもCDNでも使える設計なので公開情報のはず)  加えて、今後GitHubからFirebase Hostingへの自動デプロイを行うためには.env をGitHubに上げる必要も出てくるので、あまり意味がなくなる可能性もあります。気休めみたいなものです。  ストアから情報を呼び出す際は、このプラグインで初期化されたfirebaseを呼び出すので、 import firebase from '~/plugins/firebase'const db = firebase.firestore()  みたいになります。  このDBに対しての具体的な操作は、Firebaseのドキュメントを見ればわかります。
Cloud Firestore を使ってみる | Firebase  これ以降はdbの定義などは省いて書いていきます。

コンテンツ

 「WordPressサイトからURLを変えることなく移行」するためには、各アーカイブページを表示する必要があります。

ルーティング

 WordPressに存在する主要なページは以下の通り。
ページ名URL
トップページ(記事一覧)/
記事/archives/{post_id}
カテゴリーアーカイブ/category/{category_slug}
タグアーカイブ/tag/{tag_slug}
年別・月別・日別アーカイブ/archives/date/{year}/{month}/{day}
固定ページ/{page_slug}
 実はページの種類としてはこのくらいしかありません。  NuxtのPagesのルーティングを使うとこうなります。 image-20191110001933705  年別/月別/日別だけ面倒ですが、WordPressのルーティングを再現するのは意外と簡単なのです。  というわけで作るページはこんな感じです。意外と少ないですね。

トップページ

 まずメインの記事部分はこんな感じで取得してきます。 import firebase from '~/plugins/firebase'const db = firebase.firestore()export const state = () => ({ posts: []})export const mutations = { SET_POSTS: (state, ...

comment  0
favorite  1
技術・Web 3年前

WordPressのカテゴリー・タグなどのデータをFirestoreに同期する

WordPressのカテゴリー・タグなどのデータをFirestoreに同期する  WordPressブログをNuxt+Firebaseに移行するシリーズ。  前回、記事を全て同期させたので、次は表示……と思っていろいろ作っていたのですが、  作業の中でカテゴリー・タグ・コメントのコレクションが必要となり、  その手順を行った後にFirebaseの表示する方が流れとしてわかりやすいと思ったので、記事の順番を入れ替えることにしました。  なので現在、第3回「記事表示・ルーティング編」と第4回「サイドバー編」がほとんど書きあがっています。

記事の同期

 基本的には前回書いた通りですが、いろいろと必要なパラメータが増えたので完成版を丸ごと載せます。 function save_post_to_firestore($post) { function get_first_image($post) { if (has_post_thumbnail()) { return get_the_post_thumbnail_url($post->ID, 'card-thumb'); } else if (preg_match('/<img.*?src=(["\'])(.+?)\1.*?>/i', $post->post_content, $imgurl)) { return $imgurl[2]; } else { return '/shared/images/noimage.png'; } }; $url = "https://**********.cloudfunctions.net/addPost"; $categories = get_the_category($post->ID); $tags = get_the_tags($post->ID); $previous_post = get_previous_post(); $next_post = get_next_post(); $data = [ // base 'id' => $post->ID, 'author' => $post->post_author, 'slug' => $post->post_name, 'title' => $post->post_title, 'content' => array( 'text' => strip_tags($post->post_content), 'rendered' => $post->post_content, ), 'date' => $post->post_date, 'modified' => $post->post_modified, // taxonomy 'categories' => $categories, 'category_slugs' => array_map('convert_tax_to_slug', $categories), 'tags' => $tags, 'tag_slugs' => array_map('convert_tax_to_slug', $tags), // meta 'post_type' => $post->post_type, 'post_status' => $post->post_status, 'ping_status' => ...

comment  0
favorite  2
技術・Web 3年前

WordPressの記事データをFirestoreに同期する

WordPressブログをNuxt+Firebaseに移行するシリーズ。概要は↓  今回は最初のステップとして、まずはWordPressの記事をFirestoreに同期します。  流れとしては ①Firebaseのプロジェクトを作ったりいろいろする ②Cloud FunctionsにaddPost関数を作成 ③WordPressの投稿時/更新時にaddPostにリクエストを送る ④現時点で存在する記事を全て同期する  簡単ですね! たぶん思っているよりも簡単です。  以下にやり方を載せます。

Firebase側のセットアップ・コンソールログイン・その他いろいろ

 いろいろなところで説明されてると思うので割愛。公式ドキュメント見てください。
Firebase を JavaScript プロジェクトに追加する | Firebase  ちなみに、この記事の段階では使うのはfunctionsをデプロイするだけなので、ステップ3のFirebase SDK追加も不要ですし、Firebase側で何かすることはありません。  ただ、Firebaseの使い方としてはそれなりにトリッキーなので、一度Firebaseで真っ当にチャットとかWebアプリ作ってからの方が良い気もします。

Cloud Functions

addPost関数の作成

とりあえずfirebase initしてFirestore functionsを含めてセットアップします。 === Functions SetupA functions directory will be created in your project with a Node.jspackage pre-configured. Functions can be deployed with firebase deploy.? What language would you like to use to write Cloud Functions? TypeScript? Do you want to use TSLint to catch probable bugs and enforce style? Yes  TypeScriptを使うかだけ聞かれます。とりあえずTypeScriptを使うことにします。 Cloud Functions に TypeScript を使用する | Firebase スタートガイド: 最初の関数を作成してデプロイする | Firebase  この2ページを見ればだいたいの手順はわかると思うのですが、  注意点としては公式チュートリアルはRealtime Databaseのままになっているということです。  今からFirebaseのデータベースを使うならFirestoreを使いましょう。 import * as functions from 'firebase-functions';const admin = require('firebase-admin');admin.initializeApp();const db = admin.firestore();// ...

comment  0
favorite  2
技術・Web 3年前

新・WordPressブログをNuxt+Firebaseに完全移行するプロジェクト

半年ほど前に、こんな記事を書きました。  簡単にまとめると、  ・WordPressの重さや脆弱性、jQuery依存などの問題から脱却したい  ・ Vue/Nuxt、PWA・AMPなどの技術を取り入れづらい  などの理由から、今使っているこの  ・記事数5000件超という大規模なWordPressブログを ・記事データを1つも落とすことなく ・URLも変えることなく ・月額費用が一気に高くなったりもせずに  Firestoreに完全移行したい!という計画です。  で、途中まで進めていたものの、  そこから転職して忙しかったり意義を考えたり、あといろんな技術上の課題に突き当たってすっかり止まっていたのですが、  その会社の方でFirebaseを使ったプロジェクトに携わって、Firebaseの使い方を理解し始めたこと、ある程度技術的なイメージが湧いたことから、  このFirebase移行プロジェクトを進めることにしました。  ただ、この半年の間に、Firebase自体も進化しましたし、何よりも自分の知識も増えました。  4月時点に考えていた構成には、実装上の問題であったり非効率な部分が含まれていて、途中まで進めていたエディター画面なども正直今見ると別に不要だったな……という。  なので、改めてこのプロジェクトに関するロードマップを引き直すことにしました。  ……本当は別にこれを記事にする必要はなかったのですが、  「wordpress firestore」などのキーワードで検索するとまあまあ上位にこのブログが出てしまうという問題に最近気づきまして、ちゃんとやらないと申し訳ないなと……。  というわけで、以下が新しいロードマップです。

ロードマップ

フェーズ1:Nuxt + WP REST API + GCPでブログを表示する

 フロントのみをNuxt化し、WordPressに備わっているWP REST APIで必要なデータを取ってくる、ということです。  OGPなどの理由からSPAではなくSSRします。後々Firebaseと連携することも考慮して、Node.jsの無料枠があるGCPを選びましょう。  実はこれについては年始に途中まで進めていたものがあるので、ほぼ完了しています。  正直やり方は覚えてないので、SSRで表示するところまでの記事は詳細には書きません、ごめんなさい。
Nuxt.js v2とGAE/SE Node.jsでSPA×SSR×PWA×サーバーレスを実現する|DMM inside App Engineの標準環境でNuxtを使って無料SSR - Crieit  WordPressサイトのURL構造をクローンする方法は書くかもしれません。 https://osd-nuxt.appspot.com/ (※記事投稿時点での情報なので、その後更新されている可能性があります)  この時点では、記事投稿・データベースにはWordPressを利用しています。  Nuxtで表示はしていますが、静的サイト化ではなくSSRですし、結局ロリポップのサーバーを見に行っているので速度的に向上もしないでしょう。 (キャッシュなどを使って部分的に高速化はできるかもしれませんし、脱jQueryできるのでフロント側の速度は上がるかもしれませんが、根本的な解決ではない)

フェーズ2:FirestoreとWordPressのDBを同期させる

 FirebaseにはCloud Functionsという機能があり、外部からGET, POSTなどのメソッドと一緒に叩くことで特定のNode.js操作を実行してくれる機能があります。  これを利用して、WordPress投稿時にその記事データを自動でCloud Functionsに投げさせれば、自動でFirestoreにも記事が投稿されていく仕組みが作れるはずです。(※無料枠でできるかどうかは不明です)  現在WordPressに存在している全ての記事を特定のタイミングで一度コピーしてしまえば、あとは常にWordPressとFirestoreの同期が取れるはずです。  同様のことを記事だけでなくコメント・固定ページ・カスタム投稿タイプに対しても行えば、ブログ閲覧に際して必要なデータが全てFirestoreに渡ります。

フェーズ3:Nuxtでデータを見に行く先をFirestoreにする

 WP REST APIから取っているデータをFirestoreに変えます。APIをきっちり分けておけばここは対応できるはずです。  Firestoreからデータを取ってくる際に制約となるのは、 ・別テーブルの情報を一発で取ってこれない(クライアント側で2回リクエストして取ってくる必要がある。ただし、ブログレベルだとあまりデメリットにはならなさそう。関連記事のリンクを取ってくるのがちょっと辛いかも) ・offset指定ができない(例えば投稿日ソートするなら、startAfterで日付を渡してそれ以降を10件、みたいな指定になる) ・キーワード検索ができない  このキーワード検索だけがネックで、Algoriaなどの外部サービスと連携させる必要がありそうです。 https://firebase.google.com/docs/firestore/solutions/search?hl=ja  逆に言えば壁になりそうなのはほぼキーワード検索のみと言って良いでしょう。Algoriaと繋げるつもりですが、ここから2ヶ月くらいでFirestore公式にもう少しマシなソリューションが追加されないかなーと淡く期待しています。

フェーズ4:コメント・いいねの投稿先をFirestoreにする

 これはその名の通り。むしろ本来のFirestoreの使い方なのであんまり苦労しないと思います。  commentsやlikesのサブコレクションに書き込み権限を与えるか、cloud functionsでどうにかするかは、考え中です。  これを行うことで、WordPress側には存在せずFirestoreにしかない情報がついに生まれ始めます。

フェーズ5:記事を投稿するたびに自動で静的サイト化・デプロイが行われるようにして、JAMStack化する

 そもそもREST APIでJAMStack化できないのは、5000件もあるこのブログの記事のデータを静的サイト化のために取得しようとするとロリポップさんが確実に落ちるからであって、  無限のパワーを持つFirestoreであれば、記事更新のたびにリクエスト10000件投げてもたぶん大丈夫ですよね?無料枠でも1日50000回まで読み取り可能らしいですし、従量制でも10万回読み取るごとに6円。  静的サイト化するということは、デプロイ時以外にはFirestoreへのリクエストが行かなくなるということでもあるはずなので。……まあ実際には、コメントやサイドバーなどは静的サイト化せずにクライアントから取りに行っても良さそうですが。  ここまで行けば悲願のJAMStack化が達成されます。  自動で静的サイト化は、NetlifyならGitHubにpushするたびに更新できますが、Firebase Hostingだとどうするんだろう? やはりCircleCIになるのでしょうか。 Circle CIからFirebase Hostingに自動ビルド&デプロイする - Qiita  この記事が参考になりそうです。

フェーズ6:WordPressのレンタルサーバーとGCPを解約する

 この時点で、WordPressの機能は「記事投稿時に投稿内容をFirestoreに投げるだけ」になっているはずです。  エディターとしてWordPressを使うのだとしても、この機能であればWordPressサイトをローカルに作っても良さそうですよね。  とはいえバックアップとしては使えますし、わざわざ自作する理由もそんなになさそうなので、月250円ならしばらくは持っていても良いのかなと思います。  脆弱性に関しても、POSTしかしないならWordPressサイトごとbasic認証かけてしまって問題ないはずです。  フェーズ5で静的サイト化した時点でFirebase HostingかNetlifyに上がっているはずなので、SSRは確実に不要です。

技術構成

 フロントサーバーホスティングデータベースエディター
...

comment  0
favorite  3
技術・Web 4年前

WordPressからNuxt+Firebaseへの移行 ③ Firebaseの準備と記事の投稿

2019.11追記  ここに書いてあるのは古い内容で、あまり筋が良くなかったので現在は作業方針を変えています。詳しくは以下の記事をご覧ください。

前回までのあらすじ

 Nuxt.jsで記事編集画面を作りましたが、送信する先がまだありません。  記事を保存するデータベースをFirebaseに用意します。

Firebaseの基本設定

Nuxt.jsとFirebaseを使って簡単なWebサービスを作る<導入編>|東京のWeb制作会社|non-standard world株式会社  Firebaseの初期設定については上記のページを参考にしてください。全部書いてあります。  大まかにまとめるなら
    Firebaseのプロジェクトを作成 npm install -g firebase-tools firebase login でログイン firebase init hosting でプロジェクトを選択
 という流れです。

Firebase側の初期設定

1556651077520  Firestoreに移動し、 1556651129921  テストモードで開始します。  「コレクションの追加」を選択し、 1556651167691  posts コレクションを作成。 1556816631479  適当に中身を設定します。

Nuxt.jsにFirebaseの設定情報を追加

Nuxt で Firebase を使う (Cloud Firestore & Hosthing) - かもメモ  こちらの記事を参考に、まず環境変数を導入します。 yarn add @nuxtjs/dotenv  でモジュールをインストールし、 modules: [ '@nuxtjs/axios', '@nuxtjs/markdownit', '@nuxtjs/dotenv' ],  dotenvを追記。 .env というファイルを作成し、中身はfirebaseコンソールの埋め込みコードをコピー。 FB_API_KEY = "***"FB_AUTH_DOMAIN = "***"FB_DATABASE_URL = "***"FB_PROJECTID = "***"FB_STORAGE_BUCKET = "***"FB_MESSAGING_SENDER_ID = "***" 環境変数をブラウザ上でも参照できるよう、nuxt.config.js env: { FB_API_KEY: process.env.FB_API_KEY, FB_AUTH_DOMAIN: process.env.FB_AUTH_DOMAIN, FB_DATABASE_URL: process.env.FB_DATABASE_URL, FB_PROJECTID: process.env.FB_PROJECTID, FB_STORAGE_BUCKET: process.env.FB_STORAGE_BUCKET, FB_MESSAGING_SENDER_ID: process.env.FB_MESSAGING_SENDER_ID },  と追記。 plugins/firebase.jsというファイルを作成し、 const firebase = require('firebase/app')require('firebase/firestore')require('firebase/storage')// .env に設定した値を取得const config = { apiKey: process.env.FB_API_KEY, authDomain: process.env.FB_AUTH_DOMAIN, databaseURL: process.env.FB_DATABASE_URL, projectId: process.env.FB_PROJECTID, storageBucket: ...

comment  0
favorite  0
技術・Web 4年前

WordPressからNuxt+Firebaseへの移行 ② プロジェクト立ち上げ、記事作成画面、マークダウンエディター

2019.11追記  ここに書いてあるのは古い内容で、あまり筋が良くなかったので現在は作業方針を変えています。詳しくは以下の記事をご覧ください。

前回までのあらすじ

 脱WordPressしてHeadless CMSに移行することを決めたものの、記事数が多すぎてContentfulを使えないため、データ保存にFirestoreを使うことを決意しました。  この移行作業中も現行のブログを更新していくつもりなので、  データ保存以外の作業を全部終わらせてから最後にデータ引っ越しする方が効率が良いなと思い、まずはFirebaseで新規ブログを作る気持ちで開発を始めることにしました。  ※この記事はVue.js / Nuxt.jsについてはある程度わかっている前提で書いています。初めてNuxt.jsに触れるという方がこれをやるのはオススメしません。

Nuxt.jsのプロジェクトを準備

 さすがにVS Codeとかyarnとかの説明は省略。  
インストール - Nuxt.jsに従ってcreate-nuxt-appします。 nuxt-create-app  とりあえずLinter、Prettier、Axiosなどは全部入れておきます。  この画面でついでにsass-loaderとかも入れられれば別途入れるものがなくなるのだけど、ないのでyarn add --dev node-sass sass-loader。  あとはnuxt.js(v2)の作業ディレクトリを整理 - Qiitaで作業フォルダをsrcに移す程度。

コードの自動フォーマット

 ESLintとPriettier、別に邪魔になるものでもないのでとりあえず設定しておいて損はないかと思います。  ESLintの設定は開発ツール - Nuxt.jsで。  基本的にはnuxt.config.jsも.eslintrc.jsも全てコピペすれば良いと思うのですが、nuxt.config.jsのextendの中身を // Run ESLint on save​ if (ctx.isDev && ctx.isClient) {​ config.module.rules.push({​ enforce: 'pre',​ test: /\.(js|vue)$/,​ loader: 'eslint-loader',​ exclude: /(node_modules)/,​ options: {​ fix: true​ }​ })​ }`  と、optionsでfix: trueを指定すると、ファイルを保存するたびに勝手にコードの整形まで走らせてくれます。便利な時代になりました。  .eslintrc.jsに関しては、余計なカスタムをせずに広く支持されているルールに従うべきだと思っていますが、 // add your custom rules here globals: {​ alert: false,​ document: false,​ console: false,​ location: false,​ process: false,​ firebase: false }, rules: {​ "semi": [2, "never"],​ "no-console": "off",​ "vue/max-attributes-per-line": "off",​ "prettier/prettier": ["error", { "semi": false ...

comment  0
favorite  0
技術・Web 4年前

WordPressからFirebase+Nuxt.jsのHeadless CMSに完全移行するまでの記録 ①導入・技術選定

前置き

 2019年4月現在、このブログはWordPressで開発・運用していますが、  それに伴って生じている様々な問題を解決するために、脱WordPressすることを決めました。  主な理由は4つ。 ①サイトの速度が明らかに遅いため、Lighthouseなどのスコアが上がらないのがSEO・利便性の両面で不利。jQueryやPHP・サーバー応答速度といったボトルネックは、WordPressを使っている限り解消することができない ②NetlifyやFirebaseなどの無料で使えるサービスが充実してきている中、レンタルサーバーを使っているのはコスパも悪い ③今後のことを考えると、記事データはMySQLではなくJSON形式の方がバックアップしやすく安全 ④Vue.js、CSSフレームワーク、PWA・AMPなどといった新しい技術とWordPressの相性が致命的に悪すぎる  これに加えて、Gutenburgとかの不要な新機能に付き合いたくないとか、PHPにもう関わりたくないとか、勉強になりそうとか、いろいろあるのですが、  やはり一番の要求はサイトの速度です。
1555691656937  4月に割と大規模な改修を行ったのですが、上記のように軽量っぽいサイトであってもかなり低めのスコアが出てしまいます。  まあ部分的にVue.js+WP REST APIを使ってしまったのも悪いのですが、ただそれをせずにWordPressにHTML出力をさせると余計なクラスばかり付与されてCSSフレームワークと共存できず……。  REST API部分は読み込み後回しにしているので、上記のように初回ペイントだけはマシな速度なのですが、それでも遅い。  というかそもそも、どのJSをheadで読み込んでどれを後回しにするのかを全て頭で考えるのが無駄な作業すぎるし、プラグインのAutoptimizeを使うとこの依存関係がごちゃごちゃになって表示できなくなり、jQueryやVueやaxiosは他のJSより先に読み込まないといけないのでこのあたりの重いJSファイルにasyncやdeferを付けるとバグるという、何とも本末転倒な感じに。  改修作業をすればするほど不毛な印象を受けてしまい、これを乗り越えるにはWordPressを捨てるしかないと決断しました。  WordPressから移行してどういうサイトにしたいかというと、  ①記事をマークダウン形式で投稿し  ②JSON形式で保存し  ③JavaScriptでレンダリングし  ④静的サイトに事前出力したい(できれば)  という構成です。④については後述します。  2020.05追記  このサイトは既にFirebase/Nuxt構成への移行を完了しており、2020年2月よりFirebase Hosting上で運用されています。最終的な結果を読みたい方は、この記事の内容は無視して下の記事をご覧ください。  以下に記載している内容は2019年5月時点の想定で書かれており、この1年で古くなったり実際に実装してみると上手くいかなかったりした内容なども含まれています。あらかじめご了承ください。

理想の実装(JAMstack)

 上記の要件でブログを作るのであれば、現時点ではおそらくNuxt.js + Contentful + Netlifyという実装が最適解なのだろうと思います。 爆速を求めて個人ブログをWordpressからGatsbyJS+Contentful+Netlifyに移行した話 | blog.potproject.net Nuxt.jsとContentfulでモダンなブログを構築してみた - Qiita  NuxtではなくGatbyJS、ContentfulではなくGraphCMS、NetlifyではなくGitHub Pagesなどの違いはありますが、  この手の「Contentfulで更新されるたびに静的サイト生成してNetlifyでホスティングすれば無料で爆速で神」という記事は本当にたくさんあって、  実際タイトル通りの爆速を達成しているサイトもたくさんありますし、新規に立ち上げるブログであれば間違いなく今一番良い方法だと思います。  ちなみに、こういった実装にJAMstackという名前が付いているようです。
Modern web development architecture based on client-side JavaScript, reusable APIs, and prebuilt Markup. JAMstack | JavaScript, APIs, and Markup
 「クライアントJS、再利用可能なAPI、前もって構築済みのHTML」の組み合わせを指す言葉。格好いいし、格好いい名前がついている技術なのでたぶん流行る。  ただ、その手のサイトの多くが、あくまで技術検証を目的にしていて、記事数がそこまで多くない(サイトの制作時点では10個に満たない)ことを前提にしています。  しかし、このブログは現時点で3700件以上の記事と1500枚以上の画像があるわけで、  例えばContentfulの「レコード5000件まで無料」という、普通であれば絶対に引っかからない制限に引っかかってしまうのです。  また、静的サイト生成に関しても、3700件のページ・カテゴリー・11年分の月別アーカイブを都度再生成するのがどうなのかという問題もあります。

技術選定

フロントエンド:Nuxt.js

 私がVue.js・Nuxt.js大好きなのでここは確定。  以前、WP REST API + Nuxt.jsでのサイト製作を試していたのですが、結局WordPressを捨てないとどうしようもないと気づきました。

データベース:Firebase

 上述の理由よりContentfulでの記事管理が難しそうなので、  今回はFirebaseのFirestoreに全記事を格納しようと考えています。  Firestoreのデータ制限がどれほどかわかりませんが、料金説明によると1GB(チャットメッセージ2000万件分)までは無料なので大丈夫でしょう。 1555770518405  Firestoreは少しだけ触ったことがありますが、where・orderby・limitといった指定で絞り込みができるというのは、WordPressのget_postsに挙動が似ているので、使いやすいのではないかと思います(参考:Cloud Firestore でのデータの並べ替えと制限)  ちなみにFirebaseの最大のウリであるリアルタイムデータベースについては今回は無視する予定です。たくさんの人が投稿するサービスならともかく、個人のブログがリアルタイムで更新される必要はあんまりないし、最新記事やコメントについてもリロード時に再取得で問題ないでしょう。  Contentfulと比較した場合の最大の欠点は、新規記事を追加するためのエディターを自作しなければならないことにあるような……。

ホスティング:Netlify or GCP

 これは迷っています。  JAMstack的な実装で、静的サイト生成を行うのがパフォーマンス的には最速なのでしょうが、  記事を投稿・更新するたびにnuxt generateで4000ページを再構築するというのが、果たして現実的なのかどうかについて疑問が残ります。無料の範囲を超えてしまうのではないかと。  このあたりを、payloadなどの方法でどうにかなるのであれば、Netlifyにホスティングして記事投稿のたびにGitHubにpushすれば良さそうですが、  そうでなければ、GCPのNode.jsで普通にサーバーサイドレンダリングでも良いんじゃないかなとも思っています。  SSRと静的サイト生成を、ほぼ同じコードで開発できるのがNuxt.jsの利点ですから、このあたりは開発の最後に決めようと思っています。 ...

comment  2
favorite  1