ポートフォリオサイトをVue.jsからNuxt.jsに書き換えてサーバーサイドレンダリングをする
本記事
本記事はVue.jsを使ってGoogle App Engineにホストしている静的なサイトをNuxt.jsを使って書き直そう思います。
題材は以前使った自分のポートフォリトサイトです。
GoogleCloudPlatform(GCP)で無料枠を使いきり画像などのコンテンツをCloud Storageに置いてありましたが、Embulkをマスターしたことによって簡単に二つ目のアカウントに移行できたので、再度ホストしようと思いました。
目的
今回の移行には、以下のような目的がありました。
コンポーネント設計が自由すぎる
どこまでをどうコンポーネント分けするのかは、Vue.jsやReactを使っている人ならよくあると思います。
僕自身も、学生で、インターンといえばサーバーサイド、インフラ、モバイルアプリしか歩んでこなかったので、フロントエンドを知識がなく、HTMLやCSS、JSは書けるけど正しいかどうか分からないままコンポーネントを作っていました。
SVGを自分で書いた時も、個人的にSVGのViewboxが非常に苦手(理解できない)ので、SVGコンポーネントとして作ってしまってたくらいカオスな情況でした。
本当にアトミックなコンポーネント分けだと、どうしてもコンポーネントのネストがひどくなって、逆に管理も面倒でした。
また、ディレクトリ分けもそうです。 どこにどう置いても良いVue.jsは雑でした。
Nuxt.jsはコンポーネント分けまではやってくれませんが、ある程度ディレクトリ構成などソフトウェアに秩序をくれるため導入しました。
SEO対策とサーバーサイドレンダリング
今ではSEO対策にNuxt.jsが提供するサーバーサイドレンダリングは関係ないということが発表されていて、本当にどうなのかは調査不足のため知りませんが(ここではそれを信じるとしても)数年間、この「サーバーサイドレンダリング」がフロントエンド界隈では盛り上がっていたので知っておく価値はあるのかなと思いました。
またサーバーサイドレンダリングは、大きな容量のjsを返すのではなくて、初期表示を高速化するためにサーバーで処理して返すのは結局はUXにつながり、Googleがクロールするかだけでなく、SEO対策の一環となると思うので、重要だと思いました。
移行する
Nuxt.jsプロジェクトを作成する
npx
を使ってNuxt.jsプロジェクトをから作成します。
npx create-nuxt-app keisukeyamashita-portfolio-nuxt cp /vue/project/path/views/* ./pages
移行により必要なくなったパッケージをuninstallする
以下のように必要のないパッケージをアンインストールします。
ディレクトリを分ける
特に今回は設計に秩序をもたらしたいと思いNuxt.jsを採用したので、ディレクトリ構造について理解する必要がありました。
移行について今回知るべきことは以下の項目でした。
/pages
: ルーティングファイル。これを元にルーティングし、.vueである必要があります。SPAなので一つしかありません。/static
: 静的ファイル。robot.txtやfavicon.icoを入れました。/components
: Vueコンポーネントを入れました。plugins
: 外部ライブラリなどをimportするためのもの
この時点で以下のようになっています。
. ├── README.md ├── package.json └── src ├── components ├── pages ├── plugins └── static
Plugins
これはvendor.js
に含めたいので以下のようにnuxt.config.js
に書き加えます。
また、これらのプラグインはアプリケーションを表示するためにかならずしも重要ではないためapp.js
には入れずにvendor.js
としてまとめたいのでwebpack
の設定を書き加えます。
... plugins: [ '~plugins/hoge' ], ... build: { vendor: [ 'vue-lazyload' ], } ...
build
に書くことによってvendor.js
に含まれるようになります。
と思ったのですが、Stackdriver Loggingでみると以下のようなエラーがでます。
{ insertId: "5bbe4a710005f68ac8672452" labels: {…} logName: "projects/keisukeyamashita-portfolio/logs/stdout" receiveTimestamp: "2018-10-10T18:52:33.413653645Z" resource: {…} textPayload: "[18:52:33] vendor has been deprecated due to webpack4 optimization" timestamp: "2018-10-10T18:52:33.390794Z" }
この記事をみて、webpack4からは最適化ロジックの変更が内部でありVendor
は指定できないようになっています。
一部コードを書き直す
例えばdocument
やbody
などはクライアントサイドレンダリングでしかアクセスできないので以下のようなものも当然サーバーサイドレンダリングではできません。
beforeCreate: function () { document.body.className = 'body' },
これはDOMの構築などクリティカルレンダリングパスを学ぶとわかると思います。
ルーティングを実装
/pages
ディレクトリを正しく構築できていれば、自動的にrouterは生成されます。今まではvue-router
を使っていたし、ストリングパラメータやバリデーションの方法など、少しAPIが違うことがわかりました。
ここまでできたら、とりあえずローカルで起動できるか確認してみます。
ローカル環境ではサーバーサイドレンダリングをしないので、以下のようにします。
npm run dev
最適化をする
どのファイルが重いかを可視化をすることができます。
nuxt build --analyze
at-ui
が必要ないことに気づき、削除しました。
ビルドしてみる
以下のコマンドでビルドをしてください。
npm run build
そして、サーバーサイドレンダリングを試してみてください。
npm start
ただしく表示ができれば終了です。
GAEにホストする
以下のコマンドGAEにデプロイします。
前はVue.jsで静的サイトでしたが、今回はサーバーサイドレンダリングという名前があるようにサーバーが必要になるので少し変更します。
以下のようにapp.yaml
には書いています。
runtime: nodejs8 env: standard service: keisukeyamashita-portfolio-nuxt instance_class: F2
これでデプロイしています。
gcloud app deploy
特にruntime: nodejs8
の場合はnpm
を使う必要があり、npm install
など必要ないことがポイントです。
また、これは自分のアプリケーションだからかもしれませんが
Exceeded soft memory limit of 128 MB with 148 MB after servicing 1 requests total. Consider setting a larger instance class in app.yaml.
と出て、メモリ不足のためにinstance_class: F2
と指定しています。
確認
以下のように確認することができました。
比較
以下のようにキャッシュなしでのロード時間を計測しました。
Nuxt.js
: 445msVue.js
: 859ms