Search code examples
javascriptnode.jsreactjsfirebase-hostingnext.js

How can I setup Firebase hosting multisites with Nextjs


I'm trying to deploy nextjs app to firebase hosting and want to support multiple site. When I deploy it all app renders the default app. How can I fix this?

I was following the tutorial here on Deploying multiple sites to firebase using AngularJs and I tried to replace Angularjs with NextJs

scripts in package.json

{
  "scripts": {
    "accounts": "next \"src/apps/accounts/\"",
    "accounts-build": "next build \"src/apps/accounts/\"",

    "admin": "next \"src/apps/admin/\"",
    "admin-build": "next build \"src/apps/admin/\"",
    "preserve": "npm run build-public && npm run build-funcs && npm run admin-build && npm run copy-deps && npm run install-deps",
    "serve": "cross-env NODE_ENV=production firebase serve",
    "predeploy": "npm run build-public && npm run build-funcs && npm run accounts-build && npm run admin-build && npm run copy-deps",
    "deploy": "firebase deploy",
    "clean": "rimraf \"dist/functions/**\" && rimraf \"dist/public\"",
    "build-public": "cpx \"src/public/**/*.*\" \"dist/public\" -C",
    "build-funcs": "babel \"src/functions\" --out-dir \"dist/functions\"",
    "copy-deps": "cpx \"*{package.json,package-lock.json,yarn.lock}\" \"dist/functions\" -C",
    "install-deps": "cd \"dist/functions\" && npm i"
  }
}

firebase.json

{
  "hosting": [
    {
      "target": "accounts",
      "public": "dist/public",
      "rewrites": [
        {
          "source": "**/**",
          "function": "accounts"
        }
      ]
    },
    {
      "target": "admin",
      "public": "dist/public",
      "rewrites": [
        {
          "source": "**/**",
          "function": "admin"
        }
      ]
    }
  ],
  "functions": {
    "source": "dist/functions"
  }
}

.firebaserc

{
  "projects": {
    "default": "example-app"
  },
  "targets": {
    "example-app": {
      "hosting": {
        "accounts": [
          "example-accounts"
        ],
        "admin": [
          "example-admin"
        ]
      }
    }
  }
}

index.js in functions

import {https} from 'firebase-functions'

const dev = process.env.NODE_ENV !== 'production'
const app = require('next')({dev, conf: {distDir: 'next'}})
const handle = app.getRequestHandler()

const accounts = https.onRequest((req, res) =>
    app.prepare().then(() => handle(req, res)))

const admin = https.onRequest((req, res) =>
    app.prepare().then(() => handle(req, res)))

export {accounts, admin}

next.config.js moved it to the root folder

module.exports = {
  distDir: '../../../dist/functions/next'
}

All app render the default Accounts App. would like the admin to render the admin app.


Solution

  • As you are having different folders as admin and accounts in your apps directory so when you are making the build for each of them next.js always consider the last build you are making and serving the pages of last build so to overcome this problem we have to create the builds in different directories for admin the directory will be

    dist/functions/admin/next

    and for customer the directory will be

    dist/functions/accounts/next

    you have to define different distDir for this so while serving page it will look in the specified directory so please change your

    next.config.js for admin

    module.exports = {
      distDir: '../../../dist/functions/admin/next'
    }
    

    next.config.js for accounts

    module.exports = {
      distDir: '../../../dist/functions/accounts/next'
    }
    

    keep this next.config.js in your src/apps/admin and src/apps/customer directory respectively and change your

    index.js in functions

    import {https} from 'firebase-functions'
    
    const dev = process.env.NODE_ENV !== 'production'
    const appAdmin = require('next')({dev, conf: {distDir: 'admin/next'}});
    
    const appAccounts= require('next')({dev, conf: {distDir: 'accounts/next'}});
    
    const handle = app.getRequestHandler()
    
    const accounts = https.onRequest((req, res) =>
        appAccounts.prepare().then(() => handle(req, res)))
    
    const admin = https.onRequest((req, res) =>
        appAdmin.prepare().then(() => handle(req, res)))
    
    export {accounts, admin}