From b6ddf7349a73808ed2f32fdff7ca21f885faaaf2 Mon Sep 17 00:00:00 2001 From: Marya Belanger Date: Mon, 6 Feb 2023 12:10:01 -0800 Subject: [PATCH] outline and first drafts for some pages remove broken link add tutorial outline restructure new pages left out of last commit --- src/web/js-interop/dom.md | 38 ++++++ src/web/js-interop/index.md | 125 ++++++++++++++++++++ src/web/js-interop/js-app.md | 38 ++++++ src/web/js-interop/js-util.md | 50 ++++++++ src/web/js-interop/js_util.md | 6 + src/web/js-interop/past-js-interop.md | 59 ++++++++++ src/web/js-interop/reference.md | 162 ++++++++++++++++++++++++++ src/web/js-interop/test-and-mock.md | 45 +++++++ src/web/js-interop/tutorials.md | 29 +++++ 9 files changed, 552 insertions(+) create mode 100644 src/web/js-interop/dom.md create mode 100644 src/web/js-interop/index.md create mode 100644 src/web/js-interop/js-app.md create mode 100644 src/web/js-interop/js-util.md create mode 100644 src/web/js-interop/js_util.md create mode 100644 src/web/js-interop/past-js-interop.md create mode 100644 src/web/js-interop/reference.md create mode 100644 src/web/js-interop/test-and-mock.md create mode 100644 src/web/js-interop/tutorials.md diff --git a/src/web/js-interop/dom.md b/src/web/js-interop/dom.md new file mode 100644 index 0000000000..025183c311 --- /dev/null +++ b/src/web/js-interop/dom.md @@ -0,0 +1,38 @@ +--- +title: How to interop with DOM APIs +description: +--- + +{{site.why.learn}} + * How to... +{{site.why.end}} + +// *Introdcution paragraphs* + +## Background concepts + +The following sections provide some extra background and information +around the technologies and concepts used in the tutorial. +To skip directly to the tutorial content, +go to [Steps](#steps). + +### Topic/concept 1 + +### Topic/concept..n + +## Steps + +### Prerequisites + +Before you begin, you'll need... +* + +### Actionable step 1 + +Step subsections should be actionalble, like "Build...", "Retrieve...", "Configure...", etc. + +### Actionable step...n + +## What next? + +Point to other tutorials, reference, etc. \ No newline at end of file diff --git a/src/web/js-interop/index.md b/src/web/js-interop/index.md new file mode 100644 index 0000000000..54c53b9bc6 --- /dev/null +++ b/src/web/js-interop/index.md @@ -0,0 +1,125 @@ +--- +title: JavaScript interoperability +short-title: JS interop +description: Integrate JavaScript code into your Dart web app. +--- + +The [Dart web platform](/overview#web-platform) supports communication with +JavaScript apps and libraries, and browser DOM APIs, using the `js_interop` +package, also known as `dart:js_interop`. +Web developers can benefit from using external JS libraries in their Dart code, without +having to rewrite anything in Dart. + +## Static interop + +The principal model of JS interop in Dart is **static interop**. +Static interop means interop that requires staticly typing external members, +rather than allowing dynamic invocations. +This enables [features](#features) like better performance, type soundness, and more. + +Performant static interop model is made possible by **[inline classes][]**. +Inline classes are a special class type that wrap an existing type into a new static type, +without the overhead of a traditional class, enabling zero cost wrapping. + +### Why static interop? + +Static interop represents the desire to decouple Dart's "core" from the platform +where it's embedded +(*maybe definition of "embedded" or examples here, like the browser, Flutter, etc.?*). + +Our [previous iterations of JS interop][] provided the capabillity +to access the embedder, but were not primed to handle that decoupling. +Too much of the process was entwined into the Dart side, +like writing all the bindings to the browser +(*not sure if I understood that note correctly*). +They also had limitations around using the DOM, +typing (which is a cornerstone of Dart), +and expanding to new interop types +(*this is me trying to refer to wasm without actually saying, idk if "interop types" is the right term*). + +Static interop addresses all of the shortcomings of Dart's previous JS interop solutions. +Check out the [Features](#features) section for a summary of improvements. + +[previous iterations of JS interop]: /web/js-interop/past-js-interop + +## Usage + +The following example implements inline class-based, static, JS interop in Dart, +using its key members and syntaxes: + +```dart +@JS() +library; +// library names aren't cool anymore... + +import 'dart:js_interop'; + +inline class SomeThing { + @JS('JSON.stringify') + external String stringify(Object obj); +} +// idk where `inline` fits into this but basically just show the key components as briefly as possible +``` + +// *Below the example, go through the steps line by line **and why**:* + +1. Append the `@JS` annotation to a `library` directive *so that....* + +2. Import `dart:js_interop`, which provides most of the tools needed for static interop, +including annotations, the representation type for inline classes, *... etc.* + +3. Create an `inline` class because it *allows you to...*, +which is the core of static interop. + +4. Use the `@JS` annotation to call a main-spaced function, or top level external member, from your JS app + + // *(or, call the external member from outside an inline class if you don't care about types?* +*idk if that's worth mentioning)* + +5. Use the `external` keyword to.... *(allow external and non-external members to communicate? idk)* + +6. *show external and non-external members interacting if that's not already shown?* + +## Features + +Inline class-based static interop enable the following features: + +
+| **Rename external members** | Complex JS member names can be re-written and represented in Dart | +| **Interact external and non-external members** | Process external calls, but "keep it on the type itself" (*idk what that means?*), without writing a separate function | +| **Zero cost wrapping** | Inline classes require virtually no overhead for re-typing external members as static types. (*idk*) | +| **Static error checking** | Since external members must be statically typed, static error checking on types and other parts of the interop is possible (partially sound, more work coming) | +| **Interop with DOM types** | *You can interop with DOM types because...?* | +| **Compatibility with Wasm** | Disallowing generative constructors from the model makes `js_interop` compatible with Wasm | +{:.table .table-striped .nowrap} +
+ + +## Up next + +For a complete summary of static JS interop concepts, members, and syntaxes: +* The [static interop reference][]. + +For tutorials and help: +* [How to interop with DOM APIs][] +* [How to interop with JavaScript libraries and apps][] +* [How to test and mock JavaScript interop in Dart][] + +For additonal types of documentation on `js_interop`: + * [pub.dev site page][] + * [API reference][] + +For information on other iterations of JS interop in Dart: + * [`dart:js_util`][] + * [Past JS interop][] + + +[inline classes]: / +[static interop reference]: /web/js-interop/reference +[How to interop with DOM APIs]: /web/js-interop/dom +[How to interop with JavaScript libraries and apps]: /web/js-interop/js-app +[How to test and mock JavaScript interop in Dart]: /web/js-interop/test-and-mock +[pub.dev site page]: / +[API reference]: / +[`dart:js_util`]: /web/js-interop/js-util +[Past JS interop]: /web/js-interop/past-js-interop diff --git a/src/web/js-interop/js-app.md b/src/web/js-interop/js-app.md new file mode 100644 index 0000000000..599b4a55c8 --- /dev/null +++ b/src/web/js-interop/js-app.md @@ -0,0 +1,38 @@ +--- +title: How to interop with JavaScript libraries and apps +description: +--- + +{{site.why.learn}} + * How to... +{{site.why.end}} + +// *Introdcution paragraphs* + +## Background concepts + +The following sections provide some extra background and information +around the technologies and concepts used in the tutorial. +To skip directly to the tutorial content, +go to [Steps](#steps). + +### Topic/concept 1 + +### Topic/concept..n + +## Steps + +### Prerequisites + +Before you begin, you'll need... +* + +### Actionable step 1 + +Step subsections should be actionalble, like "Build...", "Retrieve...", "Configure...", etc. + +### Actionable step...n + +## What next? + +Point to other tutorials, reference, etc. \ No newline at end of file diff --git a/src/web/js-interop/js-util.md b/src/web/js-interop/js-util.md new file mode 100644 index 0000000000..ccc902193b --- /dev/null +++ b/src/web/js-interop/js-util.md @@ -0,0 +1,50 @@ +--- +title: The dart:js_util library +short-title: dart:js_util +description: Overview of the utility library for JS interop +--- + +[**`dart:js_util` API docs**][] + +**We will continue to support `dart:js_util` alongside static interop.** + +The `dart:js_util` library, or just `js_util`, is a low-level utility library +for performing JS interop. Because `js_util` is so low-level, +it could potentially be able to provide more flexibility than static interop, +for example, in rare edge cases where `js_interop` is not expressive enough. +This is an exception to the rule; +**please always use static, inline-class based interop by default**. + +The `js_util` library is supported by the JS and `dart2wasm` backends. +It is slower and less ergonomic than `js_interop`. + +The best example of the difference in ergonomics between `js_interop` and +`js_util` is calling equivalent [`external`][] methods. +Each interop solution generates JavaScript code upon calling an `external` method: + +```dart +// js_util external call: +... + +// javascript generated: +... +``` + +The JavaScript code `external` generates for `js_util` is very verbose, +compared to the efficient, compact generation for `js_interop`: + +```dart +// js_interop external call: +... + +// javascript generated: +... +``` + +For optimal JS interop, only use `js_util` over static interop if you encounter +a use case that `js_interop` cannot address +(and please [let us know][] if you encounter such a use case). + +[**`dart:js_util` API docs**]: {{site.dart-api}}/dart-js_util/dart-js_util-library.html +[`external`]: /web/js-interop/reference#external +[let us know]: https://github.com/dart-lang/sdk/issues/new?assignees=&labels=web-js-interop&template=1_issue_template.md&title=Create+an+issue \ No newline at end of file diff --git a/src/web/js-interop/js_util.md b/src/web/js-interop/js_util.md new file mode 100644 index 0000000000..60ea261ee2 --- /dev/null +++ b/src/web/js-interop/js_util.md @@ -0,0 +1,6 @@ +--- +title: About `dart:js_util` +description: +--- + +// *I don't know if this needs to be a page or can just be on the "other" page* \ No newline at end of file diff --git a/src/web/js-interop/past-js-interop.md b/src/web/js-interop/past-js-interop.md new file mode 100644 index 0000000000..474d6ad979 --- /dev/null +++ b/src/web/js-interop/past-js-interop.md @@ -0,0 +1,59 @@ +--- +title: Past JS interop +description: Archive of past JS interop implementations +--- + +This page addresses previous iterations of JS interop for Dart: +* `package:js` +* `dart:js` + +**We do not recommend using any JS interop solution other than [static interop][].** + +Each of these tools still exist and are usable. +However, the static interop model +is more performant, provides more capabilities, +and will continue to be supported and developed. +If you are just starting out with JS interop in Dart, +please start with the static interop library, [`js_interop`][]. + +[static interop]: /web/js-interop +[`js_interop`]: {{site.dart-api}}/js_interop + +## `package:js` + +// *This section probably doesn't make any sense* + +[**`package:js` API docs**] + +**We will not continue to support `package:js` alongside static interop.** + +The `package:js` library can represent objects in different ways with its +class type annotations: + +* [`@JS`] +* [`@anonymous`] +* [`@staticInterop`] + +Because `package:js` supports dynamic invocations of external members (the +opposite of static interop), its static type checking capabilities are +much more limited than static interop, and therefore cannot be fully sound. +For the same reason, `package:js` can not interop with [DOM APIs][]. + +[**`package:js` API docs**]: {{site.pub-pkg}}/js +[`@JS`]: /web/js-interop/reference#js +[`@Anonymous`]: /web/js-interop/reference#others +[`@staticInterop`]: /web/js-interop/reference#staticinterop +[DOM APIs]: /web/js-interop/dom + +## `dart:js` + +[**`dart:js` API docs**] + +**We will not continue to support `dart:js` alongside static interop.** + +The `dart:js` library is a low-level API for non-static interop with JavaScript. +It's wrapper-based model requires much more overhead, +and is much more expensive and slow, +than static interop's zero-cost wrapper model. + +[**`dart:js` API docs**]: {{site.dart-api}}/dart-js/dart-js-library.html \ No newline at end of file diff --git a/src/web/js-interop/reference.md b/src/web/js-interop/reference.md new file mode 100644 index 0000000000..911f10abd7 --- /dev/null +++ b/src/web/js-interop/reference.md @@ -0,0 +1,162 @@ +--- +title: JS interop reference +description: A glossary of key terms and concepts in JS interop. +--- + +## Members + +// *I'm not sure if members, syntax, etc are interchangeable or different categories,* +*so rearrange / add more headings as needed* + +### Inline classes + +[Inline classes][] are a language feature independent of JS interop and static interop. +They are a special kind of class that wraps an existing type into a new static type, without the overhead of a traditional class. + +In the context of JS interop and static interop, +inline classes are an entirely static type representation of a JavaScript object. +They consume no additional memory, as opposed to using the representation type directly. +This zero-cost wrapper capability makes static interop possible. + +Inline classes can call *non-static* external fields, getters, setters, +and methods, as well as *static* external getters, setters, and methods. + +// *You should always wrap external types with inline classes?* + + +#### Usage: + +```dart +// + +// + +// +``` + +[Inline classes]: / + +// *TO DO: link to inline class page* + +### `external` + +The [`external` keyword][] calls a method from an external source. +It is not exclusive to JS interop or static interop. +To specify external *JavaScript* members, +you need to use the `@JS` annotation with `external`. + +#### Usage: + +```dart +// + +// + +// +``` + +[`external` keyword]: https://spec.dart.dev/DartLangSpecDraft.pdf#External%20Functions + +### Top-level external members + +Communication with top-level external members is a core feature of static interop, +though not exclusive to it. We have improved it to be more sound for static interop. + +You can call a main-spaced function from a JavaScript app +without concern for type using the [`@JS` annotation](#js). + +// *Why/when will users want to use this/ not be concerned with type?* + +#### Usage: + +```dart +// +@JS(‘...’) + +// + +// +``` + +### External factories + +External factories are not exclusive to static interop, +but are an importatnt part of the interface. +You can use a factory to instantiate a JavaScript object. + +// *You will want to do this because/when...* + +#### Usage: + +```dart +// + +// + +// +``` + +### Extensions with external members + +// *Does this go under external, or extensions, or...?* + +Extensions extend types. When you have an external class that you don't own, +and you don't want to add members to it, you can simply extend it. +Just write an extension and add members. + +// *More detail on when/why you might want to use this maybe?* + +#### Usage: + +```dart +// + +// + +// +``` + +## Annotations + +### `@JS` + +The `@JS` annotation belongs to the `dart:js_interop` library. +It specifies that you're using JavaScript interop, +as opposed to any other kind of interop. +It provides the bindings between a JavaScript API and your Dart API. +The use of `@JS` interop, combined with [inline classes](#inline-classes), +is what makes static interop possible. + +#### Usage: + +```dart +// append to library directive + +// call main-spaced JS function when you're not concerned with type (if that's a feature? idk) + +// specify `external` declaration is JS +``` + +The `@JS` annotation was also a member of one of Dart's past JS interop solutions, +`package:js`. You can read more about that on the [Past JS interop][] page. + +[Past JS interop]: /web/js-interop/past-js-interop + +### `@staticInterop` + +The `@staticInterop` annotation of `package:js` was an intermeditate static interop +solution before developing the complete, inline-class based, static interop model. +Inline classes and the `@JS` annotations replace the functionality of `@staticInterop`. + +#### Usage: + +```dart +// using @staticInterop +... + +// same example using @JS + inline classes +... +``` + + + diff --git a/src/web/js-interop/test-and-mock.md b/src/web/js-interop/test-and-mock.md new file mode 100644 index 0000000000..23678bc557 --- /dev/null +++ b/src/web/js-interop/test-and-mock.md @@ -0,0 +1,45 @@ +--- +title: How to test and mock JavaScript interop in Dart +description: +--- + +{{site.why.learn}} + * How to... +{{site.why.end}} + +// *Introdcution paragraphs* + +## Background concepts + +The following sections provide some extra background and information +around the technologies and concepts used in the tutorial. +To skip directly to the tutorial content, +go to [Steps](#steps). + +### Topic/concept 1 + +### Topic/concept..n + +## Export steps + +// *make sure to link to this content: https://pub.dev/packages/js/versions/0.6.6#jsexport-and-js_utilcreatedartexport* + +### Actionable step 1 + +Step subsections should be actionalble, like "Build...", "Retrieve...", "Configure...", etc. + +### Actionable step...n + +## Test/mock steps + +// *make sure to link to this content: https://pub.dev/packages/js/versions/0.6.6#js_utilcreatestaticinteropmock + +### Actionable step 1 + +... + +### Actionable step...n + +## What next? + +Point to other tutorials, reference, etc. \ No newline at end of file diff --git a/src/web/js-interop/tutorials.md b/src/web/js-interop/tutorials.md new file mode 100644 index 0000000000..74eef4c408 --- /dev/null +++ b/src/web/js-interop/tutorials.md @@ -0,0 +1,29 @@ +--- +title: JS interop tutorials +description: Tutorials for common JavaScript interop use cases in Dart. +--- + +## Tutorials + +### [How to interop with DOM APIs][] + +The browser exposes a number of DOM APIs accessible to Dart through the `dart:js_interop` library. +DOM APIs are the most common set of APIs Dart users will want to expose or interact with while using JS interop. This tutorial shows how to access these APIs and some of the common reasons you may want to use them. + +### [How to interop with JavaScript libraries and apps][] + +Have you found a JS library or app that does exactly what you want to do in your Dart code, but it's way too complex to rewrite in Dart? + +This tutorial will show you how to incorporate methods from an existing JS library. +It will also discuss build and serving options. + +### [How to test and mock JavaScript interop in Dart][] + +Exporting Dart objects with `@JSExport` creates a mock of the object at the JS level, which essentially allows you to test your Dart JS interop code. + +This tutorial will walk through both cases: simply exporting Dart objects to JS, +and then using that same functionality to test JS interop code. + +[How to interop with DOM APIs]: /web/js-interop/dom +[How to interop with JavaScript libraries and apps]: /web/js-interop/js-app +[How to test and mock JavaScript interop in Dart]: /web/js-interop/test-and-mock \ No newline at end of file