DEV Community

David Haley
David Haley

Posted on

Kotlin in the browser: attempting Firebase + Multiplatform

I started using Kotlin to write browser apps about 1.5 years ago. It's definitely an early adopter experience. It worked well for a non-trivial but basic app. For the next frontier, multi-platform development with Firebase, I got stuck.

Since then, I've largely completed my basic needs for You Need a Splitter: an app that integrates with You Need a Budget to speed up my budget splitting workflow.

In parallel I also wrote ReservationsApp in Typescript with Angular, using Firebase. This gave me a baseline for comparison.

YNAS was written with KVision, an object oriented web framework for Kotlin/JS. I was able to develop a non-trivial app: multiple components, dialog boxes, asynchronous interaction… All in all, it was a good experience.

At first I struggled with state management (understanding which changes did/didn't trigger reactive renderings). I found Angular's state management clearer– although, Angular has changed so much & so fast, some community content is obsolete. (On that note, the KVision community is much smaller.)

One example is using arrays: is it changing the array, or its contents, that triggers a re-render? And how do you avoid tearing down & rebuilding elements that didn't change, if you react to the list reference changing?

There were also rough edges around exact DOM interaction. Here's an example where a component re-render wasn't updating FontAwesome icons. I needed to use a special unique DOM key so the buttons' icon changes would take effect.

An interesting side quest: to use the YNAB javascript SDK in Kotlin, I needed to generate Kotlin type declarations. I wrote a quick README with some notes. TLDR, I used dukat to generate the declarations but had some manual work to do.

All in all: I thought it was a success 😤 My main regret though was not accomplishing the multiplatform vision. Running YNAS on a mobile app would require a UX rewrite. 😩

Emboldened by this experience I wanted to tackle that more ambitious project: a Kotlin-Multiplatform app backed by Firebase.

Attempt: a multiplatform Firebase app

I'm building a financial planning application. YouNeedABudget is great for understanding where your money went, and allocating it to future goals. But it doesn't help me plan for the future in bigger ways: asking what-if questions like buying with cash vs financing a purchase.

The UX would center on charts: projecting cash flow scenarios, that sort of thing.

Why Firebase? Two reasons: serverless, and realtime data access. I really don't want to maintain (or pay for) servers but I do need data accessible beyond my laptop. The realtime data is a delightful cherry on top: the reactive rendering loop is built on shared data, not just local state.

I was encouraged by GitLive's Firebase Kotlin SDK … at first glance, it was exactly what I need: a multiplatform Kotlin library.

Now for the UX framework. The Compose-Multiplatform framework's big promise is to support "all" targets: web, desktop, iOS, and Android.

Compose-Multiplatform supports web through WASM, not regular Javascript (transpiled from Kotlin to be indistinguishable from normal javascript apps).

The WASM build has some caveats (I discussed in my previous post). But if it meant one codebase for all platforms, I was willing to bet on WASM's future development.

Then I needed a charting component. I settled on KoalaPlot which has a variety of plots, various customization options, and ongoing development.

Result: defeat

Alas– I got "this" close but not close enough.

I was able to build a HelloWorld app running on all platforms (well, I didn't test iOS, and only ran Android on the emulator). Here it is running on web (after PR#3):

Chart showing a line incrementing upwards

So far so good…! I even got hot-reload working for desktop, a major development cycle speedup.

Then I tried incorporating the GitLive Firebase SDK … I hit a hard wall and the magic ended. 😮‍💨
It doesn't support WASM (issue #440).

But it does support Kotlin/JS, meaning a Kotlin project transpiling to Javascript could use GitLive's Kotlin Firebase SDK.

However– that meant getting Compose itself running for Kotlin/JS. I gather it's possible…? Or at least, at some point of the experimental lifecycle of Compose-for-Web, Compose-HTML, and other library evolutions, it was maybe possible to do some things.

KoalaPlot itself also referenced Kotlin/JS so I was hopeful that I could convince the pieces to work together.

… No.

I got a Compose app compiling, but it was unable to find various font rendering functions at runtime. I went down a rabbit-hole of preloading custom emoji fonts, an apparently related but actually different set of problems. I had to downgrade from material3 to material to get it compiling. The problems piled up but solutions did not.

My conclusion was, if I want Firebase, I can't have WASM. And if I can't have WASM, then I can't have Compose. And if I can't have Compose, then I can't build a UI toward multiple targets. Sad…

What's next

At this point, I don't have great options with Kotlin:

Feature Multiplatform Kotlin/JS
Firebase
UX framework Compose Questionable

How feasible is building Firebase on Multiplatform? The discussion on issue #440 shows several attempts to get GitLive's Firebase SDK working on wasm, with only limited success (eg just the Auth library). That's great– but I need more, Firestore in particular.

In principle, I could write a multiplatform interface layer, with a WASM native implementation that calls out to the JS SDK… but no, I'm not gonna do that.

I could use the Firebase SDK on mobile & desktop– but if I have to choose those or web, I choose web. Mobile apps pose a number of distribution challenges that simply aren't worth it at this stage. Besides, a responsive web app would be ok on a phone.

Given that I'm stuck with Kotlin/JS for now– it's worth highlighting how straightforward it was to build an Angular + Firebase app with Typescript. There's no question that working within a major web app framework provides a far more integrated & seamless experience. I still prefer Kotlin 😝😭 but is it worth it?

Generally, I like my code's core framework (eg UX layer) to be battle-tested. I have limited tolerance for rough edges. 🫩

To proceed with Kotlin, I'd need to use Kotlin/JS which means sticking with KVision (I don't want to learn yet another non-Compose Kotlin+HTML framework). While KVision is fine (and I paid the learning price) the KVision developer has put recent focus into Kilua, which does target WASM working directly with the DOM no less. But it's even more cutting edge than KVision.

Could I combine Kotlin with Angular? Well, in principle Kotlin/JS means it's "just" a question of getting the build system set up correctly. Brian White wrote a StackOverflow post explaining how to do this– it's worth a try, although 2 years is "forever" in early adoption timelines. Besides, this lets Angular see the Kotlin code: I don't think it lets Kotlin code drive the Angular framework.

Final thoughts

I had high hopes for this, high enough to spend about 10 hours exploring all these rough edges. Unfortunately, at this juncture multiplatform building (mobile plus web) remains elusive. It's not enough to compile code to run on a platform: you also need frameworks to turn code into pixels, etc…

Given all this friction: is Kotlin in the browser worth it? The main advantage (besides language preference) is a monorepo that powers frontend and backend. After all: background processing needs to wrangle the same data types. What if I learned Dart/Flutter…

But today, I need to move on with my problem: visualizing my cash flow scenarios. Here's my backup option: the simplest solution, duplication. Build Kotlin + Typescript code around Firebase's data model. Make sure the data models don't get out of sync.

One day, as these frameworks mature, I'll revisit how much more I can do with Kotlin in the browser. In the meantime, my quip from Part I feels even more real:

Boromir saying: one does not simply render HTML

My goals were ambitious– perhaps one does not simply do anything. 😎

Top comments (0)