dart-lang / sdk

The Dart SDK, including the VM, dart2js, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
9.94k stars 1.53k forks source link

Latest Chrome Browser no longer works with Twilio Video/Programmable Video, issue seems to originate in the DART:JS package #55081

Open princefarming opened 4 months ago

princefarming commented 4 months ago

We have come across a critical issue where our users are unable to join a video call, when using the latest update from Chrome (version 122, for macOS it was -> 122.0.6261.69). The version before this worked fine and there was no code change from our end.

This issue below in gitlab describes the issue that we and others were facing which seems to originate in the DART:JS package, we also posted the workaround to fix the issue: https://gitlab.com/twilio-flutter/programmable-video/-/issues/261

#### General info

- Dart 3.3.0 (stable) (Tue Feb 13 10:25:19 2024 +0000) on "macos_arm64"
- on macos / Version 14.2.1 (Build 23C71)
- locale is en-CA

#### Project info

- sdk constraint: '>=3.0.0 <4.0.0'
- dependencies: assets_audio_player, badges, bloc, cached_network_image, camera, carousel_slider, chewie, collection, crypto, csv, cupertino_icons, dio, firebase_analytics, firebase_core, flutter, flutter_bloc, flutter_chat_bubble, flutter_downloader, flutter_localizations, flutter_markdown, flutter_native_timezone_updated_gradle, flutter_svg, fluttertoast, freezed_annotation, get, get_it, go_router, grouped_list, hive, hive_flutter, html, hydrated_bloc, image_picker, infinite_scroll_pagination, intl, intl_utils, json_annotation, logger, mime_type, path_provider, platform_detect, pointer_interceptor, provider, responsive_framework, retrofit, rxdart, shared_preferences, table_calendar, universal_html, url_launcher, video_player, webview_flutter
- dev_dependencies: bloc_test, build_runner, flutter_driver, flutter_lints, flutter_test, freezed, integration_test, json_serializable, mocktail, retrofit_generator, test
- elided dependencies: 4

#### Process info

| Memory |  CPU | Elapsed time | Command line                                                                    |
| -----: | ---: | -----------: | ------------------------------------------------------------------------------- |
|  36 MB | 0.0% |  02-00:37:56 | dart devtools --machine --allow-embedding                                       |
| 624 MB | 0.0% |  02-00:37:56 | dart language-server --protocol=lsp --client-id=VS-Code --client-version=3.82.0 |
|  56 MB | 0.0% |  02-00:37:56 | flutter_tools.snapshot daemon

My apologies if this isn't the correct place to post this, at this point we aren't quite sure where the responsibility lies.

srujzs commented 4 months ago

Thanks for filing! It's a little difficult to discern where the issue originates from. I can see some proposed fixes in different locations, but I can't quite tell from the issue what the original code looks like. Is there a repro you can perhaps share? Is the interop code in Flutter?

sigmundch commented 4 months ago

To add to @srujzs questions: where is the definition of JsMap that the gitlab issue discuses?

If something started failing due to a browser version update, it's soemtimes possible that the issue lies in how dart2js associates interceptors and something changing that breaks what interceptor is associated with the map-iterator. This typically affects package:js because it can't intercept anything that has a corresponding native type, but it wouldn't affect APIs written with @staticInterop or dart:js_interop, which are more resilient to changes in the underlying JavaScript types.

That said, testing Chrome 120, 121, and 122 I don't see any observable differences there at first glance. For example (new Map()).entries() seems to show "Map Iterator" as the result of Object.prototype.toString.call on all 3 browsers, which is what dart2js would use for determining the interceptor.

KaiChen-GetAHead commented 4 months ago

@srujzs @sigmundch thanks for the reply!

i've prepared a minimum code project here: https://github.com/kayatmin/jsinterop

this is only reproducible when flutter run --release or flutter run --profile, works perfectly with debug mode.

chrome console is generating this error msg NoSuchMethodError: method not found: 'mv': image

here's the flutter doctor -v: [√] Flutter (Channel stable, 3.16.5, on Microsoft Windows [Version 10.0.22631.3235], locale en-CA) • Flutter version 3.16.5 on channel stable at $\versions\3.16.5 • Upstream repository https://github.com/flutter/flutter.git • Framework revision 78666c8dc5 (3 months ago), 2023-12-19 16:14:14 -0800 • Engine revision 3f3e560236 • Dart version 3.2.3 • DevTools version 2.28.4

[√] Windows Version (Installed version of Windows is version 10 or higher)

[√] Android toolchain - develop for Android devices (Android SDK version 33.0.1) • Android SDK at $\Android\Sdk • Platform android-33-ext4, build-tools 33.0.1 • ANDROID_HOME = $\Android\Sdk • Java binary at: $\Android\Android Studio\jbr\bin\java • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-9505619) • All Android licenses accepted.

[√] Chrome - develop for the web • Chrome at $\Google\Chrome\Application\chrome.exe

[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.5.4) • Visual Studio at $\2022\Community • Visual Studio Community 2022 version 17.5.33530.505 • Windows 10 SDK version 10.0.22000.0

[√] Android Studio (version 2022.1) • Android Studio at $\Android\Android Studio • Flutter plugin can be installed from: https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-9505619)

[√] VS Code (version 1.87.0) • VS Code at $\Programs\Microsoft VS Code • Flutter extension version 3.84.0

[√] VS Code (version 1.88.0-insider) • VS Code at $\Programs\Microsoft VS Code Insiders • Flutter extension version 3.85.20240301

[√] Connected device (3 available) • Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.22631.3235] • Chrome (web) • chrome • web-javascript • Google Chrome 122.0.6261.95 • Edge (web) • edge • web-javascript • Microsoft Edge 122.0.2365.59

[√] Network resources • All expected network resources are available.

• No issues found!

srujzs commented 4 months ago

It looks like for some reason we aren't intercepting the resulting Map Iterator as LegacyJavaScriptObject. dart2js believes that the interceptor is JavaScriptObject instead. The former has the right method:

    next$0(receiver) {
      return receiver.next();
    },

whereas calling next on the latter results in calling this:

    next$0($receiver) {
      return this.noSuchMethod$1($receiver, A.createInvocationMirror("next", "next$0", 0, [], [], 0));
    },

Normally this occurs when a type is bound to an @Native class but I can't see any such classes binding Map Iterator.

Because that's the case, you may be able to use @staticInterop instead to work around this. Replace the IteratorJS definition with the following:

@JS()
@staticInterop
class IteratorJS<T> {
  external factory IteratorJS();
}

extension IteratorJSExtension<T> on IteratorJS<T> {
  external IteratorValue<T> next();
}

This makes flutter run --profile work for me.

srujzs commented 4 months ago

It looks like Chrome 122 made Map Iterator a subtype of Iterator and that's the cause for the change in interceptor: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator. It looks like Firefox has not made this change and so the issue isn't reproducible there. Since we intercept Iterator as DomIterator in dart:html that would explain this. package:js types that aren't written with @staticInterop can't interop with types that are reserved by dart:html, and therefore we come across the above issue.

The recommendation is to try to move to static interop, which avoids the limitations of package:js types when it comes to not being able to interop with types that are reserved in dart:html. The @staticInterop code above should fix this issue for you, but long-term, consider migrating to interop extension types instead using dart:js_interop: https://dart.dev/interop/js-interop.