Skip to content
This repository has been archived by the owner on Feb 19, 2022. It is now read-only.

l1qu1d/quasar-v2-ssr-firebase

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

DEPRECATED & ARCHIVED

Newer versions of Quasar should have this problem resolved. See: quasarframework/quasar#9411 (reply in thread). Since the release of this repo, I've moved on to a different framework and haven't tested any newer versions from the inital repo release.

If the issue is still valid, please raise an Issue on the official Quasar repo.

If for some reason you're still using this version of Quasar, be aware that this repo may have packages that have security issues. Be sure to run npm audit for more information.

Welcome

This repo is to help you get setup to host your Quasar V2 SSR ExpressJS project on Google's Firebase! You can fork, download, or follow the steps below to get instantly setup. The files in this repo are the exact steps shown below.

Warning

You WILL HAVE TO EDIT .firebaserc TO YOUR FIREBASE PROJECT NAME!

TLDR;

The quick and dirty is that module.exports in the ssr/index.js file is blocking exports.handler for some reason. I've tried all sorts of different ways to make it work and this was the only solution that worked for me. As future versions come out, this may change so be warned, this could be out of date.

You will have to edit the compressed code that is generated from quasar build -m ssr, mainly the ssr/index.js file. Unfortunally we have to edit this file because we couldn't do it via the middlewares folder in src-ssr in our Quasar project (e.g. the files that were created when you quasar m add ssr. The middlewares file render.js has replaced index.js in Quasar v1. Read about Quasar SSR Upgrade Guide.

TLDR; Steps

  1. Remove module.exports = n from ssr/index.js because it blocks us from exporting our handler function!
  2. Then we can add our handler function, exports.handler = m, in the IIFE (Immediately invoked function expression) where they had to "use strict".
  3. NOTE: Your variable names my be different because of the compression. For example, your exports.handler = m might be something like exports.handler = h instead.
  4. The end of your index.js file should look something like this:
    m.use(f("/"), q(".")),
      ((P = {
        app: m,
        resolve: {
          urlPath: f,
          root() {
            return (0, e.join)(h, ...arguments);
          },
          public: b,
        },
        publicPath: "/",
        folders: { root: h, public: g },
        render: (e) => y(e, d()),
        serve: { static: q },
      }),
      Promise.all([
        Promise.resolve().then(t.bind(t, 660)),
        Promise.resolve().then(t.bind(t, 100)),
      ]).then(async (e) => {
        const r = e.map((e) => e.default);
        for (let e = 0; e < r.length; e++)
          try {
            await r[e](P);
          } catch (e) {
            return void console.error("[Quasar SSR] middleware error:", e);
          }
      }));
    exports.handler = m;
  })();
})();

Technologies

Setup

Folder Structure

  1. your-project-folder
  2. your-project-folder/firebase
  3. your-project-folder/quasar

Firebase commands

Firebase Functions

In command prompt or your favorite terminal.

  1. cd your-project-folder/firebase
  2. npm install firebase-functions@latest firebase-admin@latest --save
  3. npm install -g firebase-tools
  4. firebase init functions
  5. Are you ready to proceed? (Y/n) Y
  6. Please select an option: (Use arrow keys)
    • Use an existing project
      • I will be selecting this one and if you don't have an existing one create a new one.
    • Create a new project
    • Add Firebase to an existing Google Cloud Platform project
    • Don't set up a default project
  7. Select a default Firebase project for this directory: (Use arrow keys)
    • example-project
  8. What language would you like to use to write Cloud Functions? (Use arrow keys)
    • JavaScript
    • Typescript
      • For me I prefer typescript
  9. Do you want to use ESLint to catch probable bugs and enforce style? (Y/n)
    • Up to you but I prefer to use ESLint Y
  10. Do you want to install dependencies with npm now? (Y/n) Y

Firebase Hosting

In command prompt or your favorite terminal.

  1. cd your-project-folder/firebase
  2. firebase init hosting
  3. Are you ready to proceed? (Y/n) Y
  4. What do you want to use as your public directory? (public)
    • Name it whatever you want but since we're going to be hosting out of our functions/ssr/www it won't matter. Just hit enter.
  5. Configure as a single-page app (rewrite all urls to /index.html)? (y/N) Y
    • This step is VERY IMPORTANT that you choose Y. We need this to rewrite to our SSR function later on.
  6. Set up automatic builds and deploys with GitHub? (y/N) N

Quasar

In command prompt or your favorite terminal.

  1. cd your-project-name
  2. quasar create quasar
  3. Project name (internal usage for dev) (quasar) Name it whatever you want. I'm going with default.
  4. Project product name (must start with letter if building mobile apps) (Quasar App) Name it whatever you want. I'm going with default.
  5. Project description (A Quasar Framework app) Name it whatever you want. I'm going with default.
  6. Author (Your Name <your@email.com)
  7. Pick your CSS preprocessor: (Use arrow keys) Whatever you want. I choose Sass with SCSS syntax.
  8. Check the features needed for your project: Choose the techologies you need. I choose ESLint and Typescript.
  9. Pick a component style: (Use arrow keys) Your choice. I use Composition API.
  10. Pick an ESLint preset: (Use arrow keys) Your choice. I use Prettier.
  11. Continue to install project dependencies after the project has been created? (recommended) (Use arrow keys) Choose whatever package manager you use. I use NPM.
  12. cd your-project-name/quasar
  13. quasar m add ssr

