Index Of /

Sapper and Firebase

May 30, 2019

SSR on the Firebase Hosting

To deploy this blog to the Firebase Hosting I found a great article from @eckhardtdreyer:

How to host a Sapper.js SSR app on Firebase.

Just follow the instructions and you'll have a working svelte/sapper and server-rendered website in a few minutes.

Importing Firebase

The only problem I've got was Firebase library itself. When imported it for the first time:

~/project/firebase.js
import firebase from "firebase/app"; 
...

in the terminal the following message appeared:

[2019-05-30T15:25:08.981Z]  @firebase/app:  
Warning: This is a browser-targeted Firebase bundle but it appears it is being
run in a Node environment. If running in a Node environment, make sure you
are using the bundle specified by the "main" field in package.json.
...

Have to tell you right away, that using `rollup-plugin-node-resolve` to switch to `main` leads to enormous pile of errors for a lot of packages. And I didn't realize how to solve it.

Server vs. Client

Client only

The first solution that came to my mind was to use Firebase client only. But that was not the case. Why use SSR for the blog if posts are loaded on the client after the initial rendering?

Full Firebase SDK

Second solution was to import the whole Firebase SDK:

import firebase from "firebase";

In this case almost everything is working smooth, but the size of the main chunk served to the users went up to 256 KB. And I wanted the size of the app to be as small as possible.

require() for the server

The best solution I found so far is to modify the firebase init script: import the client version and then check if it's a server (no window object) load the full Firebase API using CommonJS' require(). Since bundle size on the server is not so critical and require is synchronous, everything works as expected:

~/project/firebase.js
import firebase from "firebase/app"; 
import "firebase/firestore";

const firebaseConfig = {
// firebase config object
}

function initFirebase(config) {
if (typeof window === "object") {
return firebase.initializeApp(config);
} else {
const fb = require("firebase");
return fb.initializeApp(config);
}
}

const app = initFirebase(firebaseConfig);

// returning firestore handle
export const firestore = app.firestore();

Final deployment

If you have troubles when deploying cloud functions, you should add firebase as a dependency to the functions directory and deploy it from there:

cd ./functions 
npm install firebase --save
npm run deploy

And here we are. Everything is working as expected and the size of the chunk with firebase went down to 112 KB from 256 KB (gzipped)!

Still thinking about getting rid of the firestore and use realtime database like REST API, but for now that's enough

Andrey “Leechy” Lechev

Some frontender thoughts
Twitter, GitHub, LinkedIn