Skip to content

Add easy conditional import based on kIsWeb or dart lib #60466

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
stan-at-work opened this issue Apr 3, 2025 · 4 comments
Closed

Add easy conditional import based on kIsWeb or dart lib #60466

stan-at-work opened this issue Apr 3, 2025 · 4 comments

Comments

@stan-at-work
Copy link

stan-at-work commented Apr 3, 2025

Currently, we need to do those checks to check if some imports can be used on the web:

// Conditional import to compile on web
import '../web_mock/core_app_zebra_scanner_provider_mock.dart' if (dart.library.ffi) 'package:flutter_tools/src/providers/core_app_zebra_scanner_provider.dart';

It would be easier if it could be done like this:

if (kIsWeb == false) import 'package:ffi/ffi.dart';

or

if (dart.library.ffi) import 'package:ffi/ffi.dart' as ffiPackage;

...

and in the code check if the package is imported:

if (ffiPackage.isImported){
// Magic ffi stuff
}
@stan-at-work stan-at-work changed the title Add easy conditional import based on kIsWeb Add easy conditional import based on kIsWeb or dart lib Apr 3, 2025
@lrhn
Copy link
Member

lrhn commented Apr 3, 2025

A trick:

import 'data:,' if (dart.library.ffi) 'package:ffi/ffi.dart';

Sadly it only works in compilers, the analyzer does not accept data: URIs.
Can also use import 'my_empty_file.dart' if (...) ...; or import 'dart:core' if (...) ...; to not get anything by default.

However, it's unlikely to ever be useful to conditionally import a library with no alternative.

If you just import package:ffi/ffi.dart;` you get a compile-time error if you compile for a platform where it doesn't exist.

If you do import 'empty.dart' if (dart.library.ffi) 'package:ffi/ffi.dart';, and the dart:ffi library is available, it works.
Presumably you refer to names imported from package:ffi/ffi.dart in the library.

If you then compiler the program on a platform without dart:ffi, then those names are compile-time errors.
Your code won't compile anyway, the coditional import just changed a "can't import library depending on dart:ffi" error
to a "this name doesn't exist" error, which is a worse debugging experience.

That's why conditional imports assume that you always import some library, so that every possible import includes all the names that the library refers to. Because if they don't, the library won't work for that condition anyway.

As for having an easier condition to check for web than if (dart.library.js_interop), that would be nice. In particular if you want to distinguish JS and WASM, which both have dart:js_interop.
See #54785 for that.

If you want the code to be able to conditionally refer to names from an import, then that's closer to deferred imports, and would need to be a langauge feature (so in the language repo).
It's not a bad idea, but it needs some consideration. Let's go with what you suggested:

  • Allow an import which is not defined for all configurations.
  • import if (dart.library.ffi) 'package:ffi/ffi.dart' as ffiPackage;. (No default.)
  • Must have import prefix.
  • Allow ffiPackage.isImported (or something) as a constant value, which is true if any library was actually imported.
  • Any code guarded by such a dynamic check would be allow to access members through the prefix,
    other code cannot.
  • It's like promotion of the name to "definitely available". (If there is more than one conditional URI in the import, they must still all provide all the used names.)

In a compilation where no conditional URI applies, the library is unimported. The prefix.isImported is a false constant, recognized by flow analysis, and any (other) name access on the prefix is allowed with static type Never (and tools will refrain from giving any warnings due to things being unreachable.)

It's not perfect. If one function checks that prefix.isImported is true, then calls another helper function, then the helper function needs to check prefix.isImported again for it to be allowed access to members. The check for whether you can access import members is based on local flow analysis, it's not cross-function.

@ykmnkmi
Copy link
Contributor

ykmnkmi commented Apr 3, 2025

I need optional platform imports too:

import 'dom.dart' when (dart.library.js_interop) as dom;

if (dom.isAvailable) {
 dom.attachNodes(effect, firstNode, lastNode);
}

@lrhn
Copy link
Member

lrhn commented Apr 3, 2025

If it works, it should work with platform libraries. So I'll open a language request for it.
(No guarantee that it'll ever happen, but it's not a completely impossible request. Still fairly tricky.)

@lrhn
Copy link
Member

lrhn commented Apr 9, 2025

I think the language feature request covers all that this issue can ask for, and there is nothing that can be done by the SDK without a language change, so I'll close this issue and defer to dart-lang/language#4317.

@lrhn lrhn closed this as completed Apr 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants