2018年7月末にGCPのcloud functionsでNode v8が使えるようになりました 🎊
以前まではnode v6しか使えなかったので、nuxtのrc1バージョンしか使えなかったのですが、それが解消されました。
二番煎じな内容ではありますが、SSRに必要最低限のコードを意識してまとめてみました。
※本記事では、nuxt.js、firebaseの詳しい説明は割愛し、SSRが動くまでの流れのみ説明します。
2019.02.20更新
nuxtがv2を出して久しいので、nuxt v2用にアップデートしました。
準備
サンプルコードを用意しました。これを使う場合はクローンしてください。
https://github.com/atoka-tech/nuxt-firebase-ssr
FirebaseはGoogleアカウントがあれば、下記よりプロジェクトを作れるはずです(基本無料)。nuxt-ssrなどの適当な名前でプロジェクトを作ってください。
https://console.firebase.google.com/
更に、作業PCにnodeをインストールしておき、npmコマンドを使えるようにしておきましょう(動作確認はnpm v6.7.0で行っています)。
開発スタートまでの仕込み
サンプルコードをクローンしたら、 npm install して必要なnode moduleをインストールしましょう。
functionsディレクトリ内はcloud functionsで使うファイル群ですが、この中でも npm install しましょう。ここまでの作業で下記のようなファイル構造になります。
インストールが終わったら、プロジェクトルートディレクトリに戻り、 npx firebase login で先程作成したfirebaseプロジェクトを持つGoogleアカウントにログインします(ブラウザが開きます)。
ログインしたら npx firebase use --add コマンドを実行します。firebaseプロジェクト一覧が出てくるので、先程作ったプロジェクトをEnterで選択します。選択するとエイリアス名を入力する設問が出るので、適当な名前をタイプしてEnterしましょう。これで、ソースコードをどのfirebaseプロジェクトにデプロイするかの設定が完了しました(.firebasercファイルにエイリアス設定が追記されます)。
npm start でnuxtのローカルサーバーが起動するので、コンソールに表示されるアドレスにアクセスしてみましょう。下のような画面が表示されれば成功です。わかりやすいように3ページ作ってますので、今回はこれをデプロイします。
firebaseについて
firebaseには様々な機能がありますが、今回はhostingとcloud functionsの2つを使います。hostingでは静的ファイルをfirebaseサーバーにて管理できます。cloud functionsではバックエンドコードを実行できます。
流れとしては、
① httpアクセスをcloud functionに集める
② cloud functionでnuxt.renderを実行し、レンダリング結果をそのままレスポンスする
③ 静的ファイル(画像など)はfirebase hostingにより配信する
となります。①を実現するのが、firebase.jsonの設定です。rewrites項目を見ると分かる通り、すべてのリクエストをssrというfunctionに流す、という記述があります。
1 2 3 4 5 6 |
"rewrites": [ { "source": "**", "function": "ssr" } ] |
ssrという部分はこちらで決めた名前であり、functions/index.jsの「exports.ssr」を指しています。このfunctions/index.jsファイルのコードがssrというfunctionの中身であり、これが②を実現するものです。
このようにすることで、静的なHTMLファイルをホスティングせずとも、HTMLを配信できる仕組みができあがります。
なお、「httpアクセスをcloud functionに集める」というのは少し間違っており、hosting機能でアップロードした静的なファイルへのアクセスはそのままhostingされているファイルがレスポンスされます。どういうことかというと、今回の場合、静的にホスティングするのはsrc/static配下のファイル(sample.pngのみ)ですが、下記のようにそのファイルに直接アクセスしたときは
https://{project_ID}.firebaseapp.com/sample.png
cloud functionを通さず、このファイルがそのままレスポンスされるということです。これが③の内容です。その設定はfirebase.jsonのhosting.publicに書かれています。
nuxt.jsとnpm scriptsについて
今回、nuxtコマンドとして nuxt と nuxt build の2つを使います。前者がローカル開発用のコマンドで、後者がdeploy用コードを実行するコマンドです。
package.jsonを見てください。いくつかnpm scriptsが定義されています。
1 2 3 4 5 6 7 |
"scripts": { "start": "HOST=0.0.0.0 nuxt", "build": "nuxt build && npm run build:copy:ssr", "build:copy:ssr": "rimraf functions/ssr && mkdirp functions/ssr && cp -R .nuxt/dist functions/ssr/dist", "serve": "firebase serve", "deploy": "firebase deploy" } |
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機能を起動しアクセスしてみましょう。
npm start コマンド時と同じ画面になれば成功です。
firebaseへデプロイする
準備は整ったので、cloud functionsとhostingをfirebaseへデプロイしましょう。必要な作業は単純で、 npm run deploy コマンドで、firebase deployコマンドを起動するだけです。デプロイには少し時間がかかります(2分ほど)。
Deploy complete! で完了です。firbeaseコンソールにアクセスし、該当プロジェクトのhostingを開きます。
デプロイされてますね。ドメインにアクセスするとローカルで見たものと同じものが出ていると思います(もしエラーが出た場合は少し待ってみてください。cloud functionsが準備中の可能性があります)。
SSRは必要か
今回のような単純な静的ページの場合、 nuxt generate にて静的書き出ししたものをホスティングすれば同等のものが作れるので、それ用のサーバーを無理に構築したりして作るほどのものではないと思います。
SSRが必要な場面は、バックエンドデータを反映したHTMLを配信する必要がある場合でしょう(SNSのクローラー用など)。
ただしそういったことがなくても、フロントエンドとバックエンドを同じJSで書けるというのはメリットではあるので、要件とメリットデメリットを考えた上で採用するのが良さそうです。