@@ -7,6 +7,9 @@ end-to-end example.
77
88### Usage
99
10+ All Dart code interacting with JavaScript should use the utilities provided with
11+ ` package:js ` . Developers should avoid importing ` dart:js ` directly.
12+
1013#### Calling methods
1114
1215``` dart
@@ -94,7 +97,114 @@ DDC there will be no errors despite missing `allowInterop` calls, because DDC
9497uses JS calling semantics by default. When compiling with Dart2JS the
9598` allowInterop ` utility must be used.
9699
100+ #### Making a Dart function callable from JavaScript
101+
102+ To provide a Dart function callable from JavaScript by name use a setter
103+ annotated with ` @JS() ` .
104+
105+ ``` dart
106+ @JS()
107+ library callable_function;
108+
109+ import 'package:js/js.dart';
110+
111+ /// Allows assigning a function to be callable from `window.functionName()`
112+ @JS('functionName')
113+ external set _functionName(void Function() f);
114+
115+ /// Allows calling the assigned function from Dart as well.
116+ @JS()
117+ external void functionName();
118+
119+ void _someDartFunction() {
120+ print('Hello from Dart!');
121+ }
122+
123+ void main() {
124+ _functionName = allowInterop(_someDartFunction);
125+ // JavaScript code may now call `functionName()` or `window.functionName()`.
126+ }
127+ ```
128+
129+ ## Known limitations and bugs
130+
131+ ### Differences betwenn Dart2JS and DDC
132+
133+ Dart's production and development JavaScript compilers use different calling
134+ conventions and type representation, and therefore have different challenges in
135+ JavaScript interop. There are currently some know differences in behavior and
136+ bugs in one or both compilers.
137+
138+ #### allowInterop is required in Dart2JS, optional in DDC
139+
140+ DDC uses the same calling conventions as JavaScript and so Dart functions passed
141+ as callbacks can be invoked without modification. In Dart2JS the calling
142+ conventions are different and so ` allowInterop ` or ` allowInteropCaptureThis `
143+ must be used for any callback.
144+
145+ ** Workaround:** : Always use ` allowInterop ` even when not required in DDC.
146+
147+ #### Callbacks allow extra ignored arguments in DDC
148+
149+ In JavaScript a caller may pass any number of "extra" arguments to a function
150+ and they will be ignored. DDC follows this behavior, Dart2JS will have a runtime
151+ error if a function is invoked with more arguments than expected.
152+
153+ ** Workaround:** Write functions that take the same number of arguments as will
154+ be passed from JavaScript. If the number is variable use optional positional
155+ arguments.
156+
157+ #### DDC and Dart2JS have different representation for Maps
158+
159+ Passing a ` Map<String, String> ` as an argument to a JavaScript function will
160+ have different behavior depending on the compiler. Calling something like
161+ ` JSON.stringify() ` will give different results.
162+
163+ ** Workaround:** Only pass object literals instead of Maps as arguments. For json
164+ specifically use ` jsonEncode ` in Dart rather than a JS alternative.
165+
166+ #### Missing validation for anonymous factory constructors in DDC
167+
168+ When using an ` @anonymous ` class to create JavaScript object literals Dart2JS
169+ will enforce that only named arguments are used, while DDC will allow positional
170+ arguments but may generate incorrect code.
171+
172+ ** Workaround:** Try builds in both development and release mode to get the full
173+ scope of static validation.
174+
175+ ### Sharp Edges
176+
177+ Dart and JavaScript have different semantics and common patterns which makes it
178+ easy to make some mistakes, and difficult for the tools to provide safety. These
179+ sharp edges are known pitfalls.
180+
181+ #### Lack of runtime type checking
182+
183+ The return types of methods annotated with ` @JS() ` are not validated at runtime,
184+ so an incorrect type may "leak" into other Dart code and violate type system
185+ guarantees.
186+
187+ ** Workaround:** For any calls into JavaScript code that are not known to be safe
188+ in their return values, validate the results manually with ` is ` checks.
189+
190+ #### List instances coming from JavaScript will always be ` List<dynamic> `
191+
192+ A JavaScript array does not have a reified element type, so an array returned
193+ from a JavaScript function cannot make guarantees about it's elements without
194+ inspecting each one. At runtime a check like ` result is List ` may succeed, while
195+ ` result is List<String> ` will always fail.
196+
197+ ** Workaround:** Use a ` .cast<String>().toList() ` call to get a ` List ` with the
198+ expected reified type at runtime.
199+
200+ #### The ` JsObject ` type from ` dart:js ` can't be used with ` @JS() ` annotation
201+
202+ ` JsObject ` and related code in ` dart:js ` uses a different approach and may not
203+ be passed as an argument to a method annotated with ` @JS() ` .
97204
205+ ** Workaround:** Avoid importing ` dart:js ` and only use the ` package:js ` provided
206+ approach. To handle object literals use ` @anonymous ` on an ` @JS() ` annotated
207+ class.
98208
99209## Reporting issues
100210
0 commit comments