nuxt.js + firebase (cloud functions) で最小構成SSR

2018年7月末にGCPのcloud functionsでNode v8が使えるようになりました 🎊

以前まではnode v6しか使えなかったので、nuxtのrc1バージョンしか使えなかったのですが、それが解消されました。

二番煎じな内容ではありますが、SSRに必要最低限のコードを意識してまとめてみました。

※本記事では、nuxt.js、firebaseの詳しい説明は割愛し、SSRが動くまでの流れのみ説明します。

 

準備

サンプルコードを用意しました。これを使う場合はクローンしてください。

https://github.com/atoka-tech/nuxt-firebase-ssr

FirebaseはGoogleアカウントがあれば、下記よりプロジェクトを作れるはずです(基本無料)。適当な名前でプロジェクトを作ってください。

https://console.firebase.google.com/

更に、作業PCにnodeをインストールしておき、npmコマンドを使えるようにしておきましょう(動作確認はnpm v6.3.0で行っています)。

 

開発スタートまでの仕込み

サンプルコードをクローンしたら、 npm install して必要なnode moduleをインストールしましょう。

functionsディレクトリ内はcloud functionsで使うファイル群ですが、この中でも npm install  しましょう。ここまでの作業で下記のようなファイル構造になります。

スクリーンショット 2018-08-09 20.07.23

インストールが終わったら、プロジェクトルートディレクトリに移動し、  npx firebase login  で先程作成したfirebaseプロジェクトを持つGoogleアカウントにログインします(ブラウザが開きます)。

ログインしたら npx firebase use --add  コマンドを実行します。firebaseプロジェクト一覧が出てくるので、先程作ったプロジェクトをEnterで選択します。選択するとエイリアス名を入力する設問が出るので、適当な名前をタイプしてEnterしましょう。これで、ソースコードをどのfirebaseプロジェクトにデプロイするかの設定が完了しました(.firebasercファイルにエイリアス設定が追記されます)。

npm start  でnuxtのローカルサーバーが起動するので、http://localhost:3000/ でアクセスしてみましょう。下のような画面が表示されれば成功です。わかりやすいように3ページ作ってますので、今回はこれをデプロイします。

スクリーンショット 2018-08-09 20.01.22

 

firebaseについて

firebaseには様々な機能がありますが、今回はhostingとcloud functionsの2つを使います。hostingでは静的ファイルをfirebaseサーバーにて管理できます。cloud functionsではバックエンドコードを実行できます。

流れとしては、

① httpアクセスをcloud functionに集める
② cloud functionでnuxt.renderを実行し、レンダリング結果をそのままレスポンスする
③ 静的ファイル(画像など)はfirebase hostingにより配信する

となります。①を実現するのが、firebase.jsonの設定です。rewrites項目を見ると分かる通り、すべてのリクエストをssrというfunctionに流す、という記述があります。

ssrという部分はこちらで決めた名前であり、functions/index.jsの「exports.ssr」を指しています。このfunctions/index.jsファイルのコードがssrというfunctionの中身であり、これが②を実現するものです。

なお、全てのリクエストをこのfunctionに流すというのは少し間違っており、hosting機能でアップロードしたファイルのパスへのアクセスはそのままhostingされているファイルがレスポンスされます。これが③の内容です。これを実現するための設定はfirebase.jsonのhosting.public設定です。使用する静的ファイルすべてをhostingする必要があるので、ここではnuxtのstaticディレクトリを指定しています。

 

nuxt.jsとnpm scriptsについて

nuxtのコマンドとしては、 nuxt と nuxt build の2つを使います。前者がローカル開発用のコマンドで、後者がdeploy用コードを実行するコマンドです。

package.jsonを見てください。いくつかnpm scriptsが定義されています。

npm run build コマンドを実行すると、npm scriptsにより、まず nuxt build  が実行され、.nuxtディレイクトリに圧縮前のJS・CSSファイルが出力、.nuxt/distディレクトリにそれらのJS・CSSを圧縮したファイルが出力されます。

このうち、圧縮された.nuxt/distディレクトリの中身のみをcloud functionsで使用するので、このディレクトリをfunctions/ssrにコピーするのがbuild:copy:ssrタスクです(厳密にはコピー前にディレクトリを削除して整頓しています)。

このコピーされたfunctions/ssrファイルは、functions/index.jsの中にあるnuxtのコンフィグ設定のbuildDirとして指定されていることに注意してください。こうすると、nuxt.renderメソッドはこのビルドされたコードに従ってレンダリングを行います。

 

ローカルでCloud functionsの動作確認

npm run build  を実行してfunctions/ssrを作ったら、  npm run serve でfirebase-cliのserve機能を起動してみましょう。今度はport 5000でアクセスできます。

http://localhost:5000/

npm start  コマンド時と同じ画面になれば成功です。

 

firebaseへデプロイする

準備は整ったので、cloud functionsとhostingをfirebaseへデプロイしましょう。必要な作業は単純で、 npm run deploy  コマンドで、firebase deployコマンドを起動するだけです。デプロイには少し時間がかかります(2分ほど)。

hoge

Deploy complete! で完了です。firbeaseコンソールにアクセスし、該当プロジェクトのhostingを開きます。

hoge

デプロイされてますね。ドメインにアクセスするとローカルで見たものと同じものが出ていると思います。

SSRのメリットの一つでもあるメタタグ(タイトルタグ)がちゃんとSSRされてる!

 

遅い

アクセスしたときに感じたかもしれないですが、初期表示が遅めです(10秒位かかっちゃう場合も…)。これはおそらくcloud functionsの仕様で、アクセスが無いときはコールドスタンバイするからだと思われます。

なので、何度かリロードしていると、インスタンスがホットになりページロードの時間も短縮されるでしょう。

このように、SSRは手放しに採用すべきものではなく、環境やアプリケーションの規模や実現したいことやキャッシュやチューニングなどなどを踏まえて選択するのがよいと思います。

今回のような静的小規模サイトの場合、cloud functionsによるSSRはやめて、下記のようにfirebase.jsonのリライト設定をindex.htmlに向け、nuxtのspaモードでビルドしたファイルをホスティングするのみにした方がまとまりが良いと思います。

 

●この記事を書いた人