The tech stack powering Boxy 2, one of the most successful web wrappers for the Mac

By Francesco Di Lorenzo

After one year of work we have finally launched Boxy 2 and I thought it would be nice to write a post detailing the tech stack powering it and its evolution with respect to the first version of the app.

Boxy is a macOS wrapper for “Inbox by Gmail” that has seen incredible success in the past 18 months in the Mac App Store, reaching more that 20k paid downloads with a growing and engaged user base.

We think 99% of this success can be attributed to the incredible job did by the Inbox team at Google, nonetheless our effort to bring Inbox to the Mac as a native app has really resonated with some users and we are really grateful for that.

The native app

Boxy’s black theme

On the client side Boxy is built using AppKit, the official Apple framework for Mac apps. When we started building Boxy, Electron wasn’t nearly as famous as it is today (used at Slack and many other successful teams), but we stand by our choice. The biggest advantage of not going with Electron has been the smaller binary size (Boxy is just 6MB, more than 10 times smaller than the average Electron app) and the faster startup time. The disadvantage of course is that we cannot easily support multiple operating systems, but, as a team of two with just one developer, I think it was best to just focus on the Mac.

Venturing a little bit more in the details, the core experience of Boxy is achieved using a WKWebView (Apple’s newest API for web rendering), highly customized with features and themes implemented in JavaScript and CSS to bridge the gap between a browser and a native macOS app.

Most of the unique features of Boxy like reader mode and themes required some interaction between the native app and the web counterpart. This has been done with the excellent WKWebView APIs that allow bidirectional communication between the web view and the native app, with out-of-the-box bridging of objects between Javascript and Objective-C.

Javascript and CSS, where the magic happens

For what regards the deployment of these features we decided not to bundle the JavaScript inside the app, but to download it at runtime. This was necessary as the Inbox team is constantly tweaking the app and this occasionally breaks some of our features. This is not a problem as we can usually deploy a fix within hours without (almost 😅) anyone noticing.

To do this we have a separate repo containing all the JavaScript code, with scripts to build the JavaScript and CSS, resulting in a single file that could then be loaded inside the native app to customise the experience. Initially, it was a custom-made system that served us well, but quickly showed its limit. With version 2, we moved to a smarter solution leveraging the power of Browserify, that does what our custom system did but with an higher degree of flexibility. We host the file resulting from this build pipeline on Amazon S3, which has been embarrassingly cheap and reliable (we pay ~2$/month).

Programming against a moving target while providing the best possible user experience

Chrome Headless connecting to Inbox to verify that everything that we rely on is still there

As I mentioned before, the Inbox app is constantly changing and this sometimes breaks Boxy. To be fast to react to these changes, we have developed a system called boxy-checker, with Chrome Headless and Puppeteer.

It runs on a Debian VM, hosted on Linode (we use the base plan, which is incredibly convenient) and continuously checks that all the elements of the page on which we rely to implement some cores features are still there. We use Facebook’s Jest (an awesome testing library) and their snapshots feature to do this.

When something is wrong, we get a notification on our #emergency Slack channel and we rush to work. This makes it easier to fix issues before the first support ticket hits our ZenDesk 🙌

If you enjoyed this post and would like to try Boxy, you can learn more on the official site or on the Mac App Store.

Like what you read? Give Boxy a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.