Migrate to package:web
Dart's package:web
exposes access to browser APIs,
enabling interop between Dart applications and the web.
Use package:web
to interact with the browser and
manipulate objects and elements in the 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
#The goal of package:web
is to revamp how Dart exposes web APIs
by addressing several concerns with the existing Dart web libraries:
-
Wasm compatibility
Packages can only be compatible with Wasm if they use
dart:js_interop
anddart:js_interop_unsafe
.package:web
is based ondart:js_interop
, so by default, it's supported ondart2wasm
.Dart core web libraries, like
dart:html
anddart:svg
, are not supported when compiling to Wasm. -
Staying modern
package:web
uses the Web IDL to automatically generate interop members and interop types for each declaration in the IDL. Generating references directly, as opposed to the additional members and abstractions indart:html
, allowspackage:web
to be more concise, easier to understand, more consistent, and more able to stay up-to-date with the future of Web developments. -
Versioning
Because it's a package,
package:web
can be versioned more easily than a library likedart:html
and avoid breaking user code as it evolves. It also makes the code less exclusive and more open to contributions. Developers can create alternative interop declarations of their own and use them together withpackage:web
without conflict.
These improvements naturally result in some
implementation differences between package:web
and dart:html
.
The changes that affect existing packages the most,
like IDL renames and
type tests,
are addressed in the migration sections that follow. While we only refer to
dart:html
for brevity, the same migration patterns apply to any other Dart
core web library like dart:svg
.
Migrating from dart:html
#Remove the dart:html
import and replace it with package:web/web.dart
:
import 'dart:html' as html; // Remove
import 'package:web/web.dart' as web; // Add
Add web
to the dependencies
in your pubspec:
dart pub add web
The following sections cover some of the common migration issues
from dart:html
to package:web
.
For any other migration issues, check the dart-lang/web repo and file an issue.
Renames
#Many of the symbols in dart:html
were renamed from
their original IDL declaration to align more with Dart style.
For example, appendChild
became append
,
HTMLElement
became HtmlElement
, etc.
In contrast, to reduce confusion,
package:web
uses the original names from the IDL definitions.
A dart fix
is available to convert types that have been renamed
between dart:html
and package:web
.
After changing the import, any renamed objects will be new "undefined" errors. You can address these either:
- From the CLI, by running
dart fix --dry-run
. - In your IDE, by selecting the
dart fix
: Rename to 'package:web name
'.
The dart fix
covers many of the common type renames.
If you come across a dart:html
type without a dart fix
to rename it,
first let us know by filing an issue.
Then, you can try manually discovering the package:web
type name of an
existing dart:html
member by looking up its definition.
The value of the @Native
annotation on a dart:html
member definition
tells the compiler to treat any JS object of that type as the Dart class
that it annotates. For example, the @Native
annotation tells us that the
native JS name of dart:html
's HtmlElement
member is HTMLElement
,
so the package:web
name will also be HTMLElement
:
@Native("HTMLElement")
class HtmlElement extends Element implements NoncedElement { }
To find the dart:html
definition for an undefined member in package:web
,
try either of the following methods:
- Ctrl or command click the undefined name in the IDE and choose Go to Definition.
- Search for the name in the
dart:html
API docs and check its page under Annotations.
Similarly, you might find an undefined package:web
API whose corresponding
dart:html
member's definition uses the keyword native
.
Check if the definition uses the @JSName
annotation for a rename;
the value of the annotation will tell you the name the member uses in
package:web
:
@JSName('appendChild')
Node append(Node node) native;
native
is an internal keyword that means the same as external
in this
context.
Type tests
#It's common for code that uses dart:html
to utilize runtime checks like is
.
When used with a dart:html
object, is
and as
verify that the object is
the JS type within the @Native
annotation.
In contrast, all package:web
types are reified to JSObject
. This means a
runtime type test will result in different behavior between dart:html
and
package:web
types.
To be able to perform type tests, migrate any dart:html
code
using is
type tests to use interop methods like instanceOfString
or the more convenient and typed isA
helper
(available from Dart 3.4 onward).
The Compatibility, type checks, and casts
section of the JS types page covers alternatives in detail.
obj is Window; // Remove
obj.instanceOfString('Window'); // Add
Type signatures
#Many APIs in dart:html
support various Dart types in their type signatures.
Because dart:js_interop
restricts the types that can be written, some of
the members in package:web
will now require you to convert the value before
calling the member.
Learn how to use interop conversion methods from the Conversions
section of the JS types page.
window.addEventListener('click', callback); // Remove
window.addEventListener('click', callback.toJS); // Add
Generally, you can spot which methods need a conversion because they'll be flagged with some variation of the exception:
A value of type '...' can't be assigned to a variable of type 'JSFunction?'
Conditional imports
#It is common for code to use a conditional import based on whether dart:html
is supported to differentiate between native and web:
export 'src/hw_none.dart'
if (dart.library.io) 'src/hw_io.dart'
if (dart.library.html) 'src/hw_html.dart';
However, since dart:html
is not supported when compiling to Wasm, the correct
alternative now is to use dart.library.js_interop
to differentiate between
native and web:
export 'src/hw_none.dart'
if (dart.library.io) 'src/hw_io.dart'
if (dart.library.js_interop) 'src/hw_web.dart';
Virtual dispatch and mocking
#dart:html
classes supported virtual dispatch, but because JS interop uses
extension types, virtual dispatch is not possible. Similarly, dynamic
calls
with package:web
types won't work as expected (or, they might continue to work
just by chance, but will stop when dart:html
is removed), as their members are
only available statically. Migrate all code that relies on virtual dispatch to
avoid this issue.
One use case of virtual dispatch is mocking. If you have a mocking class that
implements
a dart:html
class, it can't be used to implement a package:web
type. Instead, prefer mocking the JS object itself. See the mocking tutorial
for more information.
Non-native
APIs
#dart:html
classes may also contain APIs that have a non-trivial
implementation. These members may or may not exist in the package:web
helpers. If your code relies on the specifics of that
implementation, you may be able to copy the necessary code.
However, if you think that's not tractable or if that code would be beneficial
for other users as well, consider filing an issue or uploading a pull request to
package:web
to support that member.
Zones
#In dart:html
, callbacks are automatically zoned.
This is not the case in package:web
. There is no automatic binding of
callbacks in the current zone.
If this matters for your application, you can still use zones, but you will have to write them yourself by binding the callback. See #54507 for more details. There is no conversion API or helper available yet to automatically do this.
Helpers
#The core of package:web
contains external
interop members,
but does not provide other functionality that dart:html
provided by default.
To mitigate these differences, package:web
contains helpers
for additional support in handling a number of use cases
that aren't directly available through the core interop.
The helper library contains various members to expose some legacy features from
the Dart web libraries.
For example, the core package:web
only has support for adding and removing
event listeners. Instead, you can use stream helpers that makes it easy to
subscribe to events with Dart Stream
s without writing that code yourself.
// dart:html version
InputElement htmlInput = InputElement();
await htmlInput.onBlur.first;
// package:web version
HTMLInputElement webInput = document.createElement('input') as HTMLInputElement;
await webInput.onBlur.first;
You can find all the helpers and their documentation in the repo at
package:web/helpers
. They will continuously be updated to aid users
in migration and make it easier to use the web APIs.
Examples
#Here are some examples of packages that have been migrated from dart:html
to package:web
:
除非另有说明,文档之所提及适用于 Dart 3.5.3 版本,本页面最后更新时间: 2024-09-03。 查看文档源码 或者 报告页面问题。