When I joined Reflectly eight months ago, I was tasked to recreate a subset of our Flutter app — but for the web.

Our initial goal was to implement basic account functionality with support for payments and discount codes. This would improve the experience for new users signing up via referral links. The long-term plan was to have a 100% feature parity with our existing mobile app.


A screen capture of our onboarding flow for web, written in AngularDart — featuring wonky icon fonts.

A screen capture of our onboarding flow for web, written in AngularDart — featuring wonky icon fonts.

Thanks to our relatively clean architecture, I could reuse most of our existing code from our core package. This meant that most of the work in creating the web app went into building the HTML/CSS-based UI layer in AngularDart.

One of the bigger tasks was to rebuild our UI component library from scratch. This included elements such as buttons, text inputs, cards, shadows and a flexible system for common animations and interactions.

Our tactile component in use with a button with inset shadows and touch feedback.

Our <tactile> component in use with a <button> with inset shadows and touch feedback.

To put it briefly, I spent a lot of time rebuilding what we already had in our mobile app but for the web — two months to be exact.

I also had to cut corners in terms of the more complex animations and overall visual beauty. The deadline was approaching fast, and I already had my hands full trying to vertically center divs in CSS.

You can’t always get what you want…

I wanted to take the full Reflectly experience to the web. Some of our users had been requesting it too.

While AngularDart is an excellent framework, spending two months on rebuilding what we already had seemed kind of a wasted effort. Especially if you’re a team of three engineers, out of which only two do frontend.

Our simplified AngularDart web dashboard.

Our simplified AngularDart web dashboard.

We launch new features, bug fixes and experiment with new designs and features every week. It can be very time consuming to build the UI with Flutter first and then vertically center divs with CSS for the web later.

The reality was that we didn’t have the resources to continue bringing Reflectly for the web at the time. We decided to freeze our web development efforts until our situation improved.

…or can you?

Shortly after releasing our AngularDart web app, the first Flutter Live event was held at the Science Museum in London.

At Flutter Live, the Flutter team announced Hummingbird, which was later rebranded to Flutter for web. A couple of months later, I got an invite to try out the early preview of Flutter for web.

Which one is web? Our onboarding flow, written in Flutter — running on iOS and Chrome.

Which one is web? Our onboarding flow, written in Flutter — running on iOS and Chrome.

Being quite excited, I grabbed four beers from the nearby supermarket and went back to our office. Before finishing the last beer, I had our existing codebase (written in Flutter) running on a new platform — the web.

Being able to ship on Android and iOS with a single codebase was one thing, but being able to run it on the web too is quite something else.

Our complex statistics screen, also written in Flutter, running on as a native Android app and in Chrome.

Our complex statistics screen, also written in Flutter, running on as a native Android app and in Chrome.

(Sidenote: during the EAP, the gzipped Javascript file for our app was just about 190kb. It might get smaller in the future, for example with the upcoming non-nullable types for Dart.)

We also did a quick test on how larger layouts would work with Flutter for web and what it would require to adapt to different screen sizes.

Our statistics page made adaptive, in less than three hours.

Our statistics page made adaptive, in less than three hours.

Since our statistics page is composed by laying out several smaller custom widgets on the screen, we can just arrange them differently for desktop.

From initial design handoff to making our statistics page adaptive, it took only three hours of work. Since Flutter has support for adapting to different screen sizes, it’s easy to create container layouts that work for both mobile and web.

The best kind of code is no code

Our AngularDart web app has almost 6000 lines of code.

That might seem small (and it is) but keep in mind that it’s just 5–10% of the features that we have in our Flutter app. That’s 5659 lines of code that I don’t want to maintain and I would be thrilled to throw away.

Lines of code in our AngularDart web app, counted with cloc.

Lines of code in our AngularDart web app, counted with cloc.

My urge to delete all the web-specific code is not because of AngularDart. I actually quite like it. What I don’t like is doing the same work twice.

With our current setup, we have just about 40% code sharing. The remaining 60%? That’s platform specific code in our Flutter and AngularDart apps.

“I just love maintaining two separate codebases that do the same thing!” — said no one ever.

Less web-specific code means fewer web bugs; no web-specific code means no web bugs. At least in the ideal world.

A couple cases of “we’re not there yet”

There are some minor speed bumps in the road preventing us from taking Reflectly to a web browser near you.

No gRPC-web support for Dart (yet)

We are very happy users of gRPC in our Flutter mobile app — every single API call is made with protobufs and gRPC goodness.

Although not Flutter for web specific, one of the most pressing blockers for us is the lack of gRPC-web support for Dart.

The issue ticket for gRPC-Web support has been open for some time in the gRPC-dart repository.

The issue ticket for gRPC-Web support has been open for some time in the gRPC-dart repository.

Although it’s possible to generate a Dart wrapper over the regular gRPC-web library using the TypeScript definitions, that’s not a road we want to take in the long term.

Lucky enough for us, there’s some good progress on the way.

No plugin support for the web (yet)

We are currently using about ten plugins in our Flutter app, but none of them will run on a web browser just yet. This is because there is no web plugin support in Flutter for web as of today.

Once the support is there, we expect those web implementations to come up for most of the existing plugins. While most of them will be easy to migrate, more complicated ones such as sqflite will take a longer time.

Not locking ourselves down

While we are very excited about the current state of Flutter for web, we don’t want to bet our business in an early technology preview.

Flutter on mobile is very forgiving regarding performance. We’re not yet sure if it will be the same story for Flutter for web. According to the Flutter for web README, “performance work is only just beginning”.

So far, we’ve seen that our statistics page has some perceivable lag on bigger screens when the graph animations are running. Time will tell if there are some low-hanging performance fruits up for grabs.

An overly simplified diagram of our current codesharing setup. If Flutter for web doesn’t work out for us, we can continue our AngularDart codesharing efforts.

An overly simplified diagram of our current codesharing setup. If Flutter for web doesn’t work out for us, we can continue our AngularDart codesharing efforts.

We are also worried about how natural Flutter for web feels on each respective platform. Will it feel too much like Adobe Flash, and if it does, is that a problem for our users?

Thanks to our relatively clean architecture, we are not tied into Flutter for web. If for some reason, we decide that it’s not a good fit for us, we will continue our codesharing efforts with AngularDart and build our web UI separately with the native web stack.

“Await-ing” on a very exciting Future

As a small team of three engineers, we couldn’t be more excited about the future of Flutter.

We jumped on board quite early with our Android and iOS apps — and we couldn’t be happier about it. More importantly, our users are extremely happy too. Our app is constantly getting solid five-star ratings and positive reviews.

Our cute little mascot hanging at the very top of Health & Fitness in the US App Store.

Our cute little mascot hanging at the very top of Health & Fitness in the US App Store.

We’ve also recently been lucky enough to hang out with brands like Calm, Headspace and Fitbit in the top ranking apps of the Health & Fitness category.

Using Flutter for mobile has been the best technical decision we’ve made. We can’t wait to say the same about Flutter for web.