Alex Pilugin
Alex Pilugin

Reputation: 703

My Vuetify Nuxt SSR (Universal) application on Firebase is hanging

Update: My approach to use 2 folders: functions and src in not working. I started to use another approach when folder for firebase functions is located inside of the src folder. This approach is implemented by winzaa123 user: winzaa123/nuxt2-vuetify-ssr-on-firebase and I could launch it on my Google firebase.

My Steps: Preparation of the project from scratch

Create a Nuxt app inside of the src folder:

  1. Create a Nuxt app in src folder with create-nuxt-app src
  2. Choose the package manager Npm
  3. Choose UI framework Vuetify.js
  4. Choose rendering mode Universal (SSR)

Create a Firebase Project

  1. Create a Firebase project with firebase init
  2. Select Firebase Hosting, Firebase Functions, Firebase Firestore, Firebase Storage, Emulators
  3. Use public directory? (public)
  4. Configure as a single-page app (y/N) - Yes

Create a package.json file in the root folder

{
  "name": "test-nuxt",
  "version": "1.0.0",
  "description": "My fine Nuxt.js project",
  "author": "Alex Pilugin",
  "private": true,
  "scripts": {
    "postinstall": "cd functions && npm install",
    "dev": "cd src && npm run dev",
    "start": "cd src && npm run dev",
    "serve": "NODE_ENV=development firebase serve",
    "build": "cd src && npm run build",
    "build-deploy": "firebase deploy --only hosting,functions",
    "build-deployf": "firebase deploy --only functions",
    "build-deployh": "firebase deploy --only hosting"
  },
  "dependencies": {
    "nuxt": "^2.0.0"
  },
  "devDependencies": {
    "@nuxtjs/vuetify": "^1.0.0"
  }
}

Project Folder Structure

Edit firebase.json file

{
  "functions": {
    "source": "functions",
    "predeploy": [
      "rm -rf functions/nuxt && npm --prefix src run build && mkdir -p functions/nuxt/dist && cp -r src/.nuxt/dist/ functions/nuxt/dist && cp src/nuxt.config.js functions/"
    ]
  },
  "hosting": {
    "public": "public",
    "predeploy": [
      "rm -rf public/* && mkdir -p public/_nuxt/ && cp -r functions/nuxt/dist/client/ public/_nuxt/ && cp -a src/static/. public/"
    ],
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "function": "nuxtssr"
      }
    ]
  },
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "storage": {
    "rules": "storage.rules"
  }
}

You can see that I plan to copy content of the src/.nuxt/dist/client into the public/_nuxt folder. I am doing it since I found "publicPath": "/_nuxt/" inside of the src/.nuxt/dist/server/client.manifest.json

Nest Step is editing of the functions/index.js file

const functions = require('firebase-functions');

const { Nuxt } = require("nuxt");
//const { Nuxt } = require("nuxt-start");

const config = {
  ssrLog: true,
  dev: true, // Don't start in dev mode.
  debug: true, //<----------------------- Debug logs
  buildDir: "nuxt",
  build: {
    //publicPath: ''
    //publicPath: '/_nuxt/',   //Default: '/_nuxt/' <-- content of .nuxt/dist/client
    /*
    ** You can extend webpack config here
    */
    extend ( config, { isDev, isClient, isServer } ) {
      if ( isServer ) {
        config.externals = {
          '@firebase/app': 'commonjs @firebase/app',
          '@firebase/firestore': 'commonjs @firebase/firestore',
          //etc...
        }
      }
    }
  }
}

const nuxt = new Nuxt(config);

let isReady = false;

async function handleRequest(req, res) {
  console.log("nuxtssr is running...");

  if (!isReady) {
    console.log("isReady: " + isReady);
    try {
      console.log("waiting for nuxt.ready().......");
      isReady = await nuxt.ready();
      console.log("nuxt is ready");
    } catch (error) {
      console.log("ERROR.....................");
      console.log(error);
      //throw new functions.https.HttpsError('error in Nuxt', error);
      process.exit(1);
    }
  }
  console.log("waiting for nuxt.render().......");

  /*
  * res.set('Cache-Control', 'public, max-age=1, s-maxage=1');
  * await nuxt.render(req, res);
  */

  res.set("Cache-Control", "public, max-age=300, s-maxage=600");
  return new Promise((resolve, reject) => {
    console.log("before nuxt.render......");
    nuxt.render(req, res, promise => {
      console.log("inside nuxt.render......");
      promise.then(resolve).catch(reject);
    });
  });
}

exports.nuxtssr = functions.https.onRequest(handleRequest);

I use $ npm start to launch the application locally:

Nuxt.js v2.12.2                           
Running in development mode (universal)   
Listening on: http://localhost:3000/

I deploy the application using $ firebase deploy command but I cannot see any Frontend. My application is hanging. nuxtssr is hanging

Upvotes: 2

Views: 1581

Answers (1)

morphatic
morphatic

Reputation: 7975

From my understanding, firebase hosting is only for static files. If you're trying to do SSR, that implies that there's a server running and some processing happening on the server side. You may need to deploy this to Google Cloud Functions as a "serverless" app. Take a look at this tutorial for an example.

That said, I'm not super familiar with Nuxt, but I can see two things you potentially need to do differently if you are, indeed, deploying to the correct place.

First, the hosting.public property in firebase.json should be the path to the folder that contains your built project. Since you've said your project is being built in public/_nuxt, you might need to change this property to match, i.e. in firebase.json have

{
  ...
  "hosting": {
    "public": "public/_nuxt",
    ...
  },
  ...
}

For what it's worth, in regular (i.e. non-Nuxt) Vue projects, the project gets built in the dist/ folder, so in my firebase.json file I have "public": "dist". That said, I haven't ever hosted a Nuxt SSR project on firebase so this may not be how it is structured.

Second, you likely need to run nuxt build or nuxt generate before you run firebase deploy so that the project is built to the target directory. The firebase deploy command really is just a fancy way to upload files onto Google's platform.

Hope this helps!

Upvotes: 0

Related Questions