10 Tricks for Making Dart:ui_web Compile in Flutter Tests with Ease

When developing Flutter Web applications, developers often encounter issues with dart:ui_web compilation during tests. This problem arises from the fact that dart:ui_web is not available on Dart VM, which is the default platform used by flutter test. As a result, compilation fails, and developers are left searching for solutions to this common issue.

The Problem

One such problem that developers face is when they try to embed YouTube iframes in their Flutter Web application. To achieve this, they use dart:ui_web and package:web. However, when running tests, the compilation fails due to the absence of dart:ui_web on Dart VM. This is where the Conditional Export comes into play.

Conditional Export is a feature in Dart that allows developers to conditionally import packages based on the platform being used. In this case, it can be used to import either platform_view_stub.dart or platform_view_web.dart, depending on whether dart:ui_web is available or not.

The Fix

The solution to this problem is to use Conditional Export to import the correct file based on the platform. This involves creating three files: platform_view.dart, platform_view_stub.dart, and platform_view_web.dart. The platform_view.dart file exports platform_view_stub.dart if dart:ui_web is absent, and platform_view_web.dart if it is present.

The platform_view_stub.dart file is a no-op for Dart VM, meaning it does not perform any actions. On the other hand, the platform_view_web.dart file is used for Flutter Web and imports dart:ui_web to register the iframe view factory.

Here’s an example of how the Conditional Export works:

import 'dart:ui_web' as ui_web;
import 'package:web/web.dart' as web;

// platform_view.dart
export 'platform_view_stub.dart' if (dart.library.ui_web) 'platform_view_web.dart';

// platform_view_stub.dart
void registerIframeViewFactory(String viewId, String src) {
  // no-op — Dart VM can't render iframes anyway
}

// platform_view_web.dart
import 'dart:ui_web' as ui_web;
import 'package:web/web.dart' as web;

void registerIframeViewFactory(String viewId, String src) {
  ui_web.platformViewRegistry.registerViewFactory(viewId, (int viewIdInt) {
    final iframe = web.HTMLIFrameElement()
     ..src = src
     ..allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'
     ..setAttribute('allowfullscreen', 'true')
     ..style.border = 'none'
     ..style.width = '100%'
     ..style.height = '100%';
    return iframe;
  });
}

To use the Conditional Export, developers need to drop the direct import of dart:ui_web and package:web, and instead import the platform_view.dart file. This will automatically import the correct file based on the platform being used.

Here’s an example of how to use the Conditional Export in a Flutter Web application:

// philosophy_page.dart — before
import 'dart:ui_web' as ui_web;
import 'package:web/web.dart' as web;

// after
import '../utils/platform_view.dart' as platform_view;

// initState — same call site, different impl behind it
for (final v in _videos) {
  platform_view.registerIframeViewFactory('youtube-${v.id}', 'https://www.youtube.com/embed/${v.id}');
}

How the Conditional Export Works

The Conditional Export works by evaluating the dart.library.ui_web condition at compile time. If dart:ui_web is absent, the platform_view_stub.dart file is used. If it is present, the platform_view_web.dart file is used.

This approach is the standard Flutter way of handling platform-conditional imports. By using the Conditional Export, developers can ensure that their Flutter Web application compiles correctly and runs smoothly, even when testing.

Result Before and After

Before using the Conditional Export, the compilation failed for test/main_test.dart, and the tests broke. However, after implementing the Conditional Export, the compilation succeeded, and the tests passed.

The table below shows the results before and after using the Conditional Export:

Test Before After
flutter test ❌ dart:ui_web compile error ✅ works
flutter build web ❌ fails ✅ works
flutter analyze ❌ 0 errors ✅ 0 errors
CI (Dart VM tests) ❌ 13 tests fail ✅ all pass

Conclusion

In conclusion, the Conditional Export is a powerful feature in Dart that allows developers to conditionally import packages based on the platform being used. By using this feature, developers can ensure that their Flutter Web application compiles correctly and runs smoothly, even when testing.

By following the steps outlined in this article, developers can easily implement the Conditional Export in their Flutter Web application and avoid the common issue of dart:ui_web compilation failure during tests.

Practical Applications

The Conditional Export has many practical applications in Flutter Web development. Here are a few examples:

  • Embedding YouTube iframes in Flutter Web applications.
  • Using dart:html and dart:ui_web for platform-conditional imports.
  • Creating platform-conditional UI components.
  • Handling platform-conditional dependencies.

By understanding the Conditional Export and how to use it, developers can take their Flutter Web applications to the next level and create robust, scalable, and maintainable codebases.

Future Developments

The Conditional Export is a feature that is constantly evolving. In the future, we can expect to see more features and improvements added to this powerful tool.

Some potential future developments include:

  • Improved support for platform-conditional imports.
  • Enhanced error handling for platform-conditional imports.
  • Support for more platforms, such as mobile and desktop.
  • Integration with other Flutter features, such as widgets and layouts.

By staying up-to-date with the latest developments and best practices, developers can ensure that their Flutter Web applications remain competitive and continue to evolve with the changing landscape of web development.

Add Comment