Build our Quasar project

  1. quasar build -m ssr

Copy our Quasar SSR files to Firebase

  1. Copy the folder your-project-folder/quasar/dist/ssr to your-project-folder/firebase/functions folder.

Add dependencies from Quasar SSR to Firebase functions

  1. Open your-project-folder/firebase/functions/ssr/package.json
  2. Copy everything in "dependencies".

Example: "dependencies": {

   "core-js": "3.15.2",
   "quasar": "2.0.3",
   "compression": "^1.0.0",
   "express": "^4.0.0",
   "vue": "3.1.5",
   "@vue/server-renderer": "3.1.5",
   "@vue/compiler-sfc": "3.1.5",
   "@quasar/ssr-helpers": "2.1.1",
   "vue-router": "4.0.10",
   "@quasar/babel-preset-app": "2.0.1"

},

  1. Paste the copied dependencies to your-project-folder/firebase/functions/package.json

Example: "dependencies": {

    "core-js": "3.15.2",
    "quasar": "2.0.3",
    "compression": "^1.0.0",
    "express": "^4.0.0",
    "vue": "3.1.5",
    "@vue/server-renderer": "3.1.5",
    "@vue/compiler-sfc": "3.1.5",
    "@quasar/ssr-helpers": "2.1.1",
    "vue-router": "4.0.10",
    "@quasar/babel-preset-app": "2.0.1",
    "firebase-admin": "^9.8.0",
    "firebase-functions": "^3.14.1"

},

Install the added dependencies

  1. cd your-project-folder/firebase/functions
  2. npm i or run install on whatever package manager you have.

Code

For editing the code I use Visual Studio Code

ESLint

  1. In your-project-folder/firebase/functions/.eslintrc.js in ignorePatterns add "/ssr" or it will try to lint the compressed ssr/index.js file.

Optional

  1. In your-project-folder/firebase/functions/.eslintrc.js comment or remove "google" in extends. In my opnion it's overly strict and creates more annoyances than maintainability.

Firebase

firebase.json

  1. Open your-project-folder/firebase/firebase.json
  2. We need to change our public location to "public": "functions/ssr/www"
  3. We need to change our rewrite from destination to "function": "ssr"

src/index.ts

This file is where you can add all of your Firebase functions. I recommened creating your functions in a different file and importing them into this file. Then you can export each one, for example:

import sendMail = require("./sendMail");
exports.sendEmail = functions.https.onCall(async (data) => {
  const returnMsg = await sendMail.send(data);
  return returnMsg;
});

  1. Open your-project-folder/firebase/functions/src/index.ts.
  2. We'll bring in our /ssr/index.js file.
  3. Then we'll have our handler function become a Firebase CloudFunction via exports.ssr.

Here's what your index.ts file should look like.

import * as functions from "firebase-functions";

// eslint-disable-next-line @typescript-eslint/no-var-requires
const ssrApp = require("../ssr/index.js");

exports.ssr = functions.https.onRequest(ssrApp.handler);

ssr/index.js

This is the compressed code that is generated from Quasar SSR. Unfortunally we have to edit this file because we couldn't do it via the middlewares folder in src-ssr in our Quasar project. The middlewares file render.js has replaced index.js in Quasar v1.

  1. Since this file is compressed we have to make it human readable(ish). If you've been following along and use prettier you can auto-format it via VS Code. If not, you can copy and paste it in an online prettier formatter.
  2. After a LOT of playing around and testing we have to remove module.exports = n because it blocks us from exporting our handler function!
  3. Then we can add our handler function in the IIFE (Immediately invoked function expression) where they had to "use strict". exports.handler = m.

The end of your index.js file should look something like this:

    m.use(f("/"), q(".")),
      ((P = {
        app: m,
        resolve: {
          urlPath: f,
          root() {
            return (0, e.join)(h, ...arguments);
          },
          public: b,
        },
        publicPath: "/",
        folders: { root: h, public: g },
        render: (e) => y(e, d()),
        serve: { static: q },
      }),
      Promise.all([
        Promise.resolve().then(t.bind(t, 660)),
        Promise.resolve().then(t.bind(t, 100)),
      ]).then(async (e) => {
        const r = e.map((e) => e.default);
        for (let e = 0; e < r.length; e++)
          try {
            await r[e](P);
          } catch (e) {
            return void console.error("[Quasar SSR] middleware error:", e);
          }
      }));
    exports.handler = m;
  })();
})();
  1. Note: If you're follwing along via the instructions only, your variable names my be different because of the compression. For example, your exports.handler = m might be something like exports.handler = h instead.
  2. Remove the listener.
.then(() => {
  const e = process.env.PORT || 3e3;
  m.listen(e, () => {
    console.log("Server listening at port " + e);
  });
});

.firebaserc

  1. If you downloaded the project you will have to change line 3 to your project name.

Testing

In command prompt or your favorite terminal.

  1. cd your-project-folder/firebase/functions
  2. npm run build this step is only necessary if you're using typescript.
  3. firebase serve this runs a local server for you to test with.
  4. In your web browser navigate to localhost:5000 and if all goes well, you should see your project running on simulated firebase hosting!

Deploy

In command prompt or your favorite terminal.

  1. cd your-project-folder/firebase/functions
  2. firebase deploy
  3. Congratulations!!! You've successfully deployed to Firebase using Quasar v2 SSR with ExpressJS!