Open kenzieschmoll opened 1 month ago
@kenzieschmoll – keep in mind, we can use query param magic to force loading certain versions. So if there are contexts where wasm won't work, we can just disable them. Or we can make loading the wasm version opt-in for testing, etc.
Ha! just read your last bullet. 🤦
Ensure that the VS Code embedded web views support WasmGC (see background information on Chromium and V8)
The current version of VS Code uses Chromium v120 which sounds like it should support this. However, I don't know if there are things in Electron/VS Code themselves that might impact the user of this. @kenzieschmoll what's the easiest way for me to build DevTools using WASM (can I do it through devtools_tool serve
? hacking scripts locally to make this work would be fine for testing).
And when it is running, how do I confirm it is using the wasm version and didn't fall back to js?
what's the easiest way for me to build DevTools using WASM (can I do it through
devtools_tool serve
? hacking scripts locally to make this work would be fine for testing).And when it is running, how do I confirm it is using the wasm version and didn't fall back to js?
Patch the changes from https://github.com/flutter/devtools/pull/7867 and https://dart-review.googlesource.com/c/sdk/+/369100. Then run devtools_tool serve --wasm
.
If the wasm changes are picked up, you should see main.dart.wasm
, main.dart.mjs
, and canvaskit/skwasm.js
, canvaskit/skwasm.wasm
in the loaded sources. Here is what I see locally.
IntelliJ uses JxBrowser version 7.38.2 currently, which includes Chromium 124.0.6367.92 and should support WasmGC.
It's hard for me to tell what version of JCEF IntelliJ uses when that option is chosen by user setting, but JCEF is a few versions behind the CEF library, which currently is using Chromium 125 (https://cef-builds.spotifycdn.com/index.html).
In summary I think either implementation of embedded browser will be fine for wasm.
@yjbanov the sequencing will likely be that we'll work on shipping devtools in wasm in google after we decide to ship flutter web in wasm in google3
@kenzieschmoll
Patch the changes from https://github.com/flutter/devtools/pull/7867 and https://dart-review.googlesource.com/c/sdk/+/369100. Then run devtools_tool serve --wasm.
The first has already landed but I patched in the second. I added "--wasm" to my dart.customDevTools
setting. Inside VS Code, it seems to have loaded the JS version:
However if I open in an external browser it loads the wasm version, however it throws and the app doesn't load:
I presume the first issue is that whatever is being used to detect whether wasm is available is failing. @kevmoo is there an easy way for me to review (or step through) these conditions? Looking through flutter_bootstrap.js
I found a function that looked like it was doing that which runs:
let o = [0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 95, 1, 120, 0];
return WebAssembly.validate(new Uint8Array(o))
However if I run that myself in the console, it appears to return true
, so I think there may be other conditions.
Seems like the issue is that window.crossOriginIsolated
is false
The docs here confirm the headers in the CL above are required, but I see those are also set:
It's not clear to me why this value is false
. There's a similar issue at https://github.com/microsoft/vscode/issues/183765 from last year about this being the case on Github.dev and a link to a private repo with a fix, which I suspect is just setting the same headers.
I tracked this back to https://github.com/microsoft/vscode/issues/186614. It seems cross-origin-isolatation is currently disabled by VS Code. When it was enabled the were performance issues that resulted in it being reverted.
I tried running code --enable-coi
to force this enabled for testing, however the iframe with DevTools in it won't load at all:
Which seems to be because another header is not present:
I don't know the implications of adding that header.
Yes, if you're loading the app in an iframe, you will need to set a CORP header for the child document if you want cross origin isolation (which is needed for the multi-threaded rendering that the skwasm renderer does). I don't know exactly how the embedding of this works with VS Code. I think Cross-Origin-Resource-Policy: cross-origin
should be fine for this use case, as long as all the assets that devtools uses are also served with Cross-Origin-Resource-Policy: cross-origin
.
Thanks! Adding that header on its own didn't work, but then I found I needed allow="cross-origin-isolated"
on the iframe. With that, the flags are all true and the wasm version is used - and fails with:
This is the same error I posted above when running outside of VS Code. It's not clear to me if that's a DevTools or wasm bug?
This is the same error I posted above when running outside of VS Code. It's not clear to me if that's a DevTools or wasm bug?
I can't reproduce on Mac, so I am wondering if this is a Windows issue with wasm. CC @eyebrowsoffire
@DanTup Could you try building again with --name-section
enabled so we get a more useful stack trace? flutter build web --wasm --name-section
@eyebrowsoffire that flag didn't seem to work:
C:\Dev\Google\devtools\packages\devtools_app > C:\Dev\Google\devtools\tool\flutter-sdk\bin\flutter.bat build web --wasm --name-section --pwa-strategy=offline-first --no-tree-shake-icons
Could not find an option named "name-section".
I tried --no-strip-wasm
(which I saw in https://github.com/dart-lang/sdk/commit/a98ce03e13c530f919e79512119271a659c35974) which initially gave the same error, but Ctrl+refresh resulted in:
Uncaught RuntimeError: illegal cast
at _isFlutterGAEnabled inner (main.dart.wasm:0x38f4da)
at _awaitHelperWithTypeCheck closure at org-dartlang-sdk:///dart-sdk/lib/_internal/wasm/lib/async_patch.dart:97:16 (main.dart.wasm:0x1fdf8e)
at closure wrapper at org-dartlang-sdk:///dart-sdk/lib/_internal/wasm/lib/async_patch.dart:97:16 trampoline (main.dart.wasm:0x1fe083)
at _rootRunUnary (main.dart.wasm:0x1febae)
at _CustomZone.runUnary (main.dart.wasm:0x50f355)
at _Future._propagateToListeners (main.dart.wasm:0x1fe77a)
at _Future._completeWithValue (main.dart.wasm:0x1fedfc)
at _Future._asyncCompleteWithValue closure at org-dartlang-sdk:///dart-sdk/lib/async/future_impl.dart:735:29 (main.dart.wasm:0x20fbd6)
at closure wrapper at org-dartlang-sdk:///dart-sdk/lib/async/future_impl.dart:735:29 trampoline (main.dart.wasm:0x20fbec)
at _rootRun (main.dart.wasm:0x1fd210)
The code for that method is here:
The response from the server appears to be an empty string:
Which I guess is coming from here:
So possibly this code here is triggering the exception?
// A return value of 'null' implies Flutter tool has never been run so
// return false for Flutter GA enabled.
final responseValue = json.decode(resp!.body);
enabled = responseValue ?? false;
Yes, sorry, I meant --no-strip-wasm
, I got the dart compile wasm
commands confused with the flutter tool's.
There are no casts in that function from the user code that I can see. I wonder if something is being inlined? You can also pass -O0
and see if that disables some inlining and that might clarify what's going on here a bit.
There are no casts in that function from the user code that I can see
It's assigning responseValue
(if not null
) to enabled
. enabled
is a bool, responseValue
is a string (and my IDE says responseValue
is dynamic
. It's not clear to me why this would behave different for wasm though.
Using -O0
I get this (which does seem to line up):
main.dart.mjs:56 Type 'String' is not a subtype of type 'bool' in type cast
main.dart.mjs:56 at _isFlutterGAEnabled inner (http://127.0.0.1:9101/main.dart.wasm:wasm-function[34885]:0x5b2405)
at _awaitHelper closure at org-dartlang-sdk:///dart-sdk/lib/_internal/wasm/lib/async_patch.dart:83:16 (http://127.0.0.1:9101/main.dart.wasm:wasm-function[62766]:0x8183af)
at closure wrapper at org-dartlang-sdk:///dart-sdk/lib/_internal/wasm/lib/async_patch.dart:83:16 trampoline (http://127.0.0.1:9101/main.dart.wasm:wasm-function[62772]:0x8184b5)
at _rootRunUnary (http://127.0.0.1:9101/main.dart.wasm:wasm-function[2992]:0x3057e0)
at _rootRunUnary tear-off trampoline (http://127.0.0.1:9101/main.dart.wasm:wasm-function[62738]:0x817ef3)
at _CustomZone.runUnary (http://127.0.0.1:9101/main.dart.wasm:wasm-function[62613]:0x816525)
at _FutureListener.handleValue (http://127.0.0.1:9101/main.dart.wasm:wasm-function[2985]:0x30556f)
at _Future._propagateToListeners closure handleValueCallback at org-dartlang-sdk:///dart-sdk/lib/async/future_impl.dart:859:33 (http://127.0.0.1:9101/main.dart.wasm:wasm-function[2963]:0x304f15)
Since that code looks bogus to me, I retried in non-wasm mode and I see errors in the console - however unlike the wasm version, it doesn't stop DevTools loading (which is why I didn't notice it before). In wasm mode, I just get a white page with nothing rendered, but with JS DevTools loads and appears to function.
(@kenzieschmoll this seems like a bug though - that API seems to be hard-coded to return an empty string and the code doesn't seem to handle empty strings, it assumes null or a boolean?)
this seems like a bug though - that API seems to be hard-coded to return an empty string and the code doesn't seem to handle empty strings, it assumes null or a boolean?).
Yes this regressed recently. Fix is here: https://github.com/flutter/devtools/pull/7896
The DevTools codebase is prepared for building DevTools with dart2wasm thanks to the unblocking work here.
There are still a few requirements that we need to meet before moving this effort forward:
Compare the dart2wasm DevTools build to dart2js and file any issues that come up.
Blocking: