package:webへの移行
Dartのpackage:web
は、ブラウザAPIへのアクセスを提供し、DartアプリケーションとWeb間の相互運用を可能にします。 package:web
を使用して、ブラウザと対話し、DOM内のオブジェクトと要素を操作します。
import 'package:web/web.dart';
void main() {
final div = document.querySelector('div')!;
div.text = 'Text set at ${DateTime.now()}';
}
package:web
vs dart:html
#package:web
の目標は、既存のDart Webライブラリに関するいくつかの懸念事項に対処することにより、DartがWeb APIを公開する方法を刷新することです。
Wasm互換性
パッケージは、Wasmと互換性があるのは、
dart:js_interop
とdart:js_interop_unsafe
を使用している場合のみです。package:web
はdart:js_interop
に基づいているため、デフォルトではdart2wasm
でサポートされています。dart:html
やdart:svg
などのDartコアWebライブラリは、Wasmにコンパイルする場合は**サポートされていません**。最新の状態を保つ
package:web
は、Web IDLを使用して、IDLの各宣言の相互運用メンバーと相互運用型を自動的に生成します。dart:html
の追加メンバーや抽象化とは対照的に、参照を直接生成することで、package:web
はより簡潔で、理解しやすく、より一貫性があり、Web開発の将来に合わせて最新の状態を維持しやすくなります。バージョン管理
パッケージであるため、
package:web
は、dart:html
のようなライブラリよりも簡単にバージョン管理でき、進化してもユーザーコードを壊すことを回避できます。 また、コードの排他性を軽減し、貢献しやすくなります。 開発者は、独自の代替相互運用宣言を作成し、package:web
と競合することなく使用できます。
これらの改善により、package:web
とdart:html
の間には、実装にいくつかの違いが生じます。 IDLの名前変更や型テストなど、既存のパッケージに最も影響を与える変更については、以下の移行セクションで説明します。 簡潔にするためにdart:html
のみを参照していますが、同じ移行パターンは、dart:svg
などの他のDartコアWebライブラリにも適用されます。
dart:html
からの移行
#dart:html
インポートを削除し、package:web/web.dart
に置き換えます
import 'dart:html' as html; // Remove
import 'package:web/web.dart' as web; // Add
pubspecのdependencies
にweb
を追加します
dart pub add web
以下のセクションでは、dart:html
からpackage:web
への一般的な移行の問題について説明します.
その他の移行の問題については、dart-lang/webリポジトリを確認し、問題を報告してください。
名前の変更
#dart:html
の多くのシンボルは、Dartスタイルとの整合性を高めるために、元のIDL宣言から名前が変更されました。 たとえば、appendChild
はappend
になり、HTMLElement
はHtmlElement
になりました。
これに対し、混乱を減らすため、package:web
はIDL定義の元の名前を使用します。 dart fix
は、dart:html
とpackage:web
の間で名前が変更された型を変換するために使用できます。
インポートを変更した後、名前が変更されたオブジェクトはすべて新しい「未定義」エラーになります。 これらは、次のいずれかの方法で対処できます。
- CLIから、
dart fix --dry-run
を実行します。 - IDEで、
dart fix
を選択します:**'package:web名
'に名前変更**。
dart fix
は、一般的な型の名前変更の多くを網羅しています。 名前の変更を行うためのdart fix
がないdart:html
型に遭遇した場合は、まずissueを提出してお知らせください。
次に、既存のdart:html
メンバーの定義を調べることで、package:web
の型名を手動で見つけることができます。 dart:html
メンバー定義の@Native
アノテーションの値は、コンパイラーに、その型のJSオブジェクトをアノテーションが付けられたDartクラスとして扱うように指示します。 たとえば、@Native
アノテーションは、dart:html
のHtmlElement
メンバーのネイティブJS名がHTMLElement
であることを示しているため、package:web
の名前もHTMLElement
になります。
@Native("HTMLElement")
class HtmlElement extends Element implements NoncedElement { }
package:web
で未定義のメンバーのdart:html
定義を見つけるには、次のいずれかの方法を試してください。
- IDEで未定義の名前をCtrlキーまたはCommandキーを押しながらクリックし、**定義へ移動**を選択します。
dart:html
APIドキュメントで名前を検索し、*アノテーション*の下にあるページを確認します。
同様に、対応するdart:html
メンバーの定義でキーワードnative
を使用している、未定義のpackage:web
APIが見つかる場合があります。 定義で名前変更のために@JSName
アノテーションが使用されているかどうかを確認します。 アノテーションの値は、メンバーがpackage:web
で使用する名前を示します。
@JSName('appendChild')
Node append(Node node) native;
native
は内部キーワードであり、このコンテキストではexternal
と同じ意味です。
型テスト
#dart:html
を使用するコードでは、is
のようなランタイムチェックを利用するのが一般的です。 dart:html
オブジェクトで使用する場合、is
とas
は、オブジェクトが@Native
アノテーション内のJS型であることを確認します。 これに対し、すべてのpackage:web
型はJSObject
に具体化されます。 つまり、ランタイム型テストの結果は、dart:html
型とpackage:web
型で異なる動作になります。
型テストを実行できるようにするには、is
型テストを使用している dart:html
コードを、instanceOfString
などの 相互運用メソッド、またはより便利で型付けされた isA
ヘルパー (Dart 3.4 以降で使用可能) を使用するように移行してください。JS 型ページの 互換性、型チェック、およびキャスト セクションでは、代替方法について詳しく説明しています。
obj is Window; // Remove
obj.instanceOfString('Window'); // Add
型シグネチャ
#dart:html
の多くの API は、型シグネチャでさまざまな Dart 型をサポートしています。dart:js_interop
は 記述できる型を制限しているため、package:web
の一部のメンバーでは、メンバーを呼び出す前に値を*変換*する必要があります。JS 型ページの 変換 セクションから、相互運用変換メソッドの使用方法を学習してください。
window.addEventListener('click', callback); // Remove
window.addEventListener('click', callback.toJS); // Add
一般的に、変換が必要なメソッドは、例外のバリエーションによってフラグが立てられるため、特定できます
A value of type '...' can't be assigned to a variable of type 'JSFunction?'
条件付きインポート
#ネイティブとウェブを区別するために、dart:html
がサポートされているかどうかによって条件付きインポートを使用するコードは一般的です
export 'src/hw_none.dart'
if (dart.library.io) 'src/hw_io.dart'
if (dart.library.html) 'src/hw_html.dart';
しかし、Wasm にコンパイルする場合、dart:html
はサポートされていないため、ネイティブとウェブを区別するための正しい代替手段は、dart.library.js_interop
を使用することです
export 'src/hw_none.dart'
if (dart.library.io) 'src/hw_io.dart'
if (dart.library.js_interop) 'src/hw_web.dart';
仮想ディスパッチとモッキング
#dart:html
クラスは仮想ディスパッチをサポートしていましたが、JS 相互運用は拡張型を使用するため、仮想ディスパッチは 不可能です。 同様に、package:web
型を使用した dynamic
呼び出しは期待どおりに機能しません (または、偶然に機能し続ける場合がありますが、dart:html
が削除されると停止します)。これは、メンバーが静的にのみ使用可能であるためです。 この問題を回避するために、仮想ディスパッチに依存するすべてのコードを移行してください。
仮想ディスパッチのユースケースの 1 つはモッキングです。dart:html
クラスを implements
するモッキングクラスがある場合、package:web
型を実装するために使用することはできません。 代わりに、JS オブジェクト自体をモックすることをお勧めします。 詳細については、モッキングチュートリアル を参照してください。
native
ではない API
#dart:html
クラスには、重要な実装を持つ API が含まれている場合があります。 これらのメンバーは、package:web
の ヘルパー に存在する場合と存在しない場合があります。 コードがその実装の specifics に依存している場合は、必要なコードをコピーできる場合があります。 ただし、それが難しいと思われる場合、またはそのコードが他のユーザーにも役立つと思われる場合は、問題を報告するか、package:web
にプルリクエストをアップロードして、そのメンバーをサポートすることを検討してください。
ゾーン
#dart:html
では、コールバックは自動的にゾーン化されます。 package:web
ではそうではありません。 現在のゾーンでのコールバックの自動バインディングはありません。
これがアプリケーションにとって重要な場合は、ゾーンを使用できますが、コールバックをバインドすることで 自分で記述する 必要があります。 詳細については、#54507 を参照してください。 これを自動的に行うための変換 API や ヘルパー はまだありません。
ヘルパー
#package:web
のコアには external
相互運用メンバーが含まれていますが、dart:html
がデフォルトで提供していた他の機能は提供していません。 これらの違いを軽減するために、package:web
には、コアの相互運用では直接利用できない多くのユースケースの処理をさらにサポートするための ヘルパー
が含まれています。 ヘルパーライブラリには、Dart ウェブライブラリのレガシー機能を公開するためのさまざまなメンバーが含まれています。
たとえば、コアの package:web
は、イベントリスナーの追加と削除のみをサポートしています。 代わりに、Dart Stream
を使用してイベントを簡単に subscribe できる ストリームヘルパー を使用できます。そのコードを自分で記述する必要はありません。
// dart:html version
InputElement htmlInput = InputElement();
await htmlInput.onBlur.first;
// package:web version
HTMLInputElement webInput = document.createElement('input') as HTMLInputElement;
await webInput.onBlur.first;
すべてヘルパーとそのドキュメントは、リポジトリの package:web/helpers
にあります。 これらは、ユーザーの移行を支援し、Web API を使いやすくするために継続的に更新されます。
例
#dart:html
から package:web
に移行されたパッケージの例を次に示します
特に明記されていない限り、このサイトのドキュメントは Dart 3.5.3 を反映しています。 ページの最終更新日: 2024-09-03。 ソースを表示 または 問題を報告する.