Creating a Browser UI using Web Technology

From a UI standpoint, we’re using modern techniques for frontend development. We’re not the first to do this by any means. Browser.html, Vivaldi, Min and many others have beaten this path. In many ways Firefox itself is a precursor to this way of doing things if you squint and pretend that XUL is a widget library for HTML.

JavaScript modules and Webpack’s filesystem watching have made for quick iteration cycles, and it means we can use ES.next through Babel. This led to a world where we could write very maintainable code thanks to async/await, classes, standard imports/exports etc, all while just using F5 to reload the whole browser just like one would in a normal webpage. Hot module reloading was also useful while writing state-dependent code, like our “overview page summaries”.

We’ve chosen React and Redux for writing our UI and managing our application state. We found it good for easily writing maintainable code and quickly prototyping different views and the interactions between them. Compared to the XUL code that much of Firefox uses we think that React+Redux strongly encourages multiple developers to code with a unified style and means that our views, stores and actions are immediately alterable by someone unfamiliar with the codebase.

We discovered that we needed to be proactive about performance by automatic testing and/or careful reviews.

Furthermore, developing with React outside of the standard predefined and essentially carefully tailored environment of a web page was difficult at times. Managing non-standard DOM nodes that required non-standard attributes was unfriendly, and required either us writing custom wrappers, special prefixing with “data-”, or hacking our way through using the magical “is” component property. Subsequently this led to potential confusion due to component properties not being magically massaged anymore when they were mapped to DOM attributes: for example “className” had to be written as “class” instead, leading to easily fixable but frustrating bugs. Therefore the biggest problems in this department arose when having to deal with <webview> nodes in Electron.

Strictly adhering to the Redux model in Electron was also difficult. Single-store application state assumes a single process per application. When writing a web browser (in Electron or otherwise), dealing with multiple processes is a necessity, so the easy abstractions and “best practices” that worked in webpages were, in practice, much harder to respect. This led to an initial architecture where there were multiple application states, one for each process, with communication happening over IPC. Our final approach was to try and mimic the web and use web sockets in order to synchronize the multiple application states: after all, synchronizing multiple instances of the same application written in React and Redux is a known problem on the web and multiple solutions exist. However, it is still not clear which is the best way to handle this issue.