This page explains how to configure, deploy and host a website with Express on Firebase.
Note that we'll use ECMAScript with modules (import from
and export
).
I strongly recommand to understand the following concepts before reading this guide.
The guide presented on this page has been tested with the following versions:
In the following, I assume that Node.js and npm are already installed. In my case, I used Volta with which you can select a Node engine when switching between projects.
The first thing to do is to create a Firebase project. Note that to deploy functions, you need a paid plan (Blaze). In the the Firebase console page of your project, add a web app.
Create a folder on your local machine and install firebase inside:
npm install firebase
If Firebase CLI tools are not installed yet, run the following command:
npm install -g firebase-tools
Login to your Firebase account:
$ firebase login
Run the following command to configure your firebase project:
firebase init hosting
firebase init functions
Your project is configured. Let's add Express.
You don't need to install Express since it's already installed with Firebase.
But, you'll have to modify the configuration in the functions/package.json
.
First, since we use ES modules, add the following line in functions/package.json
:
"type": "module",
Check the node version in functions/package.json
and update to match your Node.js installation (node -v
to get your version):
"engines": {
"node": "18"
},
In the file firebase.json
rewrite the following URLs to the myApp
function:
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "/**",
"dynamicLinks": true,
"function": "myApp"
},
]
},
Now, create the myApp
function that will manage the route /example/
. Router.
Replace the file /functions/index.js
with the following content:
// Import Firebase functions
import functions from "firebase-functions";
// Import express
import express from "express";
const app = express();
import {exampleRouter} from "./example.js";
app.use("/example", exampleRouter);
export const myApp = functions.https.onRequest(app);
You probably noticed that the above code loads a module named example.js
.
Create the file functions/example.js
with the following content:
// Import the router
import express from "express";
const router = new express.Router();
// Route /example/
router.get("/", (req, res) => {
res.send(`<h1>Example page</h1>`);
});
// Export the router
export const exampleRouter = router;
Run the following command to start your server:
firebase serve
The command should display sometihing like:
✔ hosting[fir-express-87878]: Local server: http://localhost:5000
This is the URL of your local server. Go to http://localhost:5000/example/. If you see the following page, everything is fine:
I notice that the firebase serve
command does not always detect changes, especially in files package.json
and firebase.json
.
If you encounters issues, do not hesitate to stop and restart the firebase serve
command.
Since we use modules, it's now easy to create a module for each route.
Let's create an API that will manage dynamic routeing
Create the file functions/api.js
with the following content:
// Import the router
import express from "express";
const router = new express.Router();
// Route /api/
router.get("/", (req, res) => {
res.send(`<h1>Root of /api/</h1>`);
});
// Route /api/:id
router.get("/:id", (req, res) => {
res.send(`<h1>/api/${req.params.id}</h1>`);
});
// Export the router
export const apiRouter = router;
Update the file functions/index.js
with the new route:
// Import Firebase functions
import functions from "firebase-functions";
// Import express
import express from "express";
const app = express();
// /example/
import {exampleRouter} from "./example.js";
app.use("/example", exampleRouter);
// /api/
import {apiRouter} from "./api.js";
app.use("/api", apiRouter);
// Export
export const myApp = functions.https.onRequest(app);
Now, if you enter http://localhost:5000/api/ in your browser, you should get the following page:
More fun: you can also manage dynamic routing. Go to http://localhost:5000/api/hello, you should see:
Finally, if you go to http://localhost:5000/, you'll see that static pages are still served:
Of course, you probably wonder what happen is the same URL can be serve by functions and static hosting?
Firebase first check in the public
folder. If the page does not exist, functions are called.
Create the folder and file public/api/index.html
with the following content:
<h1>Static page</h1>
Go to http://localhost:5000/api/:
This is the static page that is served to the client.
You can download the final project on Github: