Webify Your App: Tips for Flutter for Web Migration
tl;dr: Tips for migrating your Flutter app to the web
As part of my initial duties at a startup I worked at, I embarked on a mission to transform their Flutter mobile app into a web application. This journey involved careful planning and lots of research which I am excited to share with you in this blog post. By exploring the essential considerations, smart workarounds, and optimization techniques, I initially wrote this for co-workers and management but then transformed it into this article which could serves as a tips for anyone looking to migrate their Flutter app from mobile to the web.
Dependencies :
Not all flutter packages and dependencies have compatibility with Web versions (in the time of writing this article) , so the mobile app shouldn’t use those packages (to ensure we share the same code). However, as the mobile application is already developed , up and working there might be some packages that are compatible only with mobile versions. I’ve found some workarounds to this issue :
- Either to replace these incompatible packages with other packages that are compatible with Web (which means often times reworking on the mobile implementation of that package too)
- Provide and implement web support in the package by conditional imports (example), this will require more work and researching each package . Example :
//in auth0_manager.dart
AuthManager getManager() => Auth0Manager();
//in auth0_manager_for_web.dart
AuthManager getManager() => Auth0ManagerForWeb();
If you want to know more about Conditional Imports I recommend this article by Antonello Galipò
- Another workaround that is possible, is to include Javascript in the flutter web version and implement javascript features and functions to replace these packages. Example of use of JS with js package in Flutter (Dart) :
@JS()
library stringify;
import 'package:js/js.dart';
// Calls invoke JavaScript `JSON.stringify(obj)`.
@JS('JSON.stringify')
external String stringify(Object obj);
To use the js package, we must declare in a separate file the functions in JavaScript that we need to call with the help of the @JS annotation.
Web Renders :
There are two different web renderers, on default mode, the two web renders work on the production environment if the device browsing the web app is mobile then the renderer will be automatically assigned to HTML Renderer, if the device is a desktop the renderer is CanvasKit :
-
HTML renderer : This renderer is mainly used for mobile devices as it has a smaller download size. However, it is less performant than canvasKit with SVG issues and a lot of layout issues. this renderer has too many issues for any application that uses CanvasKit API or large web apps.
-
CanvasKit renderer : Fast and performant renderer with fast, accurate measurements and layouts (a lot more stable than HTML renderer). however, it has a large bundle size.
While HTML mode offers the best code size characteristics, CanvasKit provides the fastest path to the browser’s graphics stack and offers somewhat higher graphical fidelity with the native mobile targets
=> It is most preferred to force the CanvasKit renderer on the production of the web app as it is more performant and fast, as for the large bundle size, Flutter is working to reduce the size as they announced in their yearly plans.
Architecture :
Flutter for Web Architecture relies on the JS engine, Canvas, and DOM as most of the web frameworks do, as for the Framework itself it remains very similar to the mobile version. The main difference of Flutter web from other platforms is that there is no need for Flutter to provide Dart runtime yet it is compiled to Javascript. the flutter engine is designed to interface with the underlying operating system rather than a web browser. A different approach is therefore required. On the web, Flutter provides a reimplementation of the engine on top of standard browser APIs.
Browser specific interactions :
As most mobile applications do not have the same interactions as browser interactions, this is a list of the following interactions that need to be implemented : *Scrollbar: implementing a scrollbar inside the whole web application (wrapping the app with the scrollbar widget) (Scrollbar behavior in flutter have been experiencing a lot of issues) *Mouse interactions: as on the web experience the cursor changes over a region /a specific widget / a button yet flutter doesn’t provide this change on default. (wrapping up the target widgets with Mouse Region widget) . This includes Hover effects. *Keyboard shortcuts: it is possible to implement keyboard shortcuts to trigger specific actions or events. this will be implemented only when required.
Responsive and Adaptive UI :
There are too many ways to provide UI responsiveness and adapt to any screen size (either mobile, desktop, or tablet): *MediaQueries (flutter class): with MediaQuery, we can detect the device screen and adjust the UI accordingly, we can even render different views according to the screen size. With different views, we can use the same widgets or we can change the constraints depending on the screen size. *LayoutBuilder (flutter class): this comes to hand and hand with media queries, this class displays based on height, aspect ratio, etc Packages there are a lot of packages that handle responsive issues for all screens (examples: Responsive , Responsive_ui , Sizer ).
Performance:
When it comes to performance, Flutter provides great tools (Flutter Inspector, Flutter performance profiler, Performance View,..) to profile the performance and track threads. below are tips on how to improve Flutter web performance :
- Disabling navigation transitions on Flutter web : For a perceived performance improvement, it is recommended to disable the page transition animation. By default, Flutter uses page transitions for routing relevant to the platform (slide in upwards for Android or from the side for iOS). On the web, it is possible to disable the transition as it’s not something you would typically see in a web application. *Precaching images : it is a known issue in Flutter for the web especially, that images take a long time to load, to solve this problem, it’s advised to use PreCacheImage function . *Lazy Loading: Lazy Loading allows a web app to load a library on demand, if and when the library is needed. *Avoid calling SaveLayer: saveLayer method saves a copy of the current transform and clip on the save stack The saveLayer method is one of the most expensive methods in the Flutter framework. Tip : Some widgets may call this method and it’s recommended to avoid them (Most of these widgets are effects ) .
- Decoupling widgets : in other words, avoiding large single Widgets with a large build() function. it is recommended to split them into different Widgets based on encapsulation.
Search Engine Optimization :
SEO(Search Engine Optimization)-friendly means that Google and other search engines can crawl each page on the website efficiently,
Unfortunately, Flutter is not meant for heavy content related sites, so it’s quite normal that it is not a great SEO friendly solution, However,
it didn’t matter actually as flutter is meant to build SPA (Single Page Application) or PWA (Progressive Web Apps) like the product we built, a web application that doesn’t contain heavy media content.
Although it is possible to improve the engine optimization with some packages .