firebase hosting with next.js and cloud functions

Last edited time
Last updated October 18, 2022
Text
Tags
ūüí°
hosting nextjs website with firebase is a nightmare. hosting with vercel is way easier.
The firebase example provided by nexjs github repo does not work. I wasted an entire night fixing a lot of errors. Sharing my settings here so you can save time.
The full example is available on github:
firebase-nextjs-example
yihui-he ‚ÄĘ Updated Oct 14, 2022

EROFS: read-only file system

EROFS: read-only file system, unlink '/workspace/dist/next/BUILD_ID’
Next.js tries to do write operations in the node environment. Firebase Cloud Functions only offers the /temp directory where writable actions are allowed in the local disk, meaning that it does not accept any writable actions outside the /temp directory. Only read operation.
solution:
upgrade to Cloud function v2 which allows writable actions everywhere.
The function execution environment includes an in-memory file system that contains the source files and directories deployed with your function (see Structuring source code ). The directory containing your source files is read-only, but the rest of the file system is writeable (except for files used by the operating system). Use of the file system counts towards a function's memory usage.
firebaseFunction.js
const { join } = require('path') const {onRequest} = require("firebase-functions/v2/https"); const { default: next } = require('next') const nextjsDistDir = join('src', require('./src/next.config.js').distDir) // https://stackoverflow.com/questions/65601999/fetching-an-image-from-firebase-storage-using-next-image-results-in-a-400-status const nextjsServer = next({ dev: false, conf: { distDir: nextjsDistDir, images: { domains: [ 'www.notion.so', 'notion.so', 'images.unsplash.com', 'pbs.twimg.com', 'abs.twimg.com', 's3.us-west-2.amazonaws.com', 'fiery-artifact-342404.web.app', 'yihui.dev', 'fiery-artifact-342404.firebaseapp.com', 'yihuihe.notion.site', 'localhost', '127.0.0.1', ], } }, }) const nextjsHandle = nextjsServer.getRequestHandler() exports.nextjsfunc = onRequest({cors: true}, (req, res) => { return nextjsServer.prepare().then(() => nextjsHandle(req, res)) })

Fetching an image

Fetching an image from Firebase storage using next/image results in a 400 status code
solution:
 

github workflow

the github action firebase provided only supports hosting but not cloud function. You need to use another github action
firebase-action
w9jds ‚ÄĘ Updated Aug 28, 2023
example workflow .yml
name: Deploy to Firebase Hosting/Function on merge "on": push: branches: - main schedule: # * is a special character in YAML so you have to quote this string - cron: "30 5,17 * * *" jobs: build_and_deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - run: npm ci && npm run build - uses: w9jds/firebase-action@master with: args: deploy --only functions,hosting env: GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
Give your Service Account the¬†Cloud Functions Admin,¬†Artifact Registry Writer*, and¬†Firebase Authentication Viewer¬†roles, and grant it access to ‚Äúrun as‚ÄĚ the ‚ÄúApp Engine default Service Account‚ÄĚ (you‚Äôll find this listed as¬†[PROJECT_ID]@appspot.gserviceaccount.com).
 
GCP_SA_KEY - Required if FIREBASE_TOKEN is not set. A normal service account key(json format) or a base64 encoded service account key with the needed permissions for what you are trying to deploy/update. If you're deploying functions, you would also need the Cloud Functions Developer role, and the Cloud Scheduler Admin for scheduled functions. Since the deploy service account is using the App Engine default service account in the deploy process, it also needs the Service Account User role. If you're only doing Hosting, Firebase Hosting Admin is enough. https://firebase.google.com/docs/hosting/github-integration

CORS

Firebase cloud function "Your client does not have permission to get URL /200 from this server‚ÄĚ
solution: you need to set cors: true in the firebase function.
exports.nextjsfunc = onRequest({cors: true}, (req, res) => { return nextjsServer.prepare().then(() => nextjsHandle(req, res)) })

references