From 92c9e0da2f7eedc046639479d8e1df8633d5758c Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 11 Sep 2023 13:11:10 -0700 Subject: [PATCH 1/3] Fix JS interop signatures to use only JS types. --- lib/web_ui/lib/src/engine/app_bootstrap.dart | 26 +++------- .../engine/canvaskit/image_web_codecs.dart | 2 +- .../lib/src/engine/js_interop/js_loader.dart | 50 +++++++++++-------- .../lib/src/engine/js_interop/js_promise.dart | 41 ++++++--------- .../lib/src/engine/safe_browser_api.dart | 22 ++------ .../test/canvaskit/canvaskit_api_test.dart | 22 ++++---- .../test/engine/app_bootstrap_test.dart | 14 ++++-- .../test/engine/browser_detect_test.dart | 26 +++++----- .../test/engine/initialization_test.dart | 11 ++-- lib/web_ui/test/engine/window_test.dart | 20 ++++---- 10 files changed, 108 insertions(+), 126 deletions(-) diff --git a/lib/web_ui/lib/src/engine/app_bootstrap.dart b/lib/web_ui/lib/src/engine/app_bootstrap.dart index f3d5a70cc3424..dc0bf098f4a05 100644 --- a/lib/web_ui/lib/src/engine/app_bootstrap.dart +++ b/lib/web_ui/lib/src/engine/app_bootstrap.dart @@ -2,11 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:js/js_util.dart' show allowInterop; - import 'configuration.dart'; import 'js_interop/js_loader.dart'; -import 'js_interop/js_promise.dart'; /// The type of a function that initializes an engine (in Dart). typedef InitEngineFn = Future Function([JsFlutterConfiguration? params]); @@ -40,33 +37,26 @@ class AppBootstrap { // This is a convenience method that lets the programmer call "autoStart" // from JavaScript immediately after the main.dart.js has loaded. // Returns a promise that resolves to the Flutter app that was started. - autoStart: allowInterop(() => futureToPromise(() async { + autoStart: () async { await autoStart(); // Return the App that was just started return _prepareFlutterApp(); - }())), + }, // Calls [_initEngine], and returns a JS Promise that resolves to an // app runner object. - initializeEngine: allowInterop(([JsFlutterConfiguration? configuration]) => futureToPromise(() async { + initializeEngine: ([JsFlutterConfiguration? configuration]) async { await _initializeEngine(configuration); return _prepareAppRunner(); - }())) + } ); } /// Creates an appRunner that runs our encapsulated runApp function. FlutterAppRunner _prepareAppRunner() { - return FlutterAppRunner(runApp: allowInterop(([RunAppFnParameters? params]) { - // `params` coming from JS may be used to configure the run app method. - return Promise(allowInterop(( - PromiseResolver resolve, - PromiseRejecter _, - ) async { - await _runApp(); - // Return the App that was just started - resolve.resolve(_prepareFlutterApp()); - })); - })); + return FlutterAppRunner(runApp: ([RunAppFnParameters? params]) async { + await _runApp(); + return _prepareFlutterApp(); + }); } /// Represents the App that was just started, and its JS API. diff --git a/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart b/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart index 13563d0b52902..74a06d6cd4d6d 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart @@ -142,7 +142,7 @@ Future readVideoFramePixelsUnmodified(VideoFrame videoFrame) async { // In dart2wasm, Uint8List is not the same as a JS Uint8Array. So we // explicitly construct the JS object here. final JSUint8Array destination = createUint8ArrayFromLength(size); - final JsPromise copyPromise = videoFrame.copyTo(destination); + final JSPromise copyPromise = videoFrame.copyTo(destination); await promiseToFuture(copyPromise); // In dart2wasm, `toDart` incurs a copy here. On JS backends, this is a diff --git a/lib/web_ui/lib/src/engine/js_interop/js_loader.dart b/lib/web_ui/lib/src/engine/js_interop/js_loader.dart index 2e65f2aeb767c..283f3e1655fa0 100644 --- a/lib/web_ui/lib/src/engine/js_interop/js_loader.dart +++ b/lib/web_ui/lib/src/engine/js_interop/js_loader.dart @@ -8,9 +8,7 @@ library js_loader; import 'dart:js_interop'; import 'package:js/js_util.dart' as js_util; - -import '../configuration.dart'; -import 'js_promise.dart'; +import 'package:ui/src/engine.dart'; @JS() @staticInterop @@ -34,6 +32,17 @@ extension FlutterLoaderExtension on FlutterLoader { bool get isAutoStart => !js_util.hasProperty(this, 'didCreateEngineInitializer'); } +/// Typedef for the function that initializes the flutter engine. +/// /// +/// [JsFlutterConfiguration] comes from `../configuration.dart`. It is the same +/// object that can be used to configure flutter "inline", through the +/// (to be deprecated) `window.flutterConfiguration` object. +typedef InitializeEngineFn = Future Function([JsFlutterConfiguration?]); + +/// Typedef for the `autoStart` function that can be called straight from an engine initializer instance. +/// (Similar to [RunAppFn], but taking no specific "runApp" parameters). +typedef ImmediateRunAppFn = Future Function(); + // FlutterEngineInitializer /// An object that allows the user to initialize the Engine of a Flutter App. @@ -44,23 +53,19 @@ extension FlutterLoaderExtension on FlutterLoader { @anonymous @staticInterop abstract class FlutterEngineInitializer{ - external factory FlutterEngineInitializer({ + factory FlutterEngineInitializer({ required InitializeEngineFn initializeEngine, required ImmediateRunAppFn autoStart, + }) => FlutterEngineInitializer._( + initializeEngine: (() => futureToPromise(initializeEngine())).toJS, + autoStart: (() => futureToPromise(autoStart())).toJS, + ); + external factory FlutterEngineInitializer._({ + required JSFunction initializeEngine, + required JSFunction autoStart, }); } -/// Typedef for the function that initializes the flutter engine. -/// -/// [JsFlutterConfiguration] comes from `../configuration.dart`. It is the same -/// object that can be used to configure flutter "inline", through the -/// (to be deprecated) `window.flutterConfiguration` object. -typedef InitializeEngineFn = Promise Function([JsFlutterConfiguration?]); - -/// Typedef for the `autoStart` function that can be called straight from an engine initializer instance. -/// (Similar to [RunAppFn], but taking no specific "runApp" parameters). -typedef ImmediateRunAppFn = Promise Function(); - // FlutterAppRunner /// A class that exposes a function that runs the Flutter app, @@ -68,10 +73,14 @@ typedef ImmediateRunAppFn = Promise Function(); @JS() @anonymous @staticInterop -abstract class FlutterAppRunner { +abstract class FlutterAppRunner extends JSObject { + factory FlutterAppRunner({required RunAppFn runApp,}) => FlutterAppRunner._( + runApp: ((RunAppFnParameters args) => futureToPromise(runApp(args))).toJS + ); + /// Runs a flutter app - external factory FlutterAppRunner({ - required RunAppFn runApp, // Returns an App + external factory FlutterAppRunner._({ + required JSFunction runApp, // Returns an App }); } @@ -81,10 +90,11 @@ abstract class FlutterAppRunner { @anonymous @staticInterop abstract class RunAppFnParameters { + external factory RunAppFnParameters(); } /// Typedef for the function that runs the flutter app main entrypoint. -typedef RunAppFn = Promise Function([RunAppFnParameters?]); +typedef RunAppFn = Future Function([RunAppFnParameters?]); // FlutterApp @@ -92,7 +102,7 @@ typedef RunAppFn = Promise Function([RunAppFnParameters?]); @JS() @anonymous @staticInterop -abstract class FlutterApp { +abstract class FlutterApp extends JSObject { /// Cleans a Flutter app external factory FlutterApp(); } diff --git a/lib/web_ui/lib/src/engine/js_interop/js_promise.dart b/lib/web_ui/lib/src/engine/js_interop/js_promise.dart index 5f7e61dd3217e..6ad06b21566b4 100644 --- a/lib/web_ui/lib/src/engine/js_interop/js_promise.dart +++ b/lib/web_ui/lib/src/engine/js_interop/js_promise.dart @@ -11,40 +11,27 @@ import 'package:js/js_util.dart' as js_util; import '../util.dart'; -@JS() -@staticInterop -class PromiseResolver {} - -extension PromiseResolverExtension on PromiseResolver { - void resolve(T result) => js_util.callMethod(this, 'call', [this, if (result != null) result]); -} - -@JS() -@staticInterop -class PromiseRejecter {} - -extension PromiseRejecterExtension on PromiseRejecter { - void reject(Object? error) => js_util.callMethod(this, 'call', [this, if (error != null) error]); +extension CallExtension on JSFunction { + external void call(JSAny? this_, JSAny? object); } -/// Type-safe JS Promises @JS('Promise') -@staticInterop -abstract class Promise { - /// A constructor for a JS promise - external factory Promise(PromiseExecutor executor); -} +external JSAny get _promiseConstructor; + +JSPromise createPromise(JSFunction executor) => + js_util.callConstructor( + _promiseConstructor, + [executor], + ); -/// The type of function that is used to create a Promise -typedef PromiseExecutor = void Function(PromiseResolver resolve, PromiseRejecter reject); -Promise futureToPromise(Future future) { - return Promise(js_util.allowInterop((PromiseResolver resolver, PromiseRejecter rejecter) { +JSPromise futureToPromise(Future future) { + return createPromise((JSFunction resolver, JSFunction rejecter) { future.then( - (T value) => resolver.resolve(value), + (T value) => resolver.call(null, value), onError: (Object? error) { printWarning('Rejecting promise with error: $error'); - rejecter.reject(error); + rejecter.call(null, null); }); - })); + }.toJS); } diff --git a/lib/web_ui/lib/src/engine/safe_browser_api.dart b/lib/web_ui/lib/src/engine/safe_browser_api.dart index a8359793fe53e..73ba4775ac169 100644 --- a/lib/web_ui/lib/src/engine/safe_browser_api.dart +++ b/lib/web_ui/lib/src/engine/safe_browser_api.dart @@ -196,20 +196,6 @@ bool get _defaultBrowserSupportsImageDecoder => // enable it explicitly. bool get _isBrowserImageDecoderStable => browserEngine == BrowserEngine.blink; -/// The signature of the function passed to the constructor of JavaScript `Promise`. -typedef JsPromiseCallback = void Function(void Function(Object? value) resolve, void Function(Object? error) reject); - -/// Corresponds to JavaScript's `Promise`. -/// -/// This type doesn't need any members. Instead, it should be first converted -/// to Dart's [Future] using [promiseToFuture] then interacted with through the -/// [Future] API. -@JS('window.Promise') -@staticInterop -class JsPromise { - external factory JsPromise(JsPromiseCallback callback); -} - /// Corresponds to the browser's `ImageDecoder` type. /// /// See also: @@ -228,7 +214,7 @@ extension ImageDecoderExtension on ImageDecoder { external JSBoolean get _complete; bool get complete => _complete.toDart; - external JsPromise decode(DecodeOptions options); + external JSPromise decode(DecodeOptions options); external JSVoid close(); } @@ -302,8 +288,8 @@ extension VideoFrameExtension on VideoFrame { double allocationSize() => _allocationSize().toDartDouble; @JS('copyTo') - external JsPromise _copyTo(JSAny destination); - JsPromise copyTo(Object destination) => _copyTo(destination.toJSAnyShallow); + external JSPromise _copyTo(JSAny destination); + JSPromise copyTo(Object destination) => _copyTo(destination.toJSAnyShallow); @JS('format') external JSString? get _format; @@ -344,7 +330,7 @@ extension VideoFrameExtension on VideoFrame { class ImageTrackList {} extension ImageTrackListExtension on ImageTrackList { - external JsPromise get ready; + external JSPromise get ready; external ImageTrack? get selectedTrack; } diff --git a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart index 7cc6081747d62..514ad95ded270 100644 --- a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart +++ b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart @@ -1847,8 +1847,8 @@ void _paragraphTests() { }, skip: isFirefox); // Intended: Headless firefox has no webgl support https://github.com/flutter/flutter/issues/109265 group('getCanvasKitJsFileNames', () { - dynamic oldV8BreakIterator = v8BreakIterator; - dynamic oldIntlSegmenter = intlSegmenter; + JSAny? oldV8BreakIterator = v8BreakIterator; + JSAny? oldIntlSegmenter = intlSegmenter; setUp(() { oldV8BreakIterator = v8BreakIterator; @@ -1861,8 +1861,8 @@ void _paragraphTests() { }); test('in Chromium-based browsers', () { - v8BreakIterator = Object(); // Any non-null value. - intlSegmenter = Object(); // Any non-null value. + v8BreakIterator = Object().toJSBox; // Any non-null value. + intlSegmenter = Object().toJSBox; // Any non-null value. browserSupportsImageDecoder = true; expect(getCanvasKitJsFileNames(CanvasKitVariant.full), ['canvaskit.js']); @@ -1874,7 +1874,7 @@ void _paragraphTests() { }); test('in older versions of Chromium-based browsers', () { - v8BreakIterator = Object(); // Any non-null value. + v8BreakIterator = Object().toJSBox; // Any non-null value. intlSegmenter = null; // Older versions of Chromium didn't have the Intl.Segmenter API. browserSupportsImageDecoder = true; @@ -1884,7 +1884,7 @@ void _paragraphTests() { }); test('in other browsers', () { - intlSegmenter = Object(); // Any non-null value. + intlSegmenter = Object().toJSBox; // Any non-null value. v8BreakIterator = null; browserSupportsImageDecoder = true; @@ -1892,7 +1892,7 @@ void _paragraphTests() { expect(getCanvasKitJsFileNames(CanvasKitVariant.chromium), ['chromium/canvaskit.js']); expect(getCanvasKitJsFileNames(CanvasKitVariant.auto), ['canvaskit.js']); - v8BreakIterator = Object(); + v8BreakIterator = Object().toJSBox; browserSupportsImageDecoder = false; // TODO(mdebbar): we don't check image codecs for now. // https://github.com/flutter/flutter/issues/122331 @@ -1935,13 +1935,13 @@ void _paragraphTests() { @JS('window.Intl.v8BreakIterator') -external dynamic get v8BreakIterator; +external JSAny? get v8BreakIterator; @JS('window.Intl.v8BreakIterator') -external set v8BreakIterator(dynamic x); +external set v8BreakIterator(JSAny? x); @JS('window.Intl.Segmenter') -external dynamic get intlSegmenter; +external JSAny? get intlSegmenter; @JS('window.Intl.Segmenter') -external set intlSegmenter(dynamic x); +external set intlSegmenter(JSAny? x); diff --git a/lib/web_ui/test/engine/app_bootstrap_test.dart b/lib/web_ui/test/engine/app_bootstrap_test.dart index 609c569883bb6..14af5490dc9e0 100644 --- a/lib/web_ui/test/engine/app_bootstrap_test.dart +++ b/lib/web_ui/test/engine/app_bootstrap_test.dart @@ -88,9 +88,17 @@ void testMain() { final FlutterEngineInitializer engineInitializer = bootstrap.prepareEngineInitializer(); - final Object appInitializer = await promiseToFuture(callMethod(engineInitializer, 'initializeEngine', [])); - final Object maybeApp = await promiseToFuture(callMethod(appInitializer, 'runApp', [])); - + final Object appInitializer = await promiseToFuture(callMethod( + engineInitializer, + 'initializeEngine', + [] + )); + expect(appInitializer, isA()); + final Object maybeApp = await promiseToFuture(callMethod( + appInitializer, + 'runApp', + [RunAppFnParameters()] + )); expect(maybeApp, isA()); expect(initCalled, 1, reason: 'initEngine should have been called.'); expect(runCalled, 2, reason: 'runApp should have been called.'); diff --git a/lib/web_ui/test/engine/browser_detect_test.dart b/lib/web_ui/test/engine/browser_detect_test.dart index 26b742e00d3a6..e3b17cacd7f79 100644 --- a/lib/web_ui/test/engine/browser_detect_test.dart +++ b/lib/web_ui/test/engine/browser_detect_test.dart @@ -157,8 +157,8 @@ void testMain() { }); group('browserSupportsCanvasKitChromium', () { - dynamic oldV8BreakIterator = v8BreakIterator; - dynamic oldIntlSegmenter = intlSegmenter; + JSAny? oldV8BreakIterator = v8BreakIterator; + JSAny? oldIntlSegmenter = intlSegmenter; setUp(() { oldV8BreakIterator = v8BreakIterator; @@ -171,16 +171,16 @@ void testMain() { }); test('Detect browsers that support CanvasKit Chromium', () { - v8BreakIterator = Object(); // Any non-null value. - intlSegmenter = Object(); // Any non-null value. + v8BreakIterator = Object().toJSBox; // Any non-null value. + intlSegmenter = Object().toJSBox; // Any non-null value. browserSupportsImageDecoder = true; expect(browserSupportsCanvaskitChromium, isTrue); }); test('Detect browsers that do not support image codecs', () { - v8BreakIterator = Object(); // Any non-null value. - intlSegmenter = Object(); // Any non-null value. + v8BreakIterator = Object().toJSBox; // Any non-null value. + intlSegmenter = Object().toJSBox; // Any non-null value. browserSupportsImageDecoder = false; // TODO(mdebbar): we don't check image codecs for now. @@ -190,7 +190,7 @@ void testMain() { test('Detect browsers that do not support v8BreakIterator', () { v8BreakIterator = null; - intlSegmenter = Object(); // Any non-null value. + intlSegmenter = Object().toJSBox; // Any non-null value. browserSupportsImageDecoder = true; expect(browserSupportsCanvaskitChromium, isFalse); @@ -198,14 +198,14 @@ void testMain() { test('Detect browsers that support neither', () { v8BreakIterator = null; - intlSegmenter = Object(); // Any non-null value. + intlSegmenter = Object().toJSBox; // Any non-null value. browserSupportsImageDecoder = false; expect(browserSupportsCanvaskitChromium, isFalse); }); test('Detect browsers that support v8BreakIterator but no Intl.Segmenter', () { - v8BreakIterator = Object(); // Any non-null value. + v8BreakIterator = Object().toJSBox; // Any non-null value. intlSegmenter = null; expect(browserSupportsCanvaskitChromium, isFalse); @@ -222,13 +222,13 @@ void testMain() { } @JS('window.Intl.v8BreakIterator') -external dynamic get v8BreakIterator; +external JSAny? get v8BreakIterator; @JS('window.Intl.v8BreakIterator') -external set v8BreakIterator(dynamic x); +external set v8BreakIterator(JSAny? x); @JS('window.Intl.Segmenter') -external dynamic get intlSegmenter; +external JSAny? get intlSegmenter; @JS('window.Intl.Segmenter') -external set intlSegmenter(dynamic x); +external set intlSegmenter(JSAny? x); diff --git a/lib/web_ui/test/engine/initialization_test.dart b/lib/web_ui/test/engine/initialization_test.dart index 0068628b88d66..166efdc8129c8 100644 --- a/lib/web_ui/test/engine/initialization_test.dart +++ b/lib/web_ui/test/engine/initialization_test.dart @@ -15,13 +15,13 @@ external set _loader(JSAny? loader); set loader(Object? l) => _loader = l?.toJSAnyShallow; @JS('_flutter.loader.didCreateEngineInitializer') -external set didCreateEngineInitializer(Object? callback); +external set didCreateEngineInitializer(JSFunction? callback); void main() { // Prepare _flutter.loader.didCreateEngineInitializer, so it's ready in the page ASAP. loader = js_util.jsify({ 'loader': { - 'didCreateEngineInitializer': js_util.allowInterop(() { print('not mocked'); }), + 'didCreateEngineInitializer': () { print('not mocked'); }.toJS, }, }); internalBootstrapBrowserTest(() => testMain); @@ -29,14 +29,15 @@ void main() { void testMain() { test('bootstrapEngine calls _flutter.loader.didCreateEngineInitializer callback', () async { - Object? engineInitializer; + JSAny? engineInitializer; - void didCreateEngineInitializerMock(Object? obj) { + void didCreateEngineInitializerMock(JSAny? obj) { + print('obj: $obj'); engineInitializer = obj; } // Prepare the DOM for: _flutter.loader.didCreateEngineInitializer - didCreateEngineInitializer = js_util.allowInterop(didCreateEngineInitializerMock); + didCreateEngineInitializer = didCreateEngineInitializerMock.toJS; // Reset the engine engine.debugResetEngineInitializationState(); diff --git a/lib/web_ui/test/engine/window_test.dart b/lib/web_ui/test/engine/window_test.dart index 85f40e1662c3a..df39afb17adde 100644 --- a/lib/web_ui/test/engine/window_test.dart +++ b/lib/web_ui/test/engine/window_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:js_interop'; import 'dart:js_util' as js_util; import 'dart:typed_data'; @@ -331,19 +332,18 @@ Future testMain() async { // The `orientation` property cannot be overridden, so this test overrides the entire `screen`. js_util.setProperty(domWindow, 'screen', js_util.jsify({ 'orientation': { - 'lock': allowInterop((String lockType) { + 'lock': (String lockType) { lockCalls.add(lockType); - return Promise(allowInterop((PromiseResolver resolve, PromiseRejecter reject) { - if (!simulateError) { - resolve.resolve(null); - } else { - reject.reject('Simulating error'); + return futureToPromise(() async { + if (simulateError) { + throw Error(); } - })); - }), - 'unlock': allowInterop(() { + return 0.toJS; + }()); + }.toJS, + 'unlock': () { unlockCount += 1; - }), + }.toJS, }, })); From 404c9453cdfec8537c5e31e3047953ac8e156ca3 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 11 Sep 2023 16:41:46 -0700 Subject: [PATCH 2/3] Make runApp have optional parameters. --- lib/web_ui/lib/src/engine/js_interop/js_loader.dart | 3 +-- lib/web_ui/test/engine/app_bootstrap_test.dart | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/web_ui/lib/src/engine/js_interop/js_loader.dart b/lib/web_ui/lib/src/engine/js_interop/js_loader.dart index 283f3e1655fa0..b85d442a331d5 100644 --- a/lib/web_ui/lib/src/engine/js_interop/js_loader.dart +++ b/lib/web_ui/lib/src/engine/js_interop/js_loader.dart @@ -75,7 +75,7 @@ abstract class FlutterEngineInitializer{ @staticInterop abstract class FlutterAppRunner extends JSObject { factory FlutterAppRunner({required RunAppFn runApp,}) => FlutterAppRunner._( - runApp: ((RunAppFnParameters args) => futureToPromise(runApp(args))).toJS + runApp: (([RunAppFnParameters? args]) => futureToPromise(runApp(args))).toJS ); /// Runs a flutter app @@ -90,7 +90,6 @@ abstract class FlutterAppRunner extends JSObject { @anonymous @staticInterop abstract class RunAppFnParameters { - external factory RunAppFnParameters(); } /// Typedef for the function that runs the flutter app main entrypoint. diff --git a/lib/web_ui/test/engine/app_bootstrap_test.dart b/lib/web_ui/test/engine/app_bootstrap_test.dart index 14af5490dc9e0..925d8448248bb 100644 --- a/lib/web_ui/test/engine/app_bootstrap_test.dart +++ b/lib/web_ui/test/engine/app_bootstrap_test.dart @@ -97,7 +97,7 @@ void testMain() { final Object maybeApp = await promiseToFuture(callMethod( appInitializer, 'runApp', - [RunAppFnParameters()] + [] )); expect(maybeApp, isA()); expect(initCalled, 1, reason: 'initEngine should have been called.'); From 0f2a316799d3c1df80ef942f31943490296ea142 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Tue, 12 Sep 2023 11:08:35 -0700 Subject: [PATCH 3/3] Pass intitialize engine args along. --- lib/web_ui/lib/src/engine/js_interop/js_loader.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/js_interop/js_loader.dart b/lib/web_ui/lib/src/engine/js_interop/js_loader.dart index b85d442a331d5..096fb57915a15 100644 --- a/lib/web_ui/lib/src/engine/js_interop/js_loader.dart +++ b/lib/web_ui/lib/src/engine/js_interop/js_loader.dart @@ -57,7 +57,7 @@ abstract class FlutterEngineInitializer{ required InitializeEngineFn initializeEngine, required ImmediateRunAppFn autoStart, }) => FlutterEngineInitializer._( - initializeEngine: (() => futureToPromise(initializeEngine())).toJS, + initializeEngine: (([JsFlutterConfiguration? config]) => futureToPromise(initializeEngine(config))).toJS, autoStart: (() => futureToPromise(autoStart())).toJS, ); external factory FlutterEngineInitializer._({