Nuxt.js(SSR)+FirebaseというWEBアプリの最強最終形態
Nuxt.js(SPA)でS3にデプロイする方法にはだいぶ慣れたが、SEOの観点からSPAには限界を感じ始めていた。実際に自分がデプロイしたWEBアプリのPVを観測して出した結論ではないけれど、いつまでも悶々としているよりも、SSRを出来るようになった方が自分の成長の為にも絶対に良いハズ。
SSRと言えどサーバーレスな構成にするのは譲れない。インスタンス管理はやはり面倒。オンプレで運用している方から見ればだいぶ贅沢な事言ってるなと思うだろうが…笑
Nuxt.jsの静的ホスティングやSPAは、
・S3(AWS)
・Netlify
・Cloud Storage(GCP)
と選択肢が多いが、SSRをサーバーレスで実装するとなると、
・Lambda + API Gateway(AWS)
・Firebase(GCP)
・Fargate(AWS)
を使う3つの選択肢が一般的だと思う。
ログイン認証とNo SQLデータベースが用意されているFirebaseの使い方をマスター出来れば、もはやほとんどWEBアプリの究極系なのでは…と思ったのでFirebaseを選択。
何番煎じかはわからないけれど、実装にあたりハマったポイントがいくつかあったので、備忘録がてら書き残しておく。
環境
Windows 10でWSL(Windows Subsystem for Linux)
npm (version: 6.14.5)
firebase-tools (version: 8.3.0)
Firebase sparkプラン(従量課金)
Nuxt.jsをセットアップ
npx create-nuxt-app <directory>
----------------------------------------
Project name: Default
Project description: Default
Author name: Default
Choose programming language: Javascript
Choose the package manager: Npm
Choose UI framework: None
Choose custom server framework: None
Choose Nuxt.js modules: None
Choose linting tools: EsLint
Choose test framework: None
Choose rendering mode: Universal(SSR)
Choose development tools: None
ここでの注意点は、UI frameworkとNuxt.js modulesを選択しないこと。
Bootstrap-vueとAxiosを選択してたら、Cloud functionsでモジュールが読み込めずハマった。。。
完了したらnpm run devでちゃんとWEBサイトが閲覧出来るか確認してから次のステップへ。
Firebaseを設定
cd <directory>
firebase init
-----------------------------------------
fiDrestore, cloud functions, hostingを選択
What file should be used for Firestore Rules?: Default
What file should be used for Firestore indexes?: Default
What language would you like to use to write Cloud Functions?: Javascript
Do you want to use ESLint to catch probable bugs and enforce style?: No
Do you want to install dependencies with npm now?: Yes
What do you want to use as your public directory?: public(Default)
Configure as a single-page app(rewrite all urls to /index.html)?: No
ここの注意点は、ESLintを外すこと(外さずに進めてエラーでまくってBuildに失敗した)。ESLintはNuxtアプリ作成時に設定すれば重複になるので必要ないと思う。
firebase.jsonを編集
vim firebase.json
---------------------------------------------
{
"functions": {
"functions": {
"source": "functions"
}
},
"hosting": {
"public": "static",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"function": "ssr"
}
]
}
}
上記のように書き直す。functionエリアの追加と、rewritesエリアの追加と、publicフォルダの設定。
publicで設定されたフォルダを見に行き、対象ファイルがないとssr functionが実行される設定。favicon.icoなどの非圧縮ファイルを格納するstaticフォルダを指定するとルートディレクトリ上に保存されるので便利。staticフォルダにindex.htmlが保存されているとrewritesが発生しないので注意。
Functionsの依存モジュールを修正
cd functions && npm install --save nuxt
vim package.json
--------------------------------------------
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"serve": "firebase serve --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "10"
},
"dependencies": {
"firebase-admin": "^8.6.0",
"firebase-functions": "^3.3.0",
"nuxt": "^2.12.2"
},
"devDependencies": {
"firebase-functions-test": "^0.1.6"
},
"private": true
}
nodeのversionを10に設定し、dependenciesにnuxtを追加する。nuxtのバージョンはnpm info nuxt versionで確認可能。
Functionsを作成
const functions = require('firebase-functions');
const { Nuxt } = require('nuxt');
const nuxt = new Nuxt({
buildDir: 'ssr',
dev: false
});
exports.ssr = functions.https.onRequest(async (req, res) => {
await nuxt.ready()
return nuxt.render(req, res)
})
Buildコマンドを修正して便利化
cd ../
vim package.json # functionsより1つ上の階層のpackage.jsonなので注意
-------------------------------------------------
{
"name": "***********",
"version": "1.0.0",
"description": "My splendid Nuxt.js project",
"author": "*****",
"private": true,
"scripts": {
"dev": "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",
"start": "nuxt start",
"generate": "nuxt generate",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore ."
},
"dependencies": {
"nuxt": "^2.0.0"
},
"devDependencies": {
"@nuxtjs/eslint-config": "^2.0.0",
"@nuxtjs/eslint-module": "^1.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^6.1.0",
"eslint-plugin-nuxt": ">=0.4.2"
}
} "name": "drillbank", "version": "1.0.0", "description": "My splendid Nuxt.js project", "author": "IDFSDUS", "private": true, "scripts": { "dev": "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", "start": "nuxt start", "generate": "nuxt generate", "lint": "eslint --ext .js,.vue --ignore-path .gitignore ." }, "dependencies": { "nuxt": "^2.0.0" }, "devDependencies": { "@nuxtjs/eslint-config": "^2.0.0", "@nuxtjs/eslint-module": "^1.0.0", "babel-eslint": "^10.0.1", "eslint": "^6.1.0", "eslint-plugin-nuxt": ">=0.4.2" } }{ "name": "drillbank", "version": "1.0.0", "description": "My splendid Nuxt.js project", "author": "IDFSDUS", "private": true, "scripts": { "dev": "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", "start": "nuxt start", "generate": "nuxt generate", "lint": "eslint --ext .js,.vue --ignore-path .gitignore ." }, "dependencies": { "nuxt": "^2.0.0" }, "devDependencies": { "@nuxtjs/eslint-config": "^2.0.0", "@nuxtjs/eslint-module": "^1.0.0", "babel-eslint": "^10.0.1", "eslint": "^6.1.0", "eslint-plugin-nuxt": ">=0.4.2" } }{ "name": "drillbank", "version": "1.0.0", "description": "My splendid Nuxt.js project", "author": "IDFSDUS", "private": true, "scripts": { "dev": "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", "start": "nuxt start", "generate": "nuxt generate", "lint": "eslint --ext .js,.vue --ignore-path .gitignore ." }, "dependencies": { "nuxt": "^2.0.0" }, "devDependencies": { "@nuxtjs/eslint-config": "^2.0.0", "@nuxtjs/eslint-module": "^1.0.0", "babel-eslint": "^10.0.1", "eslint": "^6.1.0", "eslint-plugin-nuxt": ">=0.4.2" } }
scripts内の、buildとbuild:copy:ssrの2のみ修正。ビルド時に.nuxt/distのファイル群が自動的にfunctions/ssr/distにコピーされる。
axios、bootstrap-vueなどの外部モジュールを使用する場合は、こことfunctions直下2つのpackage.jsonに記述する必要があるので注意。
Firebaseにデプロイ
npm run build && firebase deploy
お疲れ様でした。
この記事が気に入ったらサポートをしてみませんか?