-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Closed
Labels
area-web-jsIssues related to JavaScript support for Dart Web, including DDC, dart2js, and JS interop.Issues related to JavaScript support for Dart Web, including DDC, dart2js, and JS interop.web-js-interopIssues that impact all js interopIssues that impact all js interop
Description
I was updating a JS interop part of a library and encountered that globalThis did not contain a property which should have pointed to a JS class.
The library that I am integrating is ZXing, a barcode scanning library, which supports the web.
To reproduce:
flutter create web_sample --platforms=web- Add the ZXing script in the head tag of the index.html
<script src="https://unpkg.com/@zxing/library@0.19.1" type="application/javascript"></script>
- Add the following code sample to
lib/interop.dart
lib/interop.dart
// ./lib/interop.dart
import 'dart:js_interop';
/// A static interop stub for the `Map` class.
///
/// This stub is here because the `js_types` from the Dart SDK do not yet provide a `Map` equivalent:
/// https://github.com/dart-lang/sdk/issues/54365
///
/// See also: https://github.com/dart-lang/sdk/issues/54365#issuecomment-1856995463
///
/// Object literals can be made using [jsify].
@JS('Map')
@staticInterop
class JsMap<K extends JSAny, V extends JSAny> implements JSObject {
external factory JsMap();
}
extension JsMapExtension<K extends JSAny, V extends JSAny> on JsMap<K, V> {
external V? get(K key);
external JSVoid set(K key, V? value);
}
/// The JS interop class for the ZXing BrowserMultiFormatReader.
///
/// See https://github.com/zxing-js/library/blob/master/src/browser/BrowserMultiFormatReader.ts
@JS('ZXing.BrowserMultiFormatReader')
@staticInterop
class ZXingBrowserMultiFormatReader implements JSObject {
/// Construct a new ZXingBrowserMultiFormatReader.
///
/// The [hints] are the configuration options for the reader.
/// The [timeBetweenScansMillis] is the allowed time between scans in milliseconds.
///
/// See also: https://github.com/zxing-js/library/blob/master/src/core/DecodeHintType.ts
external factory ZXingBrowserMultiFormatReader(
JsMap? hints,
int? timeBetweenScansMillis,
);
}- Replace main.dart with
main.dart
import 'dart:js_interop';
import 'dart:js_util';
import 'package:flutter/material.dart';
import 'interop.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ZXingBrowserMultiFormatReader? reader;
@override
void initState() {
super.initState();
final JSObject? zxing = getProperty(globalThis, 'ZXing');
final JSObject? multiFormatReader = getProperty(globalThis, 'ZXing.BrowserMultiFormatReader');
print('ZXing is defined? ${zxing.isDefinedAndNotNull}');
print('ZXing.BrowserMultiFormatReader is defined? ${multiFormatReader.isDefinedAndNotNull}');
reader = ZXingBrowserMultiFormatReader(
JsMap(),
500,
);
print('reader variable is defined? ${reader?.isDefinedAndNotNull}');
print('reader is a ZXing.BrowserMultiFormatReader? ${instanceOfString(reader, 'ZXing.BrowserMultiFormatReader')}');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: const Center(),
);
}
}- Run the application with
flutter run -d chrome - Observe the following log:
ZXing is defined? true
ZXing.BrowserMultiFormatReader is defined? false
reader variable is defined? true
reader is a ZXing.BrowserMultiFormatReader? false
- Open the browser console, and enter the expression "globalThis.ZXing.BrowserMultiFormatReader"
This outputs
class extends L{constructor(t=null,e=500){const r=new ir;r.setHints(t),super(r,e)}decodeBitmap(t){return this.reader.decodeWithState(t)}}
It seems that the globalThis in Dart, is not fully in sync with the browser equivalent?
I have also tried using the callAsConstructor<T>() utility, where I had ZXing as a separate interop type,
which had BrowserMultiFormatReader as a JSFunction, but that ended up with the same result. (probably because that also looks at globalThis)
dart info
#### General info
- Dart 3.2.3 (stable) (Tue Dec 5 17:58:33 2023 +0000) on "macos_x64"
- on macos / Version 14.1.2 (Build 23B92)
- locale is en-BE
#### Process info
| Memory | CPU | Elapsed time | Command line |
| -----: | ---: | -----------: | ------------------------------------------------------------------------------------------ |
| 57 MB | 0.0% | 03:23:00 | dart devtools --machine --allow-embedding |
| 59 MB | 0.0% | 02:51 | dart devtools --no-launch-browser |
| 963 MB | 0.0% | 03:23:00 | dart language-server --protocol=lsp --client-id=VS-Code --client-version=3.80.0 |
| 138 MB | 0.0% | 03:23:00 | flutter_tools.snapshot daemon |
| 202 MB | 1.3% | 03:20 | flutter_tools.snapshot run -d chrome |
| 602 MB | 0.0% | 03:19 | frontend_server.dart.snapshot --sdk-root <path>/ --incremental --target=dartdevc --experimental-emit-debug-metadata -DFLUTTER_WEB_AUTO_DETECT=true -DFLUTTER_WEB_CANVASKIT_URL=https:<path>/ --output-dill <path>/app.dill --packages <path>/package_config.json -Ddart.vm.profile=false -Ddart.vm.product=false --enable-asserts --track-widget-creation --filesystem-root <path>/flutter_tools.9p94Xi --filesystem-scheme org-dartlang-app --initialize-from-dill build/a072907fec955372e484c180f3334617.cache.dill.track.dill --platform file:<path>/ddc_outline_sound.dill --verbosity=error --sound-null-safety |
MacOS Sonoma 14.1.2
Google Chrome 120.0.6099.199 (Official Build) (x86_64)
Flutter 3.16.5 / Dart 3.2.3
Metadata
Metadata
Assignees
Labels
area-web-jsIssues related to JavaScript support for Dart Web, including DDC, dart2js, and JS interop.Issues related to JavaScript support for Dart Web, including DDC, dart2js, and JS interop.web-js-interopIssues that impact all js interopIssues that impact all js interop