Friday, December 23, 2011

Reusing HTML/CSS/JS across Web & Mobile

At this point, there's only one of me working on EatDifferent. That's awesome because it means I get to learn everything about what it means to make a user-facing website, but it also means that I need to be careful about where I spend my time, since it is such a precious resource.

When I started it, EatDifferent was a web-only service, but I soon realized that when it comes to tracking your daily habits, users really want to be able to track on the go, from their mobile device. I realized I needed a real strategy for how I could offer it as a website, mobile-optimized website, and as multi-platform mobile app while keeping them all up-to-date and still having time to iterate on the core functionality. So I decided to find a way to reuse as much of my code across those offerings as possible. Here's how I do it:

Basic setup

Datastore

When a user logins in, I store their authentication in a session cookie. From then on, either my web app or mobile app can make XMLHttpRequests to fetch or save information for the user. In the mobile app, the calls are made over SSL (and in case you're wondering, the cross-domain restrictions aren't applied to files in Phonegap apps so that is not an issue).

HTML

The Flask microframework comes bundled with support for Jinja2 templates (like Django templates but better) so that's what I use for server-side templating in my web app. I mostly use the templates for includes/inheritance and not for variable rendering, as then I can keep my logic in JavaScript, making it easier to re-use that logic in the mobile app. For example, log.html extends from a base HTML and includes Jinja2 templates for the log sections.

I wanted to reuse much of the same HTML in my mobile app, so I use the Jinja2 template engine for it as well. My mobile app is actually one single HTML page, where each "page" is a DIV with a .mobile-page class, and many of the "pages" include Jinja2 templates (the same ones that are used by the web app). After I make changes to the base HTML or templates, I test them in a browser (using a Chrome extension to mimic a small screen), and then when I want to output them to a device, I render the templates using a script and copy them to the Android/iOS app folders.

CSS

I start off with Twitter Bootstrap for my CSS, because it makes for a slick but easy-to-customize foundation. I then use SASS for writing my own CSS rules, as I can write cleaner cross-browser CSS that way and can also do things like includes. I define my shared styles and variables in common.scss, and include that in web.scss (for the web app) and phonegap.scss (for the mobile app). I use CSS media queries in both common.scss and web.scss to define rules for smaller screens &emdash; some of those rules apply also to the mobile app, but some just to the web app.

JS

As I mentioned in an earlier post, I recently refactored my JavaScript to make it easier to share logic across the web and mobile app. I now have a shared.js for shared functionality, a web.js for web-specific functionality, and phonegap.js for mobile-specific functionality (makes sense, doesn't it? :). Since I also use different JS libraries across the web and mobile app versions, I use different rules in my Makefile to generate the final compressed JavaScript for the web and mobile apps.

Summary

Here's a Venn diagram that summarizes what's different and what's shared:

And here are screenshots comparing the log on the web versus in the mobile app:

I suspect that my HTML/CSS/JS for the mobile app version will diverge more as I try to make the app conform more to the expectations of mobile users (and iPhone users in particular), but I still like the idea of reusing as much of my code as I can. The less time I spend writing redundant code, the more time I can spend adding features and improving the EatDifferent service for all my users.

No comments: