Open bryanrideshark opened 5 years ago
As I see it, supporting Web Assembly is not a language feature. It doesn't require any new language features, and since it's only available on the web, we would cautious about adding platform specific syntax. All it needs is a way to communicate with JavaScript, which we already have in JavaScript interop.
I'll move this question to the SDK repository and make it a question for the Dart-for-web team, who are in charge of JavaScript interop: Can they include WASM interop in dart:js or package:js?
A package for accessing raw WASM API from JS exists: https://pub.dev/packages/wasm_interop
common compile target which could be used as a bridge
Emscripten-compiled modules always require additional JS glue to do initialization and to pass any function parameter or return value that is not a number. So an actual interop would be between dart2js compiled JS and emscripten-supplied JS (which is already possible via existing JS-interop options).
Compiling Dart code to WASM may be interesting for some use cases but the final result would look like what emscripten does: a WASM module with auto-generated JS glue. So again, an actual interop would be between two JS codebases.
CC @yjbanov @mraleph @matanlurey
Could you clarify what you mean by "Web Assembly Support" because there are multiple different things this could mean, for example:
For example I'd love to use Dart/Flutter but doing so would be incredibly costly without much benefit. Were I able to use WASM in Dart however the story would be very different- Flutter would become just as easy to use as any other web interface were that the case.
It is not really clear to me why any form of WASM support makes it easier for you to use Flutter.
You can already use any native language in your Flutter application, you don't really need any WASM support for that. Of course you need to figure out interoperability story because Flutter framework is written in Dart so it works best when actually used from Dart and not from some other language.
Say you want to use Flutter class StatefulWidget
from C++ code - how is this supposed to work? What does it even mean? WASM does not magically answer this question.
Since we have an issue ( #32894 ) for compilation, let's use this for interop. We may want to split the native and web cases ( @mraleph 's first two bullets) at some point, but one use case might be deploying / sharing C++ components between Web and native targets.
We are interested in Google i18n about using WASM in native environments with Dart. See https://github.com/dart-lang/sdk/issues/32894#issuecomment-513325349
@nex3 – do you already have an issue open on this?
@kevmoo I don't think so.
Using WASM from Dart is something I'm interested in seeing as someone with a vested interest in Dart's success. WASM is extremely portable (any language could add support for it, and it's usable in the browser), it will provide a clearly-defined interop interface for high-level languages, and it's likely to be quite performant for algorithmically-intensive code. This combination positions it very well for becoming the de facto standard platform for self-contained libraries. Library authors are motivated to target WASM because it'll make their libraries easy for downstream users across all manner of languages and platforms to use, and languages will be motivated to support it because so many libraries exist. The normal bootstrapping problem a network effect like this will be smashed by having support from the two most widely-used platforms, Node.js and the browser, from the word go.
If Dart gets ahead of the curve and starts adding support for WASM now, it'll have access to (and input into) this ecosystem as it grows, making it easier and more attractive for new users to move to Dart. But if you wait until WASM support is de rigueur for any serious language, you'll have to exert the same energy playing catch-up that could have instead been a competitive advantage.
I was more wanting to use WASM inside Dart, in a mobile Flutter app. I maintain a large enterprise codebase which must be able to work in the browser; Moving to Flutter is simply not feasible, because as it stands, it would require an entire rewrite of important business logic, etc.
If I could use WASM to contain my business logic etc. then I could easily move to a Flutter app as I would need to do, is import the appropriate WASM module.
Actually @bryanrideshark as far I can tell Dart will support wasmerio for loading web assembly modules, so you don't have to be worry about that. I think it is behind an experimental flag on master.
I'm guessing that @sachaarbonel you mean #37882 so this is very exciting to see support for wasm libraries coming to Dart and I assume eventually to Flutter?
Yep exactly @maks
you mean wasmvm on dart? i need this too
For everybody tracking this issue. We are currently evaluating how to move multiplatform Dart<->WASM interop forward. Similarly to our C FFI work we would like to collect some examples of code that people would like to use in their Dart applications via WASM. So if you have one that is open source please leave a comment here or on #37882 with a link to the source and which platforms you would like to use it on (Flutter on iOS/Android/Desktop/Web, Dart Web), please also include information if you have ever tried running this library in WASM before. Thank you.
The i18n Engineering team at Google is building a cross-platform standard i18n library, which we intend to make available via WASM (internal link http://go/omnicu, public link http://bit.ly/omnicu-charter). Dart supporting WASM would be a big boost.
Another use case separate from i18n that I'm interested in is to use 2D graphics libraries, such as Cairo. I have not done it personally, but a quick Google search brings up a few different examples of how to use Cairo on the web via WASM.
That's awesome @sffc. We are working on bringing universality to the WebAssembly modules, integrating Wasm into multiple languages (we already have integrations for Python, PHP, Rust, Ruby, Elixir, C#, Go, C, C++...)
Would be great to chat and see how we can make omnicu usable from all this languages, including Dart as well!
Here's my email, in case is useful for following up syrus@wasmer.io :)
Would be nice to use in combination with skia canvaskit so that we can have flutter support for web based designops tools like storybook.
@codemasterover9000 FWIW you can use CanvasKit as the rendering backend in Flutter on the Web already (still experimental though). All you need to do is pass --dart-define=FLUTTER_WEB_USE_SKIA=true
to flutter run
or flutter build web
. When you use the normal Canvas
and SceneBuilder
we'll use CanvasKit behind the scenes.
@mraleph
I would like to use libraries written in "rust" compiled to wasm, directly in dart projects (AngularDart,Flutter for Web,...), like the lib "photon_rs" https://silvia-odwyer.github.io/photon/ without the need to create javascript glue files, a way for the dart compiler to create the glue would be excellent.
https://github.com/insinfo/photon-test
Something like that
mod utils;
use wasm_bindgen::prelude::*;
use web_sys::{HtmlCanvasElement};
//for production use: wasm-pack build --target no-modules --release
//for dev use: wasm-pack build --target no-modules --debug
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
#[wasm_bindgen]
extern "C" {
// Use `js_namespace` here to bind `console.log(..)` instead of just
// `log(..)`
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
// The `console.log` is quite polymorphic, so we can bind it with multiple
// signatures. Note that we need to use `js_name` to ensure we always call
// `log` in JS.
#[wasm_bindgen(js_namespace = console, js_name = log)]
fn log_u32(a: u32);
// Multiple arguments too!
#[wasm_bindgen(js_namespace = console, js_name = log)]
fn log_many(a: &str, b: &str);
}
macro_rules! console_log {
// Note that this is using the `log` function imported above during
// `bare_bones`
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}
#[wasm_bindgen]
pub fn greet(canvas: HtmlCanvasElement) {
//alert("Hello, teste!");
console_log!("greet {:?}", canvas.width());
}
[package]
name = "teste"
version = "0.1.0"
authors = ["insinfo <insinfo2008@gmail.com>"]
edition = "2018"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.74" #0.2.63
js-sys = "0.3.51"
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.6", optional = true }
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
#
# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
wee_alloc = { version = "0.4.5", optional = true }
[dev-dependencies]
wasm-bindgen-test = "0.3.24"
wasm-bindgen-futures = "0.4.24"
[dependencies.web-sys]
version = "0.3.51"
features = [
"Document",
"Element",
"HtmlElement",
"Node",
"Window",
"CanvasRenderingContext2d",
"ImageData",
"HtmlCanvasElement",
"HtmlImageElement",
"console",
'CssStyleDeclaration',
'EventTarget',
]
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
import 'dart:wasm';
import 'dart:html';
//maybe analyze this at compile time
external import * as wasm from './lib.wasm';
@wasm('greet')
external void greet(CanvasElement canvas);
is there any way to do something like this today?
@insinfo
This Gentleman is doing something interesting https://dev.to/sunshine-chain/dart-meets-rust-a-match-made-in-heaven-9f5
@tsavo-vdb-knott although I appreciate the article written at this link, the article itself only shows dart ffi interacting with shared dynamic libraries c, it seems out of the topic covered here, dart ffi does not have support yet for libraries written in c compiled for web assembly, if if dart ffi were web assembly compatible it would be fantastic.
@insinfo if all you want is to do this with Dart in Webbrowsers, then no, I don't think this is possible yet.
But if what you mean by "dart projects" also includes Dart on desktop then the dart:wasm
package does allow you to use wasm modules from Dart. I believe support for Flutter is coming soon too. Perhaps you could use this as a starting point to enhance that package to work on Web too.
I also wrote up my experience of using the package to make use of a codebase written in Assemblyscript so it's definitely already usable for codebases originally written to be used within webbrowsers.
I'm personally interested in using a C library on mobile and web. One way I'm thinking about going about this is:
However this would be cumbersome. It would be easier if I could compile to wasm for all platforms.
By the way, https://github.com/fzyzcjy/flutter_rust_bridge already supports Flutter Web to call WASM (compiled from Rust) with safety etc.
Sweet @fzyzcjy !!
Thanks! @kevmoo
Oh forget to say, thanks @Desdaemon for contributing the implementation!
We've shipped the Wasm backend as experimental with Dart 3.3 and as stable with 3.4 (it's still experimental). Closing as completed.
Does Dart support loading WASM libraries, or only emitting them? If the latter and not the former, I don't think this should be closed yet.
We can compile Dart to Wasm, and interact with other Wasm modules in Dart compiled to Wasm.
The latter is done via Native
. AFAIK this is how Flutter interacts with SkWasm (e.g. in https://github.com/flutter/engine/tree/main/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw).
Good to know, thanks. It's also worth noting that in 3.4 dart compile
doesn't list wasm as an option, and dart compile wasm
explicitly says *NOTE*: Compilation to WasmGC is experimental.
Can you clarify whether or not this is in fact considered stable, and if so whether these should be considered UI bugs in the CLI?
Ah, my bad, I read the release notes wrong. It looks like we still advertise it as experimental. I've updated my original comment.
The latter is done via Native. AFAIK this is how Flutter interacts with SkWasm
We discussed this a little bit today, Native
works today but we will limit its usage to SDK and Flutter repo. For users that want to interact with any Wasm module we will design and implement a separate mechanism.
Good to know, thanks. It's also worth noting that in 3.4 dart compile doesn't list wasm as an option, and dart compile wasm explicitly says NOTE: Compilation to WasmGC is experimental. Can you clarify whether or not this is in fact considered stable, and if so whether these should be considered UI bugs in the CLI?
This has been removed in 004d6a3fad85e53c0b6f36d7b4e84993db9e1050 and the Compile Dart to Wasm bug was closed.
Cross-linking other bugs:
dart:ffi
work on web)We could consider closing this issue in favor of the more concrete ones listed above. wdyt?
- Running dart2wasm-compiled code in non-JS environments: Issue 53884
We could consider closing this issue in favor of the more concrete ones listed above. wdyt?
@mkustermann I feel that the issue above + this one would easily translate in WASI support
The latter is done via Native. AFAIK this is how Flutter interacts with SkWasm
We discussed this a little bit today,
Native
works today but we will limit its usage to SDK and Flutter repo. For users that want to interact with any Wasm module we will design and implement a separate mechanism.
@osa1 seeking a bit of clarification on the direction here:
1) Does this mean that, at some point in future, it won't be possible for me to create any Dart library that uses @ffi.Native
to invoke a method in some external C library on any platform? Or just that we won't be able to do so when compiling to WASM? Or is that something Flutter-specific?
2) Why is dart:ffi
specifically not suitable for WASM? Is it because it's based around the 'native' memory paradigm (e.g. single shared linear memory), which doesn't accommodate WasmGC or multiple linear memory instances? Or is there some other reason?
@nmfisher
Does this mean that, at some point in future, it won't be possible for me to create any Dart library that uses @ffi.Native to invoke a method in some external C library on any platform? Or just that we won't be able to do so when compiling to WASM? Or is that something Flutter-specific?
This is when compiling to Wasm. Other platforms/targets will work as before.
Why is dart:ffi specifically not suitable for WASM? Is it because it's based around the 'native' memory paradigm (e.g. single shared linear memory), which doesn't accommodate WasmGC or multiple linear memory instances? Or is there some other reason?
I think most (probably even all) of dart:ffi
can be supported with the current Wasm + GC instructions, and I think we will need to support it at some point to allow using emscripten-generated modules with dart2wasm-generated modules. The main problem, as I see it, is that it needs more work, and we may have to do breaking changes to the currently supported (only allowed internally in Flutter) version of dart:ffi
. Current version was implemented based on what we need in Flutter. It's easier to disallow it for now and release it when it's properly supported.
I think we can't properly support multiple linear memories (and we certainly don't need to support it) for dart:ffi
. The API assumes there's one shared memory with all the FFI code.
(@mkustermann may have more thoughts on this)
@nmfisher As @osa1 alluded to
dart:ffi
has been designed for native (i.e. Dart VM) and is fully supported theredart:ffi
in dart2wasm (just enough to support flutter engine use cases). But it's far from being as robust and feature complete as the support the VM has. Because of this we disallow using it for the time being.dart:ffi
can be made to work well on the web (tracking bug: dart:ffi for web). It may require a different API, it may have smaller feature set, ... - to be figured out. Please subscribe to dart:ffi for web. This support will most likely be there for all web compilers (not just dart2wasm).
=> It requires some work, stay tuned!Thanks for the responses @osa1 and @mkustermann. I've been posting about this on Twitter too, but I figure it's better to move it here for a more fruitful discussion :)
By way of background, I was using dart:ffi
, package:ffi
and package:ffigen
so that my Dart library could load symbols from native libraries across all platforms via ffi.Native
see here for an example.
This works exceptionally well on desktop/mobile. On web/WASM, I can compile the native library via emscripten, generate the native<->Dart bindings with ffigen
, compile the Dart library to WASM, pass the emscripten library to the dart2wasm module in JS at instantiation time, and now both Dart and emscripten libraries have access to the same address space (there's a lot of passing pointers around).
This required some hacks to get around missing dart:ffi
functionality. I had previously raised the problems here, and the response was that they wouldn't be fixed because dart:ffi
wouldn't be used on web going forward. That's fine - I understand that, no complaint.
However, pulling WASM support for dart:ffi
before the replacement was in place is a bit frustrating. I know it wasn't 100% complete/stable, but a subset was - after all, that's what Flutter relies on. What was the downside to just keeping it publicly available? There may have been a few GitHub issues filed saying "dart:ffi isn't working on WASM", but couldn't those be adequately addressed with "dart:ffi isn't officially supported on WASM, that won't be fixed until we have a replacement"?
It also feels a bit strange to grant the Flutter engine access to something that other apps can't use (I mean, if Flutter needs dart:ffi
to run on web wasm, other apps probably do too, right?). I'm fully behind the decision to create something like dart:wasm
(and I know the current "official" approach now is to use JS interop), but for continuity's sake, it didn't really seem like dart:ffi
was causing that many problems that it had to be nuked from the WASM target.
However, pulling WASM support for dart:ffi before the replacement was in place is a bit frustrating. I know it wasn't 100% complete/stable, but a subset was - after all, that's what Flutter relies on. What was the downside to just keeping it publicly available? There may have been a few GitHub issues filed saying "dart:ffi isn't working on WASM", but couldn't those be adequately addressed with "dart:ffi isn't officially supported on WASM, that won't be fixed until we have a replacement"?
It also feels a bit strange to grant the Flutter engine access to something that other apps can't use (I mean, if Flutter needs dart:ffi to run on web wasm, other apps probably do too, right?). I'm fully behind the decision to create something like dart:wasm (and I know the current "official" approach now is to use JS interop), but for continuity's sake, it didn't really seem like dart:ffi was causing that many problems that it had to be nuked from the WASM target.
Happy to explain the multitude of reasons that led to this decision:
dart:ffi
support - any user using dart:ffi
with wasm would be unable to iterate on their app with with DDC - and we have no intention in the short/medium term to make a hot-reload/hot-restart development wasm compiler. So we prefer to offer dart:ffi
if it works in both development & deployment modes, not just wasm-specific deployment mode.dart:ffi
APIs as well as the same feature set we have on native on the web. So we want to first come up with design & implementation on the web. If we put it out now, we'll get a bunch of bug reports - which we may be unable to fix in short term, make some users rely on it only for us to possibly break them a few months later.dart:ffi
in dart2wasm is just not. To back this up, let me give a concrete example: The following most trivial example crashes the tip-of-tree dart2wasm compiler:
import 'dart:ffi';
main() => print(Pointer<Int8>.fromAddress(0));
with
Exception in FactoryConstructorInvocation at file:///.../test.dart
Unhandled exception:
Bad state: No element
#0 List.single (dart:core-patch/growable_array.dart:354)
#1 Intrinsifier.generateStaticIntrinsic (package:dart2wasm/intrinsics.dart:810)
#2 CodeGenerator.visitStaticInvocation (package:dart2wasm/code_generator.dart:1777)
#3 StaticInvocation.accept1 (package:kernel/ast.dart:6586)
#4 CodeGenerator.wrap (package:dart2wasm/code_generator.dart:881)
#5 CodeGenerator.visitArgumentsLists (package:dart2wasm/code_generator.dart:2817)
...
dart.library.ffi
. Those packages are broken if the ffi-specific imports are used (instead of the web fallback paths). See e.g. flutter/issues/149984. We want those packages to work as well as in dart2js and not fail to compile or run.It's fantastic to see the community so eager to get this and build on top of it - it's very motivating for us. We'll get there, stay tuned!
Appreciate the response @mkustermann. I understand why dart:ffi
isn't stable, and also why the Dart team wouldn't want to open the door to support something known to be unstable (even if personally I'm happy with the "not officially supported, fix it yourself" response to any issue).
Why the exception for Flutter internals though? Rightly or wrongly, many people see Dart as the "Flutter language" rather than a fantastic language/platform in its own right. Giving Flutter "trusted" access to SDK internals doesn't help dispel that view.
Why the exception for Flutter internals though? Rightly or wrongly, many people see Dart as the "Flutter language" rather than a fantastic language/platform in its own right. Giving Flutter "trusted" access to SDK internals doesn't help dispel that view.
From a technical point of view, we allow any dart:*
library to import other internal dart:*
libraries - it's not specific to flutter in that sense. Flutter happens to have two dart-colon libraries (dart:ui
and dart:web_ui
) which can access dart:ffi
. But the flutter framework for example cannot use dart:ffi
. So if a 3rd party would come along and make a flutter-like framework, adds more dart:*
libraries, those would be allowed to import it as well.
From a practical standpoint: We e.g. don't have to maintain API stability. We can break the API at any point, update the corresponding flutter engine (i.e. dart:ui
/ dart:web_ui
) code - do so within a day or two without causing widespread breakages throughout our ecosystem. The bar for public APIs is much higher.
(In hindsight we should have started out with dart:_ffi
(just like we have dart:_wasm
, dart:_internal
, dart:_...
) and graduate it to dart:ffi
(or similar library) once it's ready)
dart:ui
is a Flutter SDK package, though. dart:ffi
isn't, it is a public Dart API that you can still call on any Dart (VM) platform. It sounds like the WASM implementation fell into a grey area where it was developed specifically for Flutter compatibility, published, but was never intended for public consumption (because it was intentionally incomplete). Understandable, but given it was published, and that Flutter still relies on it for WASM compilation, a graceful deprecation would have made things easier.
I don't want to take up any more of your time, though - you've acknowledged my feedback and there's probably nothing further to add. I'm sure you have many better things to spend your time on! I look forward to the next iteration of WASM interop on Dart.
Not to minimize how useful hot reload is, and not to discount other issues which are blocking ffi on web, but while better support for hot reload on web would definitely be useful, in practice it's not really working that well in web, and probably shouldn't block any dart features from shipping if it's not blocking Flutter itself from shipping web support.
Would it be possible to enable Web Assembly in Dart?
Were this to be possible, I think it would greatly increase investment in the language as existing codebases would have a common compile target which could be used as a bridge.
For example I'd love to use Dart/Flutter but doing so would be incredibly costly without much benefit. Were I able to use WASM in Dart however the story would be very different- Flutter would become just as easy to use as any other web interface were that the case.
Can we get an up/down on whether or not this is A possible, and B something the team would like to support in the future?