From 672103ad2ff0e1a616de2eed281725132bf7928a Mon Sep 17 00:00:00 2001 From: "auto-submit[bot]" Date: Wed, 3 Jul 2024 08:38:09 +0000 Subject: [PATCH] Revert "Reland "Output .js files as ES6 modules. (#52023)" (#53688)" This reverts commit c5c0c54d6d1da3ddf45a6a527b57310d1283b897. --- DEPS | 2 +- lib/web_ui/flutter_js/src/canvaskit_loader.js | 33 +++++++---- lib/web_ui/flutter_js/src/skwasm_loader.js | 59 ++++++++++++------- .../src/engine/canvaskit/canvaskit_api.dart | 56 ++++++++++++------ lib/web_ui/lib/src/engine/configuration.dart | 2 +- lib/web_ui/lib/src/engine/dom.dart | 6 +- .../does_not_mock_module_exports_test.dart | 7 +++ .../test/engine/configuration_test.dart | 14 ++--- 8 files changed, 118 insertions(+), 61 deletions(-) diff --git a/DEPS b/DEPS index 695f3353bbd59..a241597cc8b0b 100644 --- a/DEPS +++ b/DEPS @@ -277,7 +277,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + 'e265c359126b24351f534080fb22edaa159f2215', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '8c2d66fa4e6298894425f5bdd0591bc5b1154c53', 'src/flutter/third_party/depot_tools': Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '580b4ff3f5cd0dcaa2eacda28cefe0f45320e8f7', diff --git a/lib/web_ui/flutter_js/src/canvaskit_loader.js b/lib/web_ui/flutter_js/src/canvaskit_loader.js index 4c8e91c7bc175..64dc6734ec273 100644 --- a/lib/web_ui/flutter_js/src/canvaskit_loader.js +++ b/lib/web_ui/flutter_js/src/canvaskit_loader.js @@ -6,11 +6,11 @@ import { createWasmInstantiator } from "./instantiate_wasm.js"; import { joinPathSegments } from "./utils.js"; export const loadCanvasKit = (deps, config, browserEnvironment, canvasKitBaseUrl) => { - window.flutterCanvasKitLoaded = (async () => { - if (window.flutterCanvasKit) { - // The user has set this global variable ahead of time, so we just return that. - return window.flutterCanvasKit; - } + if (window.flutterCanvasKit) { + // The user has set this global variable ahead of time, so we just return that. + return Promise.resolve(window.flutterCanvasKit); + } + window.flutterCanvasKitLoaded = new Promise((resolve, reject) => { const supportsChromiumCanvasKit = browserEnvironment.hasChromiumBreakIterators && browserEnvironment.hasImageCodecs; if (!supportsChromiumCanvasKit && config.canvasKitVariant == "chromium") { throw "Chromium CanvasKit variant specifically requested, but unsupported in this browser"; @@ -25,11 +25,24 @@ export const loadCanvasKit = (deps, config, browserEnvironment, canvasKitBaseUrl canvasKitUrl = deps.flutterTT.policy.createScriptURL(canvasKitUrl); } const wasmInstantiator = createWasmInstantiator(joinPathSegments(baseUrl, "canvaskit.wasm")); - const canvasKitModule = await import(canvasKitUrl); - window.flutterCanvasKit = await canvasKitModule.default({ - instantiateWasm: wasmInstantiator, + const script = document.createElement("script"); + script.src = canvasKitUrl; + if (config.nonce) { + script.nonce = config.nonce; + } + script.addEventListener("load", async () => { + try { + const canvasKit = await CanvasKitInit({ + instantiateWasm: wasmInstantiator, + }); + window.flutterCanvasKit = canvasKit; + resolve(canvasKit); + } catch (e) { + reject(e); + } }); - return window.flutterCanvasKit; - })(); + script.addEventListener("error", reject); + document.head.appendChild(script); + }); return window.flutterCanvasKitLoaded; } diff --git a/lib/web_ui/flutter_js/src/skwasm_loader.js b/lib/web_ui/flutter_js/src/skwasm_loader.js index 01b4fe3cb2375..241f4e8c81e02 100644 --- a/lib/web_ui/flutter_js/src/skwasm_loader.js +++ b/lib/web_ui/flutter_js/src/skwasm_loader.js @@ -5,28 +5,43 @@ import { createWasmInstantiator } from "./instantiate_wasm.js"; import { joinPathSegments } from "./utils.js"; -export const loadSkwasm = async (deps, config, browserEnvironment, baseUrl) => { - let skwasmUrl = joinPathSegments(baseUrl, "skwasm.js"); - if (deps.flutterTT.policy) { - skwasmUrl = deps.flutterTT.policy.createScriptURL(skwasmUrl); - } - const wasmInstantiator = createWasmInstantiator(joinPathSegments(baseUrl, "skwasm.wasm")); - const skwasm = await import(skwasmUrl); - return await skwasm.default({ - instantiateWasm: wasmInstantiator, - locateFile: (fileName, scriptDirectory) => { - // When hosted via a CDN or some other url that is not the same - // origin as the main script of the page, we will fail to create - // a web worker with the .worker.js script. This workaround will - // make sure that the worker JS can be loaded regardless of where - // it is hosted. - const url = scriptDirectory + fileName; - if (url.endsWith('.worker.js')) { - return URL.createObjectURL(new Blob( - [`importScripts('${url}');`], - { 'type': 'application/javascript' })); - } - return url; +export const loadSkwasm = (deps, config, browserEnvironment, baseUrl) => { + return new Promise((resolve, reject) => { + let skwasmUrl = joinPathSegments(baseUrl, "skwasm.js"); + if (deps.flutterTT.policy) { + skwasmUrl = deps.flutterTT.policy.createScriptURL(skwasmUrl); + } + const wasmInstantiator = createWasmInstantiator(joinPathSegments(baseUrl, "skwasm.wasm")); + const script = document.createElement("script"); + script.src = skwasmUrl; + if (config.nonce) { + script.nonce = config.nonce; } + script.addEventListener("load", async () => { + try { + const skwasmInstance = await skwasm({ + instantiateWasm: wasmInstantiator, + locateFile: (fileName, scriptDirectory) => { + // When hosted via a CDN or some other url that is not the same + // origin as the main script of the page, we will fail to create + // a web worker with the .worker.js script. This workaround will + // make sure that the worker JS can be loaded regardless of where + // it is hosted. + const url = scriptDirectory + fileName; + if (url.endsWith(".worker.js")) { + return URL.createObjectURL(new Blob( + [`importScripts("${url}");`], + { "type": "application/javascript" })); + } + return url; + } + }); + resolve(skwasmInstance); + } catch (e) { + reject(e); + } + }); + script.addEventListener("error", reject); + document.head.appendChild(script); }); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart index 2e6e8dfc62a6e..c41da41b36aac 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -259,13 +259,12 @@ extension CanvasKitExtension on CanvasKit { ); } -@JS() -@staticInterop -class CanvasKitModule {} +@JS('window.CanvasKitInit') +external JSAny _CanvasKitInit(CanvasKitInitOptions options); -extension CanvasKitModuleExtension on CanvasKitModule { - @JS('default') - external JSPromise defaultExport(CanvasKitInitOptions options); +Future CanvasKitInit(CanvasKitInitOptions options) { + return js_util.promiseToFuture( + _CanvasKitInit(options).toObjectShallow); } typedef LocateFileCallback = String Function(String file, String unusedBase); @@ -3662,11 +3661,11 @@ String canvasKitWasmModuleUrl(String file, String canvasKitBase) => /// Downloads the CanvasKit JavaScript, then calls `CanvasKitInit` to download /// and intialize the CanvasKit wasm. Future downloadCanvasKit() async { - final CanvasKitModule canvasKitModule = await _downloadOneOf(_canvasKitJsUrls); + await _downloadOneOf(_canvasKitJsUrls); - final CanvasKit canvasKit = (await canvasKitModule.defaultExport(CanvasKitInitOptions( + final CanvasKit canvasKit = await CanvasKitInit(CanvasKitInitOptions( locateFile: createLocateFileCallback(canvasKitWasmModuleUrl), - )).toDart) as CanvasKit; + )); if (canvasKit.ParagraphBuilder.RequiresClientICU() && !browserSupportsCanvaskitChromium) { throw Exception( @@ -3682,12 +3681,10 @@ Future downloadCanvasKit() async { /// downloads it. /// /// If none of the URLs can be downloaded, throws an [Exception]. -Future _downloadOneOf(Iterable urls) async { +Future _downloadOneOf(Iterable urls) async { for (final String url in urls) { - try { - return await _downloadCanvasKitJs(url); - } catch (_) { - continue; + if (await _downloadCanvasKitJs(url)) { + return; } } @@ -3701,7 +3698,32 @@ Future _downloadOneOf(Iterable urls) async { /// /// Returns a [Future] that completes with `true` if the CanvasKit JavaScript /// file was successfully downloaded, or `false` if it failed. -Future _downloadCanvasKitJs(String url) async { - final JSAny scriptUrl = createTrustedScriptUrl(url); - return (await importModule(scriptUrl).toDart) as CanvasKitModule; +Future _downloadCanvasKitJs(String url) { + final DomHTMLScriptElement canvasKitScript = + createDomHTMLScriptElement(configuration.nonce); + canvasKitScript.src = createTrustedScriptUrl(url); + + final Completer canvasKitLoadCompleter = Completer(); + + late final DomEventListener loadCallback; + late final DomEventListener errorCallback; + + void loadEventHandler(DomEvent _) { + canvasKitScript.remove(); + canvasKitLoadCompleter.complete(true); + } + void errorEventHandler(DomEvent errorEvent) { + canvasKitScript.remove(); + canvasKitLoadCompleter.complete(false); + } + + loadCallback = createDomEventListener(loadEventHandler); + errorCallback = createDomEventListener(errorEventHandler); + + canvasKitScript.addEventListener('load', loadCallback); + canvasKitScript.addEventListener('error', errorCallback); + + domDocument.head!.appendChild(canvasKitScript); + + return canvasKitLoadCompleter.future; } diff --git a/lib/web_ui/lib/src/engine/configuration.dart b/lib/web_ui/lib/src/engine/configuration.dart index 050dda1e494bd..33235af14c152 100644 --- a/lib/web_ui/lib/src/engine/configuration.dart +++ b/lib/web_ui/lib/src/engine/configuration.dart @@ -241,7 +241,7 @@ class FlutterConfiguration { _configuration?.canvasKitBaseUrl ?? _defaultCanvasKitBaseUrl; static const String _defaultCanvasKitBaseUrl = String.fromEnvironment( 'FLUTTER_WEB_CANVASKIT_URL', - defaultValue: '/canvaskit/', + defaultValue: 'canvaskit/', ); /// The variant of CanvasKit to download. diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 04eb31fdd507f..b81bba41245f2 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -3383,16 +3383,16 @@ final DomTrustedTypePolicy _ttPolicy = domWindow.trustedTypes!.createPolicy( /// Converts a String `url` into a [DomTrustedScriptURL] object when the /// Trusted Types API is available, else returns the unmodified `url`. -JSAny createTrustedScriptUrl(String url) { +Object createTrustedScriptUrl(String url) { if (domWindow.trustedTypes != null) { // Pass `url` through Flutter Engine's TrustedType policy. final DomTrustedScriptURL trustedUrl = _ttPolicy.createScriptURL(url); assert(trustedUrl.url != '', 'URL: $url rejected by TrustedTypePolicy'); - return trustedUrl as JSAny; + return trustedUrl; } - return url.toJS; + return url; } DomMessageChannel createDomMessageChannel() => DomMessageChannel(); diff --git a/lib/web_ui/test/canvaskit/initialization/does_not_mock_module_exports_test.dart b/lib/web_ui/test/canvaskit/initialization/does_not_mock_module_exports_test.dart index 96e0c8a6d14d5..b6676f2af4fcf 100644 --- a/lib/web_ui/test/canvaskit/initialization/does_not_mock_module_exports_test.dart +++ b/lib/web_ui/test/canvaskit/initialization/does_not_mock_module_exports_test.dart @@ -18,6 +18,13 @@ void testMain() { // Initialize CanvasKit... await bootstrapAndRunApp(); + // CanvasKitInit should be defined... + expect( + js_util.hasProperty(domWindow, 'CanvasKitInit'), + isTrue, + reason: 'CanvasKitInit should be defined on Window', + ); + // window.exports and window.module should be undefined! expect( js_util.hasProperty(domWindow, 'exports'), diff --git a/lib/web_ui/test/engine/configuration_test.dart b/lib/web_ui/test/engine/configuration_test.dart index cb2ac7fdfbfc8..24f748f42f3ef 100644 --- a/lib/web_ui/test/engine/configuration_test.dart +++ b/lib/web_ui/test/engine/configuration_test.dart @@ -22,16 +22,16 @@ void testMain() { test('initializes with null', () async { final FlutterConfiguration config = FlutterConfiguration.legacy(null); - expect(config.canvasKitBaseUrl, '/canvaskit/'); // _defaultCanvasKitBaseUrl + expect(config.canvasKitBaseUrl, 'canvaskit/'); // _defaultCanvasKitBaseUrl }); test('legacy constructor initializes with a Js Object', () async { final FlutterConfiguration config = FlutterConfiguration.legacy( js_util.jsify({ - 'canvasKitBaseUrl': '/some_other_url/', + 'canvasKitBaseUrl': 'some_other_url/', }) as JsFlutterConfiguration); - expect(config.canvasKitBaseUrl, '/some_other_url/'); + expect(config.canvasKitBaseUrl, 'some_other_url/'); }); }); @@ -39,13 +39,13 @@ void testMain() { test('throws assertion error if already initialized from JS', () async { final FlutterConfiguration config = FlutterConfiguration.legacy( js_util.jsify({ - 'canvasKitBaseUrl': '/some_other_url/', + 'canvasKitBaseUrl': 'some_other_url/', }) as JsFlutterConfiguration); expect(() { config.setUserConfiguration( js_util.jsify({ - 'canvasKitBaseUrl': '/yet_another_url/', + 'canvasKitBaseUrl': 'yet_another_url/', }) as JsFlutterConfiguration); }, throwsAssertionError); }); @@ -55,10 +55,10 @@ void testMain() { config.setUserConfiguration( js_util.jsify({ - 'canvasKitBaseUrl': '/one_more_url/', + 'canvasKitBaseUrl': 'one_more_url/', }) as JsFlutterConfiguration); - expect(config.canvasKitBaseUrl, '/one_more_url/'); + expect(config.canvasKitBaseUrl, 'one_more_url/'); }); test('can receive non-existing properties without crashing', () async {