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.
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.
You WILL HAVE TO EDIT .firebaserc
TO YOUR FIREBASE PROJECT NAME!
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.
- Remove
module.exports = n
from ssr/index.js because it blocks us from exporting our handler function! - Then we can add our handler function,
exports.handler = m
, in the IIFE (Immediately invoked function expression) where they had to "use strict". - NOTE: Your variable names my be different because of the compression. For example, your
exports.handler = m
might be something likeexports.handler = h
instead. - 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;
})();
})();
- your-project-folder
- your-project-folder/firebase
- your-project-folder/quasar
In command prompt or your favorite terminal.
cd your-project-folder/firebase
npm install firebase-functions@latest firebase-admin@latest --save
npm install -g firebase-tools
firebase init functions
- Are you ready to proceed? (Y/n)
Y
- 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
- Use an existing project
- Select a default Firebase project for this directory: (Use arrow keys)
- example-project
- What language would you like to use to write Cloud Functions? (Use arrow keys)
- JavaScript
- Typescript
- For me I prefer typescript
- 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
- Up to you but I prefer to use ESLint
- Do you want to install dependencies with npm now? (Y/n)
Y
In command prompt or your favorite terminal.
cd your-project-folder/firebase
firebase init hosting
- Are you ready to proceed? (Y/n)
Y
- 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.
- Name it whatever you want but since we're going to be hosting out of our
- 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.
- This step is VERY IMPORTANT that you choose
- Set up automatic builds and deploys with GitHub? (y/N)
N
In command prompt or your favorite terminal.
cd your-project-name
quasar create quasar
- Project name (internal usage for dev) (quasar)
Name it whatever you want. I'm going with default.
- Project product name (must start with letter if building mobile apps) (Quasar App)
Name it whatever you want. I'm going with default.
- Project description (A Quasar Framework app)
Name it whatever you want. I'm going with default.
- Author (Your Name <[email protected])
- Pick your CSS preprocessor: (Use arrow keys)
Whatever you want. I choose Sass with SCSS syntax.
- Check the features needed for your project:
Choose the techologies you need. I choose ESLint and Typescript.
- Pick a component style: (Use arrow keys)
Your choice. I use Composition API.
- Pick an ESLint preset: (Use arrow keys)
Your choice. I use Prettier.
- Continue to install project dependencies after the project has been created? (recommended) (Use arrow keys)
Choose whatever package manager you use. I use NPM.
cd your-project-name/quasar
quasar m add ssr
quasar build -m ssr
- Copy the folder
your-project-folder/quasar/dist/ssr
toyour-project-folder/firebase/functions
folder.
- Open
your-project-folder/firebase/functions/ssr/package.json
- 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"
},
- 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"
},
cd your-project-folder/firebase/functions
npm i
or run install on whatever package manager you have.
For editing the code I use Visual Studio Code
- In
your-project-folder/firebase/functions/.eslintrc.js
inignorePatterns
add"/ssr"
or it will try to lint the compressed ssr/index.js file.
- In
your-project-folder/firebase/functions/.eslintrc.js
comment or remove"google"
inextends
. In my opnion it's overly strict and creates more annoyances than maintainability.
- Open
your-project-folder/firebase/firebase.json
- We need to change our public location to
"public": "functions/ssr/www"
- We need to change our rewrite from destination to
"function": "ssr"
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;
});
- Open
your-project-folder/firebase/functions/src/index.ts
. - We'll bring in our
/ssr/index.js
file. - 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);
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.
- 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.
- After a LOT of playing around and testing we have to remove
module.exports = n
because it blocks us from exporting our handler function! - 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;
})();
})();
- 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 likeexports.handler = h
instead. - Remove the listener.
.then(() => {
const e = process.env.PORT || 3e3;
m.listen(e, () => {
console.log("Server listening at port " + e);
});
});
- If you downloaded the project you will have to change line 3 to your project name.
In command prompt or your favorite terminal.
cd your-project-folder/firebase/functions
npm run build
this step is only necessary if you're using typescript.firebase serve
this runs a local server for you to test with.- In your web browser navigate to
localhost:5000
and if all goes well, you should see your project running on simulated firebase hosting!
In command prompt or your favorite terminal.
cd your-project-folder/firebase/functions
firebase deploy
- Congratulations!!! You've successfully deployed to Firebase using Quasar v2 SSR with ExpressJS!