Skip to main content
A conditional import is a compilation directive that selects a specific library URI to load based on the configuration of the compilation environment. This mechanism resolves imports at compile-time, allowing a single directive to reference platform-specific implementations or configuration-dependent logic without triggering compilation errors on targets where those libraries are incompatible or unavailable.

Syntax Specification

The syntax appends if clauses to a standard import or export directive. The compiler evaluates conditions sequentially from top to bottom. The first condition that evaluates to true determines the file to be included. If no conditions are met, the default URI is used.
// Syntax for import
import 'default_implementation.dart'
  if (condition_a) 'implementation_a.dart'
  if (condition_b == 'value') 'implementation_b.dart';

// Syntax for export
export 'default_implementation.dart'
  if (dart.library.io) 'io_implementation.dart';

Condition Evaluation

The condition inside the if clause evaluates environment declarations. These declarations are key-value pairs defined in the compilation environment.
  1. Platform Availability: The Dart compiler automatically sets boolean flags indicating which standard libraries are available.
    • dart.library.io: True for native platforms (VM, Desktop, Mobile).
    • dart.library.js_interop: True for modern Web (JS and Wasm).
    • dart.library.html: True for legacy Web (JS only).
  2. Arbitrary Constants: Conditions can evaluate user-defined constants passed via the -D command-line flag (e.g., dart compile exe -Dmy.flag=true main.dart).
Evaluation Logic:
  • Boolean Check: if (key) evaluates to true if the key exists and its value is "true".
  • Equality Check: if (key == 'value') evaluates to true if the key exists and matches the string value.

Architectural Requirements

To ensure type safety and compilation success, the default library (the stub) and all conditional targets must adhere to a strict interface contract:
  1. Symbol Parity: Every class, function, or variable exposed by the stub must exist in every platform-specific implementation.
  2. Signature Matching: The return types and parameter lists of functions must match exactly across all implementations.
  3. Abstraction: Consuming code must rely solely on the interface defined in the stub, remaining unaware of the underlying platform-specific implementation.

Implementation Pattern

The standard implementation structure involves a stub file, platform-specific files, and a main interface file.

1. The Stub (Default)

This file defines the public API and throws UnimplementedError. It serves as the fallback for platforms not covered by the conditions and provides the interface for the IDE/analyzer.
// file: src/manager_stub.dart
class PlatformManager {
  String get platformName => throw UnimplementedError('Platform not supported');
}

2. Platform Implementations

These files import platform-specific libraries and implement the API defined in the stub. Native Implementation:
// file: src/manager_io.dart
import 'dart:io';

class PlatformManager {
  String get platformName => Platform.operatingSystem;
}
Web Implementation:
// file: src/manager_web.dart
import 'package:web/web.dart';

class PlatformManager {
  String get platformName => window.navigator.userAgent;
}

3. The Conditional Directive

The main entry point uses a conditional export directive to route the request to the correct file based on the compiler flags. This allows consumers to import a single file (manager.dart) while receiving the correct implementation for their target platform.
// file: manager.dart
export 'src/manager_stub.dart'
  if (dart.library.io) 'src/manager_io.dart'
  if (dart.library.js_interop) 'src/manager_web.dart';
Master Dart with Deep Grasping Methodology!Learn More