Light My Firebase

Last month, I finally carved out some time to build my own personal website.  Way overdue- but anything I create instantly looks like a pile of crap, so I usually end up spending way too much time trying to tinker with the look.  What I really love is making things work.

I used Angular to continue practicing that framework- particularly with the new animations module.  It’s pretty fun and easy to use.

I decided to host on Google’s Firebase platform.  I always thought it was just a real-time database, but now they offer content hosting as well.  With their tools you can install locally, it makes deploying super easy (as in: type “firebase deploy” level easy).

But what about a backend?  I wanted a simple contact form, so I’d need a backend to process the email sending (submissions would also be stored in the real time database).  I love writing Node- but most of my experience so far has been with Express- I wanted to get into the basics.  http, fs, dns, etc (that last one isn’t a module, don’t try to require it into your project)- all very useful and all native to Node.  My first thought was to just make a simple node backend with just a couple endpoints: one for sending email (using the awesome nodemailer library) and one for returning all routes to the root (to serve my Angular project).

However, Firebase hosting doesn’t work like that.  It’s not so much a backend hosting as a serverless architecture.  Please note: I may be using that term incorrectly.  In this case, it just means that you don’t use http.createServer and listen for request events.  Nor do you import express and build an awesome rest API.  With Firebase hosting, you use functions.

And those functions really are basically just simple Javascript functions.  In your app’s main folder, create a functions folder.  You can have multiple files, but be sure to have an index.js file.  This is where you can require other modules- or if you’re just making a simple function (like mine to send email), insert your backend code there.

You will also have a package.json in your functions folder (I believe Firebase creates this for you when you initialize their Functions option)  It will have a few dependencies by default (firebase-admin so you can authenticate your app and firebase-functions so you can register your functions).  You can add other Node modules here as well- I added nodemailer.  These become available as ‘require’ able in your index.js.

I created my email sending function- most of it is configuring the sending options and the template for the email content, as well as some nodemailer related config.  The content isn’t important- it’s just titled sendFormHandler.  Once it’s done, I just register it with an event on my database (in this case, saving a new contact on form submission):

exports.sendFormViaEmail = functions.database.ref('/form_submissions/{pushId}').onWrite(event => {
    const newSubmission = event.data.val();
    
    return sendFormHandler(newSubmission.name, newSubmission.email, newSubmission.content);
});

exports is just a shortcut for module.exports. functions is a reference to require(‘functions’).  I grab a reference to the data (the event is the database write, the data.val() function gets the object submitted.  Then I can pass that info to my simple sendFormHandler and off we go!

I’ll still stick to writing backend code for more complex applications, but this serverless thing is pretty cool (if that’s what this qualifies as).  One mistake I made you might avoid with Firebase: double check the path you provide to functions.database.ref.  Initially I was passing just ‘/form_submissions’ – the endpoint I use for saving new submissions.  However, this gets all entries in the form_submissions object (I almost said ‘table’, but this is not sql!).  I spent more time than I want to admit logging the return value from that endpoint, trying to figure out how I could get a diff of the previous object and the updated object to single out the new one.  I found a property: event.data._delta that showed the new object, but the pushId is randomly generated, so I couldn’t figure a way to reliably select just that object.  However, adding ‘/{pushId}’ to the end of the url you pass takes care of all that for you.  It gets the most recent entry by that unique pushId- very useful! only new addition, but had trouble accessing properties (pushId is randomly generated).

Advertisements

Google on the go

As I’m sure everyone knows, google recently changed it’s search ranking algorithm to take ‘mobile-friendliness’ into account.  Sites that pass their test will be bumped up (or, at least, not penalized).  It seems like a good idea- and gave us the push we needed to finally start upgrading our system to play nice with today’s mobile devices.

Our system was originally created in 2002-2003, and it really is quite good.  But back then, people just didn’t (very often) view websites on their phones.  You simply didn’t (really) have to account for screen width, horizontal scrolling, etc.  It would be nice to take this opportunity to completely rewrite the layout of the system, switching to floats and divs and all that nice stuff, instead of using tables for layout (I know, we suck).  But there just isn’t time for that right now, so the order of the day shall be shoehorning media queries into the existing structure.

And it’s going ok so far.  Got the width and font size changes down, reduced image size to 100% max, and even found an easy way to reduce the size of a Google Map (many are embedded in our system’s sites) down to the correct width (just grab the css tag for iframe and make it 100% max).  We’re finishing up with a nice mobile menu that folds down/up and will integrate with the existing menu items already created (though it only works for the vertical menu option for now).

The main issue is due to the fact that we’re just too lazy to rewrite the structure to remove tables right now.  Depending on how a client has set up their site, we used php variables to determine the colspan of different table columns.  For example, if they have a logo (upper left of screen) and header (top middle/right), but are using the horizontal menu layout (which spans the full screen width), the main body text and footer both have a colspan of 2.  But switching to mobile rearranges it so everything is one column- the logo is hidden to save space and the image is moved into the header area.  Mostly works, but still leaves an odd ‘cut off’ section because the table still expects colspan=2 at that point.

Haven’t quite figured out that one yet, but once we do, we’re about home free (with stage 1, anyway).