-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lack of documentation for migration from js to js_interop #55352
Comments
Is there any update on this? It seems nearly impossible to use wasm without more documentation on this. |
I think Marya has been working on an interop tutorial first and then this, but feel free to ask me questions in the meantime on how to port specific lines of code. The general model is similar to Looking at the OP edits:
This is mildly covered on that webpage, but there are two
In general, you should move code from classes to extension types on @JS('mapboxgl')
library mapboxgl.interop.ui.control.navigation_control;
import 'dart:js_interop';
import 'package:mapbox_gl_dart/src/interop/interop.dart';
// No need for `@JS` if not renaming, and no need for `@anonymous` as you can
// write an external constructor with named parameters directly (as shown below).
extension type NavigationControlOptionsJsImpl._(JSObject _) implements JSObject {
external bool get showCompass;
external bool get showZoom;
external bool get visualizePitch;
external factory NavigationControlOptionsJsImpl({
bool? showCompass,
bool? showZoom,
bool? visualizePitch,
});
}
@JS('NavigationControl')
extension type NavigationControlJsImpl._(JSObject _) implements JSObject {
external NavigationControlOptionsJsImpl get options;
external factory NavigationControlJsImpl(
NavigationControlOptionsJsImpl options);
external onAdd(MapboxMapJsImpl map);
external onRemove();
} |
Following the example with extension types, I can now no longer implement my own interface.
Which will give me an error saying XHROptions is not a supertype of JSObject. But I use my own interface for dependency inversion throughout my code. How can I with this new approach implement my own interfaces so my other projects won't break? |
What is Instead, if you want to still reuse the interface of extension type JavascriptXHROptions._(JSObject _) implements JSObject {}
...
final javascriptXHROptions = ...;
(javascriptXHROptions as XHROptions).someMethod(); Note that |
XHROptions is my own custom abstract class that serves as an interface only.
I just took it as an example as I have many of these interfaces. But my point was that before with package:js I was able to implement that interface like so
But with the new approach
This now seems like it's no longer possible. Because XHROptions is not a super type of JSObject, and I don't want it to be. I want the interace to be separated from any js related coupling. Instead I use it for dependency inversion in my other packages to avoid them being tightly coupled to any web or js related package. But now it seems I cannot implement it anymore with this new approach. So how do I migrate my package js code so that it doesn't break all my other packages because I cannot use the interfaces anymore. |
I see, you're just using it as an interface. Extension types by design do not allow virtual/dynamic dispatch, so you can't have an interop extension type implement an unrelated Dart class. One option to make this work (that will be slower) is a wrapper class: extension type JavascriptXHROptions._(JSObject _) implements JSObject {
// whatever interop members you might need
JavascriptXHROptions({String method});
external String method;
}
class JavascriptXHROptionsImpl implements XHROptions {
late final JavaScriptXHROptions _options;
JavascriptXHROptionsImpl({required String method}) {
_options = JavascriptXHROptions(method);
}
String get method => _options.method;
set method(String value) => _options.method = value;
} |
Thanks for the example. The irony, the very thing extension types would solve is the very thing they can't solve in a way. IMO most people would never couple their project tightly to javascript code as flutter is a multi platform framework and in general dependency inversion is very commonly used in the flutter ecosystem. So the new extension type mostly just adds more boilerplate code for framework users. Where the old way of doing it with the js package likely has similar performance to this approach but less boilerplate code. I'm a flutter user btw. |
Maybe. :) I've mostly seen that approach with more granular APIs that call a number of JS members and handle the results, so you need a wrapper class regardless in that case. However, in the case where you just need a set of options, like |
In most cases we don't need to have non-external members on a JS class. Also wouldn't you be able to write extensions for the package:js classes, it seems to work for me? I'm still not seeing the advantage of using an extension type for this, but perhaps I'm overlooking something. |
Sorry, my comment might have been confusing - it was in reference to specifically implementing a shared interface.
Right, but that's the same as extension types in that the non-
For dependency inversion, there isn't an advantage. I was mostly pointing out that it might not be worse than |
@srujzs your example is exactly what i ended up doing Converting over 8200 lines of pure interface code took like two days, so its very much manageable. The bigger issues i faced showed up as i tired to run the code after it was complied to wasm as suddenly the JS - dart interface becomes much stricter so any existing issue in the interface suddely start throwing errors. If you just complie to JS many issues don't show up. Managed to fix them tho. I also ran into issues with other lib's ablity to compile to wasm, so any futher work was put on hold untill the ecsosystem catches up. Most of these issues i expect to have been resolved by now. @duck-dev-go Pushed the full project if you need something to compare against: https://github.com/Ocell-io/mapbox-gl-dart/tree/new-js_interop |
Nice! Yeah, I expect the change in what types are allowed will be the bigger lift than the change to extension types.
Can you elaborate what you mean by this? Do you mean you saw errors going from |
Is saw the error after porting to js_interop and had a basic running version with js. Some issues only showed up after i tried to compling to wasm. This was a multistage process. dart2wasm showed issues during compiling, while dart2js complied just fine. After that i also had some runtime errors with dart2wasm that were tricky to debug, as there is no debugger for wasm, and the error message / stacktrace was lacking as there weren't even debug symbols. These two commit hold the changes required to get wasm running. |
Looking at the code again it seems that all (most?) issues where with the js object container layer not with the interop itself. |
Ah I see, this is partially a change in imports from |
With the recent beta release of wasm for flutter i wanted to try compling my application to the new target. As (somewhat) expected i ran into some js interop issues.
I tried to switch to the new package
import 'dart:js_interop';
but struggled to get it working as there seems to be very litte documentation on how to do the migration.Old code
Diff
The error i am getting is
Error: The '@JS' annotation from 'dart:js_interop' can only be used for static interop, either through extension types or '@staticInterop' classes.
I found some documentation in https://dart.dev/interop/js-interop/usage
e.g.
Before converting all the code in my dart js warper i would like to be sure that this is the correct approach. It would be great if you could also provide some concrete side by side examples of old js vs new js_interop code in the documentation.
Config
The text was updated successfully, but these errors were encountered: