avatarAntonello Galipò

Summary

The article discusses the use of conditional imports in Flutter to manage platform-specific dependencies, particularly for integrating Auth0 authentication in a Flutter app that targets both mobile and web platforms.

Abstract

The article titled "Conditional imports across Flutter and Web" addresses the challenge of implementing features in Flutter that are supported by plugins on mobile but not on the web. It uses the example of integrating Auth0 authentication, where the flutter_auth0 plugin is available for mobile but not for web. The author explores the initial approach of using a factory pattern with the kIsWeb runtime check, which proves inadequate due to kIsWeb not being a compile-time constant and the inability to tree-shake code for unsupported platforms. The solution presented involves leveraging Dart's conditional import feature to selectively import platform-specific code at compile time, ensuring compatibility and avoiding runtime errors. The article provides code examples for creating an abstract class, concrete implementations for mobile and web, and an import stub to facilitate the conditional import process. The author also references a forthcoming article that will delve into the complexities of implementing Auth0 on Flutter Web and acknowledges contributions from collaborators.

Opinions

  • The author believes that while Flutter Web is improving, there are still challenges to be addressed, particularly with plugin support.
  • The use of a factory pattern is initially considered for encapsulating platform-specific logic but is deemed less effective than conditional imports for the given use case.
  • The author suggests that conditional imports are a more elegant solution for platform-specific dependency management, as they allow the compiler to select the appropriate code for the target platform.
  • The author expresses confidence in the conditional import solution by stating that it ensures the correct file is imported and that the code will not fail due to missing libraries on the target platform.
  • The article implies that the community can benefit from sharing knowledge and experiences, as demonstrated by the collaboration with Gabriele Tramonte and the reference to his example repository.
  • The author encourages readers to consider alternative AI services, like ZAI.chat, as a cost-effective alternative to ChatGPT Plus (GPT-4).

Conditional imports across Flutter and Web

http://www.theoutplay.com/wp-content/uploads/2017/05/crossroads-1280x471.png

Flutter Web is growing in popularity and it’s becoming more and more mature as the time passes. We’re not there with perfection, there are still some issues but hopefully they’re going to be solved soon!

If you’ve had the chance to fiddle around with a Flutter project that targets you might have found yourself trapped in this situation:

I need this feature, I could use this plugin that already does that, but it doesn’t support Web.

Then you answer yourself something like this:

Well I’ll wrap it into a factory, if kIsWeb is true then I’m on Web and return the Web-compatible instance!

Well, yes. And no. Let’s break this down.

Since I first encountered the problem when adding Auth0 authentication in my app, I’ll take this as our use case.

There is a plugin that allows to use Auth0 on mobile, but it doesn’t support Web. I’d tell you why it’s not that easy to develop a Web part for this, but I’m currently working on a dedicated article which explores the non-triviality of implementing auth0 on Flutter Web and how I’ve found a way to do it. I’ll update this article with the link when it’ll be ready, but for now, since those reasons are not in the scope of this article, let’s talk generally.

So the plugin provides an Auth0 class which allows us to perform the tasks.

We decide to wrap those tasks in another class in order to leverage the factory (and to encapsulate the plugin for architectural reasons, of course).

Our abstract class will be:

I didn’t use a factory but a bunch of if just to avoid creating a real factory that we’d throw away afterwards (trust me on it).

Our concrete classes will be then:

This is the manager for the web side, stripped of the “functional code” since we just need to know that its implementations use dart:js .

And this is the manager for the mobile side, which uses the plugin.

If we try to compile this on mobile, the compiler will complain that it won’t be able to find dart:js for the target platform!

But how’s that possible! We used the if (kIsWeb) to build the correct manager!

Well there are some reasons for this not to work:

  • kIsWeb is not a compile time constant, this means that it will be evaluated at runtime and the code that uses dart:js will not be tree-shaked
  • mobile target platform does not have the js library, so our code will fail on the import, which won’t be found.

And this is where conditional imports come to the rescue! Dart lets us decide wether to import one thing or another by doing something like this:

import "something.dart" if (dart.library.io) "other.dart"

This means that we can choose what to import at compile time according to the target platform. This comes handy in cases we need to condition imports for mobile or web.

You can find more on conditional imports on this Daniel Varga’s article.

Let’s get back on our track: we’re going to use conditional imports to import the correct auth0 manager for our platform.

First of all, we’re going to create an import stub:

The file will only have a getter which returns an instance of AuthManager which is the abstract class our two managers inherit from.

Then we’re going to add the following instructions in our managers’ files:

And, lastly, our abstract class will become like this:

By doing this, we have defined a getManager top level function which has different implementations for different files.

The compiler will then say something like this:

Let’s import aut0_manager_stub.dart , but if the dart.library.io is available, import auth0_manager.dart . But hey, if dart.library.js is available, import auth0_manager_for_web.dart !

This will result in importing the correct file for our target platform without having to rely or the non constant kIsWeb and, instead of a factory (remember when I said that we’d have thrown the factory away?) we’re going to call that getManager function which will do the work depending on its implementation.

Note that since we know that at least one between dart.library.js and dart.library.io exists, we can be safe that we don’t fall into importing the stub.

It was quite a lot here, if you’re still with me here at the end of the article well…

That’s all and thank you!

Sources:

https://www.twitter.com/FlutterComm

Flutter
Flutter Web
Recommended from ReadMedium