Skip to content
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

Migrate to dart:js_interop and Extension Types #26

Open
pattobrien opened this issue Jul 4, 2024 · 8 comments
Open

Migrate to dart:js_interop and Extension Types #26

pattobrien opened this issue Jul 4, 2024 · 8 comments

Comments

@pattobrien
Copy link

Are there any plans to use the new js_interop features? I've been working on some experiment ts2dart converters (e.g. to create a VSCode Extension using Dart), and would love to work together to migrate to the new conventions.

Some of the topics I've been working on revolve around the following:

  • defining a JSON Schema meta-schema that represents a Dart js_interop IDL
  • creating typescript d.ts to Dart IDL converters using ts-morph
  • creating macros that generate the given Dart code from a given Schema

I'd love to begin discussing ways we could collaborate with the community to migrate to js_interop!

@Blimster
Copy link

Blimster commented Jul 4, 2024

Hi @pattobrien,

I just closed my issue #25. I opened it an hour before you, but you put much more effort into your description.

I'm also interested to work together on that topic. My final goal is to provide (almost) complete bindings for BabylonJS. I wrote a transpiler for that some years ago (see https://github.com/Blimster/babylon_dart/tree/main/generator). But it only supports maybe 40% of the BabylonJS API.

Next to your 3 bullets, I think 2 more things must be considered:

  • Sanitize (e.g. method overrides with less parameters)
  • Configuration to change the behavior of the transpiler

@pattobrien
Copy link
Author

pattobrien commented Jul 4, 2024

@Blimster ah amazing! what a nice coincidence :)

Sanitize (e.g. method overrides with less parameters)
Configuration to change the behavior of the transpiler

Good additional points.. Here's a little bit of insight into how I believe a very good DevX would go for library developers (e.g. BabylonDart), which allows configuration of generated code for both build_runner as well as macros.

  1. Convert BabylonJS .d.ts files to JSON Schema representation (fairly self-explanatory).
  2. Configure Typings base macro with the Babylon schema.
// babylon_dart/lib/macro.dart

class BabylonType extends TypingsMacro {
    const BabylonType(
      JsonPointer super.pointer,
    );
    
    @override
    TypescriptSchema get metaSchema => TypescriptSchema(
       defs: {
          'Engine': /* Engine type schema goes here */,
          'FreeCamera': /* FreeCamera type schema */,
          ...
        },
    );
}
  1. Use the above Macro to build the types:
// babylon_dart/lib/types/engine.dart

@BabylonType('#/defs/Engine') // here we tell the macro which type we're declaring
extension type Engine(JSObject value) implements JSObject {
  /* members are automatically generated */
  
  // alternatively we can override members of a type
  // by simply inlining a new method definition
  void resize() { /* custom resize definition */ }
}

Of course, we could also use a cli app to generate most of the above code for us, so that you wouldn't have to manually create declarations for the Engine type if you don't need to override any of its members.

Importantly, this kind of workflow would allow library developers to very easily work alongside the code generators, to modify the JS/TS types in ways that make sense for Dart developers. No additional code-gen configurations required.

What do you think?

@jodinathan
Copy link
Owner

I am not sure what kind of features in the new js_interop we coud use in Typings.

I've created a plugin for VSCode using Typings, you can check it here: https://github.com/jodinathan/element_tree_viewer/tree/main/plugins/element_tree_vscode

@pattobrien
Copy link
Author

pattobrien commented Jul 4, 2024

I am not sure what kind of features in the new js_interop we coud use in Typings.

It's not so much about new features, its that js_interop is the recommended mechanism for interop going forward. dart:js and dart:html are now considered legacy packages.

You can see some additional benefits of the migration here: https://dart.dev/interop/js-interop/past-js-interop

I've created a plugin for VSCode using Typings, you can check it here: https://github.com/jodinathan/element_tree_viewer/tree/main/plugins/element_tree_vscode

Appreciate this a lot! This will be great reference.

@jodinathan
Copy link
Owner

I am not sure what kind of features in the new js_interop we coud use in Typings.

It's not so much about new features, its that js_interop is the recommended mechanism for interop going forward. dart:js and dart:html are now considered legacy packages.

You can see some additional benefits of the migration here: https://dart.dev/interop/js-interop/past-js-interop

So, the new package:web from the Dart team is based on my old js_bindings.
Typings is already a new replacement for it.

So actually, you can ditch package:web (which I think there are too much boilerplate) and use Typings instead.

Check the wiki to know more about how Typings work and feel free to make any questions

@pattobrien
Copy link
Author

pattobrien commented Jul 4, 2024

Check the wiki to know more about how Typings work and feel free to make any questions

I'm familiar with how Typings and the rest of the packages work - it doesn't change the fact that dart:js, package:js, dart:html, and dart:js_utils (packages which Typings relies on) are now considered legacy packages in favor of dart:js_interop and extension types. These features were introduced very recently in Dart v3.3, and though support for the legacy packages will likely still remain for the forseeable future, they won't be getting updates as much as dart:js_interop will.

So actually, you can ditch package:web (which I think there are too much boilerplate) and use Typings instead.

You can probably understand that first-party Dart SDK support will almost always be preferred over a third party package - so it's likely that the JS- and browser-specific bindings in package:web and dart:js_interop will be preferred by the community over the equivalent bindings that exist in Typings. Typings would then focus on bindings from packages on npm.

But there's still a lot that can be re-used regarding the code-generation portion of this repository (i.e. ts2dart and ts_ast) - this code could be ported over to use the new js_interop library and Extension Types, so that users can generate Typings packages using the newer APIs that are now recommended by the Dart team.

Does that make sense?

@jodinathan
Copy link
Owner

Does that make sense?

it does to a degree.
Typings doesn't rely on dart:html and IIRC, the dart:js_interop uses the package:js and package:js_util.
So I may be mistaken, and probably am, but there is a chance that Typings is already on pair with the new interop stuff.

but, it has been quite some time that I've read about js_interop, so things should have changed.

Can you add some before->after of what the generated code would be?

@Blimster
Copy link

Blimster commented Jul 5, 2024

@jodinathan, you should really read the docs for the new js interop (https://dart.dev/interop/js-interop/past-js-interop). Starting with Dart 3.3, the preferred way for JS interop is to use Dart extension types together with types from dart:js_interop.

From the docs linked above a Dart binding for a JS class should now look like that:

extension type Time._(JSObject _) implements JSObject {
  external Time(int hours, int minutes);
  external factory Time.onlyHours(int hours);

  external static Time dinnerTime;
  external static Time getTimeDifference(Time t1, Time t2);

  external int hours;
  external int minutes;
  external bool isDinnerTime();

  bool isMidnight() => hours == 0 && minutes == 0;
}

That said, Typings have to be changed to generate Dart sources to use the new way for JS interop. The package:web is provided by the Dart team for browser APIs. It already uses the new JS interop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants