mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 21:20:36 +00:00
Add section on known bugs
For now stage this in the package:js README - that might not be the best place for it long term since the details may change... - Add a note that makes it explicit we expect all interop to use `package:js` instead of `dart:js`. - Add notes about known limitations and differences between dart2js and DDC. Change-Id: Ib4c967ea1435dd85f41f56646140352b125cee4c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107560 Reviewed-by: Nicholas Shahan <nshahan@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
parent
f6c0b2d3ce
commit
60e474bf7a
110
pkg/js/README.md
110
pkg/js/README.md
|
@ -7,6 +7,9 @@ end-to-end example.
|
|||
|
||||
### Usage
|
||||
|
||||
All Dart code interacting with JavaScript should use the utilities provided with
|
||||
`package:js`. Developers should avoid importing `dart:js` directly.
|
||||
|
||||
#### Calling methods
|
||||
|
||||
```dart
|
||||
|
@ -94,7 +97,114 @@ DDC there will be no errors despite missing `allowInterop` calls, because DDC
|
|||
uses JS calling semantics by default. When compiling with Dart2JS the
|
||||
`allowInterop` utility must be used.
|
||||
|
||||
#### Making a Dart function callable from JavaScript
|
||||
|
||||
To provide a Dart function callable from JavaScript by name use a setter
|
||||
annotated with `@JS()`.
|
||||
|
||||
```dart
|
||||
@JS()
|
||||
library callable_function;
|
||||
|
||||
import 'package:js/js.dart';
|
||||
|
||||
/// Allows assigning a function to be callable from `window.functionName()`
|
||||
@JS('functionName')
|
||||
external set _functionName(void Function() f);
|
||||
|
||||
/// Allows calling the assigned function from Dart as well.
|
||||
@JS()
|
||||
external void functionName();
|
||||
|
||||
void _someDartFunction() {
|
||||
print('Hello from Dart!');
|
||||
}
|
||||
|
||||
void main() {
|
||||
_functionName = allowInterop(_someDartFunction);
|
||||
// JavaScript code may now call `functionName()` or `window.functionName()`.
|
||||
}
|
||||
```
|
||||
|
||||
## Known limitations and bugs
|
||||
|
||||
### Differences betwenn Dart2JS and DDC
|
||||
|
||||
Dart's production and development JavaScript compilers use different calling
|
||||
conventions and type representation, and therefore have different challenges in
|
||||
JavaScript interop. There are currently some know differences in behavior and
|
||||
bugs in one or both compilers.
|
||||
|
||||
#### allowInterop is required in Dart2JS, optional in DDC
|
||||
|
||||
DDC uses the same calling conventions as JavaScript and so Dart functions passed
|
||||
as callbacks can be invoked without modification. In Dart2JS the calling
|
||||
conventions are different and so `allowInterop` or `allowInteropCaptureThis`
|
||||
must be used for any callback.
|
||||
|
||||
**Workaround:**: Always use `allowInterop` even when not required in DDC.
|
||||
|
||||
#### Callbacks allow extra ignored arguments in DDC
|
||||
|
||||
In JavaScript a caller may pass any number of "extra" arguments to a function
|
||||
and they will be ignored. DDC follows this behavior, Dart2JS will have a runtime
|
||||
error if a function is invoked with more arguments than expected.
|
||||
|
||||
**Workaround:** Write functions that take the same number of arguments as will
|
||||
be passed from JavaScript. If the number is variable use optional positional
|
||||
arguments.
|
||||
|
||||
#### DDC and Dart2JS have different representation for Maps
|
||||
|
||||
Passing a `Map<String, String>` as an argument to a JavaScript function will
|
||||
have different behavior depending on the compiler. Calling something like
|
||||
`JSON.stringify()` will give different results.
|
||||
|
||||
**Workaround:** Only pass object literals instead of Maps as arguments. For json
|
||||
specifically use `jsonEncode` in Dart rather than a JS alternative.
|
||||
|
||||
#### Missing validation for anonymous factory constructors in DDC
|
||||
|
||||
When using an `@anonymous` class to create JavaScript object literals Dart2JS
|
||||
will enforce that only named arguments are used, while DDC will allow positional
|
||||
arguments but may generate incorrect code.
|
||||
|
||||
**Workaround:** Try builds in both development and release mode to get the full
|
||||
scope of static validation.
|
||||
|
||||
### Sharp Edges
|
||||
|
||||
Dart and JavaScript have different semantics and common patterns which makes it
|
||||
easy to make some mistakes, and difficult for the tools to provide safety. These
|
||||
sharp edges are known pitfalls.
|
||||
|
||||
#### Lack of runtime type checking
|
||||
|
||||
The return types of methods annotated with `@JS()` are not validated at runtime,
|
||||
so an incorrect type may "leak" into other Dart code and violate type system
|
||||
guarantees.
|
||||
|
||||
**Workaround:** For any calls into JavaScript code that are not known to be safe
|
||||
in their return values, validate the results manually with `is` checks.
|
||||
|
||||
#### List instances coming from JavaScript will always be `List<dynamic>`
|
||||
|
||||
A JavaScript array does not have a reified element type, so an array returned
|
||||
from a JavaScript function cannot make guarantees about it's elements without
|
||||
inspecting each one. At runtime a check like `result is List` may succeed, while
|
||||
`result is List<String>` will always fail.
|
||||
|
||||
**Workaround:** Use a `.cast<String>().toList()` call to get a `List` with the
|
||||
expected reified type at runtime.
|
||||
|
||||
#### The `JsObject` type from `dart:js` can't be used with `@JS()` annotation
|
||||
|
||||
`JsObject` and related code in `dart:js` uses a different approach and may not
|
||||
be passed as an argument to a method annotated with `@JS()`.
|
||||
|
||||
**Workaround:** Avoid importing `dart:js` and only use the `package:js` provided
|
||||
approach. To handle object literals use `@anonymous` on an `@JS()` annotated
|
||||
class.
|
||||
|
||||
## Reporting issues
|
||||
|
||||
|
|
Loading…
Reference in a new issue