Flutter — an Angular developer’s perspective
Will it fly or should you stick to Angular?
What can you expect from this blog post?
Coming from angular, the following questions feel the most important to me:
- What is it? What is the target audience?
- What language does it use? How does it compare to TS?
- What are the differences in architecture ? Does it use components/modules?
- What template engine does it use? How’s Styling Support ?
- How good is library support ?
- Creating a basic example with buttons and navigation — how are buttons and UX handled between different OSs ?
- What is performance like?
What’s Flutter?
Flutter is an open-source mobile UI framework by Google, first released in 2017. Flutter supports iOS and Android, with beta support for the web (as of the time of writing).
The flutter system stack at a glance — Flutter Docs
An introduction to the Dart language
Have a look at the following code:
void printInts(List<int> a) => print(a);
void main() {
var list = [];
list.add(1);
list.add("2");
printInts(list);
}
At first glance, Dart looks like a weakly typed language. However, Dart uses a combination of static type checking and runtime checks to ensure that values match the variable’s type, which makes it a strongly typed language . The above code sample gives the following error:
error • The argument type 'List' can't be assigned to the parameter type 'List<int>' • argument_type_not_assignable
psst: you can play around and view the correct implementation in my DartPad . There’s also an example with the “dynamic” type somewhere in there 🤫
Like Python and Javascript, in Dart, everything is an object. Dart also contains support for sane object comparators, generics, with wasm support on the horizon . If you’d like to dive deeper, I highly recommend reading the language tour on dart.dev
You should also keep in mind that dart uses its own VM for compiling code and uses dart2js to transpile code to javascript on the web. This may make debugging in-depth issues more troublesome — especially on firefox, which does not support debugger source mapping just yet. Lazy loading is supported on the DartVM and Flutter, however, deferred loading is not there just yet .
Let’s discuss architecture
Asynchronicity
Isolates are what all dart code runs in. Each isolate has it’s own separate functions and memory and runs in a single thread loop . Isolates can only access their own individual functions and memory — this is neat because this negates the need for memory locks and makes garbage collection easier.
Many apps often stick to one isolate, but sometimes a particularly heavy flow can result in poor app performance or stuttering animations, often called “jank”. In these cases, you can have multiple isolates and communicate between them using messages. Isolates are useful when there are large computations — by using them, you can avoid frame drops on the main thread.
A visualisation of flutter isolates. Each isolate has its own thread and memory and they communicate with messages
Code structure — widgets
Flutter uses the concepts of widgets to structure your apps. Widgets are then nested to form what is known as a “Widget tree”. Each widget nests inside a parent widget and inherits properties from its parent. This tree is built by overriding the build() as we’ll see in the example below.
There are 2 types of Widgets — StatelessWidget and StatefulWidget . Stateless widgets are created once and their appearance never changes. Stateful widgets have a state which is transferrable across tree rebuilds, so it is not lost.
Data is transferred between widgets using the following architecture:
// Flutter
class CustomCard extends StatelessWidget {
CustomCard({@required this.index, @required
this.onPress});
final index;
final Function onPress;
@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: <Widget>[
Text('Card $index'),
FlatButton(
child: const Text('Press'),
onPressed: this.onPress,
),
],
)
);
}
}
...
// Usage
CustomCard(
index: index,
onPress: () {
print('Card $index');
},
)
The constructor for the CustomCard class uses Dart’s curly brace syntax { } to indicate named optional parameters . To require these fields, either remove the curly braces from the constructor or add @required to the constructor.
Templating and styling
Flutter does not use CSS and HTML but has its own internal constraint system for defining styles. It should also be noted that all values used in styling are unitless. Although the styling is done in a completely different way, the names for most styles are similar to the naming conventions used in CSS. Here’s an example from the docs:
Styling comparison between HTML/CSS and Flutter’s implementation
Writing templates is also done completely within the dart files using functions like Text instead of creating tags in HTML.
While this might seem like a major jump, it does come with some advantages :
1. By moving away from CSS and HTML, you also move away from javascript. The styling also appears to follow the same conventions, so it’s not all doom and gloom
2. There are tools to help generate widgets for you such as FlutterStudio . In the case of FlutterStudio, it works similarly to the drag and drop system on Android Studio. It also supports switching devices/resolutions, and you can also add your own Pubspecs (more on this in a bit). For more customised animations/styles, you’ll still want to build it in your own project — but it’s a great place to start.
Library Support
Flutter does not directly support npm packages . This issue can be bypassed by using web views — but this is less than ideal.
Any packages you need for flutter need to be installed from pub.dev . Libraries on the site sometimes have a “Flutter favorite” badge — be on the lookout for these badges as they “guarantee” a degree of quality by following these quality gates .
The flutter favorite badge
Adding dependencies to your app is a fairly straightforward process — you add the dependencies under the dependencies section in your pubspec.yaml and call “flutter pub get” to pull the packages. It even supports packages version ranges!
Pubspec sample
As of the time of writing, pub.dev contains 10,000 installable libraries which means it is still a way’s off from npm’s recent 1.35million package milestone
UX handling between different OSs?
Flutter provides a check to determine which OS the user is using within each widget, however, it is becoming more common to have UX flows be shared between iOS and Android.
Overall the process of detecting the platform is very straightforward — requiring only a platform import and an if statement
Let’s talk performance
Based on the following 2 articles, flutter seems to be much faster than React Native, but not as fast as pure native just yet. I expect this to change once wasm support is added. It should also be noted that out of these comparisons, only flutter is capable of running as a web app.
Final thoughts
Flutter offers a level of polish I haven’t seen before in both Nativescript and React-Native, with better performance to boot. I feel the biggest hurdle with Flutter will be the template engine — moving away from HTML and CSS would be challenging, especially when it comes to complex animations and 3D. The library support also feels small, but all the essentials are there and the framework seems to be gaining traction fast. Since the web framework is still in beta, it seems unfair to benchmark and compare it to Angular as of today.
Other aspects of the development process
The tooling provided with flutter was excellent. There’s memory profilers, options to manually hot reload, inspectors, and emulation of iOS on Android devices. The built-in feature-set is also great with AOT/JIT builds supported out of the box. AOT is important because it avoids context switching in the “javascript bridge” — a problem present in react native. Things like widgets are moved directly into the app, making it feel much snappier compared to react-native. Garbage collection is also well thought out.
Flutter doctor also ensures that you have set up your environment correctly for running flutter apps. The tooling even searches for IDEs which are installed, and detects/recommends installing Flutter plugins for IntelliSense support!
It should be noted that although it has hot reloading, it does not automatically run hot reloading on changes by default. This can be fixed by following this handy guide:
How to automatically hot reload Flutter when Dart source files change
Once hot reloading is automated, it’s also very fast and retains state across reload.
100ms–500ms hot reloading
If you’re interested in trying things out for yourself, get your hands dirty with the Codelabs!