Flutter-ファイル名選択ダイアログで自前修正したものを自分のdartファイルにimportして、それをWEB版でビルドした時にWin32パッケージでエラーが出てしまった。
原因は、main.dartでimportしたファイルの中でwin32パッケージを使用していたため。
WEB版のビルドでは、それらがコンパイルできなかったのでエラーが出てしまったようだ。
ここでこのファイルのオリジナル側のファイルを使用した場合コンパイルエラーが出なかったのはなぜなのか、気になって調査してみた。
オリジナル側の記述
オリジナル側の記述は以下の様になっていた。
import 'package:file_picker/src/windows/stub.dart'
if (dart.library.io) 'package:file_picker/src/windows/file_picker_windows.dart';
importの後ろにif文が入っているのを始めて見てしまった。
ファイルピック用のクラスのファクトリーをメソッド「filePickerWithFFI()」で用意していてstub.dart内では未実装状態で定義し、dart.library.ioが定義されていればfile_picker_windows.dart側を読み込み、そちら側の実装を使うという内容のようだった。
importの構文
これは何だろうかということで、仕様書を見てみることにした。
19.1と19.7が関連するところで、importの定義は次のような記述になっている。
<libraryImport> ::= <metadata> <importSpecification>
<importSpecification> ::= import <configurableUri> (deferred? as <identifier>)? <combinator>* ‘;’
<uri> ::= <stringLiteral>
<configurableUri> ::= <uri> <configurationUri>*
<configurationUri> ::= if ‘(’ <uriTest> ‘)’ <uri>
<uriTest> ::= <dottedIdentifierList> (‘==’ <stringLiterali)?
importの後ろに<configurableUri>というのが配置できて、その中にUriの後ろにif文(configurationUri)が書けるようになっているという記述があった。
configurationUri
これはif文のコンディションが正の場合、先頭の<uri>の代わりにif文の後ろの<uri>を代替して読み込むというものらしい。
仕様書の19.7、簡易版としてはhttps://dart.dev/guides/libraries/create-library-packages#conditionally-importing-and-exporting-library-filesに記述がある。
条件付きimport/exportといったもののようだ。
判定に利用できる<uriTest>とは
これに関しては仕様書に書かれているのだけど、その中の識別子である<dottedIdentifierList>の詳細は書かれていないようだ。
同名の定義はlibraryの識別として使用できるようなことが書いてあったのだが中身は異なるようだ。
実際に使用されている文字は、dart.library.ioとdart.library.html。
対応するようなimport先の”dart:io”と”dart:html”内のlibraryの記述はそれぞれdart.ioとdart.dom.htmlと異なっている。
違うんです。
じゃあ、<dottedIdentifierList>に設定可能な文字列は何なのかという疑問が出るのだけど、これを明確に定義している文書は見つからなかった。
少し古いけどhttps://github.com/dart-lang/sdk/issues/34262でDart 1の時は環境変数(もしくは起動引数–dart-defineで指定した定義)を設定可能なようだったのだけど、もろもろの理由でその仕様が変更されたとのこと。
その中での記述としてはdart.library.*が用意されていると書かれている。
dart.library.*のtrue/falseはどうなのか
そこで、https://api.flutter.dev/index.htmlにあるdart:*の名前をdart.library.*に当てはめられるのではないかと考え、String.fromEnvironmentの結果を見てみた。
DartのみはWindows環境でDartプロジェクトのmainから呼び出したもの。
実際の出力結果は”true”もしくは””になるので、”true”を〇で記述する。
名称 | Windows | Android | WEB | Dartのみ |
dart.library.async dart.library.collection dart.library.convert dart.library.core dart.library.developer dart.library.math dart.library.typed_data |
〇 | 〇 | 〇 | 〇 |
dart.library.ffi dart.library.io dart.library.isolate |
〇 | 〇 | × | 〇 |
dart.library.html dart.library.js dart.library.js_util |
× | × | 〇 | × |
dart.library.ui | 〇 | 〇 | 〇 | × |
dart.libraryとしては全部で4つに分類でき、async, collection, convert, core, developer, math, typed_dataはすべて共通。ffi, io, isolateはWEB以外、html, js, js_utilはWEBのみ、uiはGUIを構築可能なもののみ、それぞれtrueになっていた。
またdart.library.wasmというのもあったのだけど、これは全環境falseだった。
これを見る限り、実行環境ごとにimportするファイルを切り替えるための識別名は、dart.library.io、dart.library.html、dart.library.uiの3つを覚えておけばいいのではないかと推測できる。
注意事項
条件付きimportについてはDart 2で互換性がなくなる破壊的な変更が行われたのと、仕様として明確になっていないような感じがするので、今後環境が増えてくるたびに変わるのではないかなと思う。
利用する際は、export用のimportファイルにまとめて記述しておくのが良いのではないかと思う。
コメント