Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit fc5bc14

Browse files
Reverts "Output .js files as ES6 modules. (#52023)" (#53674)
Reverts: #52023 Initiated by: eyebrowsoffire Reason for reverting: Causing issues in engine -> framework roll flutter/flutter#151139 Original PR Author: eyebrowsoffire Reviewed By: {ditman} This change reverts the following previous change: This changes CanvasKit and Skwasm to be compiled and loaded as ES6 modules instead of as vanilla script tags. Currently, the emscripten JS files try to register themselves with require.js or AMD module loading systems. We suspect this is causing issues (flutter/flutter#149565) with DDC's module loading system, which itself uses require.js. This is probably also the fix for flutter/flutter#147731
1 parent 8aa0362 commit fc5bc14

File tree

6 files changed

+110
-53
lines changed

6 files changed

+110
-53
lines changed

DEPS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ allowed_hosts = [
277277
]
278278

279279
deps = {
280-
'src': 'https://github.com/flutter/buildroot.git' + '@' + '6c01dbca494b78e32f9e4aa704514faabfba74e8',
280+
'src': 'https://github.com/flutter/buildroot.git' + '@' + '8c2d66fa4e6298894425f5bdd0591bc5b1154c53',
281281

282282
'src/flutter/third_party/depot_tools':
283283
Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '580b4ff3f5cd0dcaa2eacda28cefe0f45320e8f7',

lib/web_ui/flutter_js/src/canvaskit_loader.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import { createWasmInstantiator } from "./instantiate_wasm.js";
66
import { joinPathSegments } from "./utils.js";
77

88
export const loadCanvasKit = (deps, config, browserEnvironment, canvasKitBaseUrl) => {
9-
window.flutterCanvasKitLoaded = (async () => {
10-
if (window.flutterCanvasKit) {
11-
// The user has set this global variable ahead of time, so we just return that.
12-
return window.flutterCanvasKit;
13-
}
9+
if (window.flutterCanvasKit) {
10+
// The user has set this global variable ahead of time, so we just return that.
11+
return Promise.resolve(window.flutterCanvasKit);
12+
}
13+
window.flutterCanvasKitLoaded = new Promise((resolve, reject) => {
1414
const supportsChromiumCanvasKit = browserEnvironment.hasChromiumBreakIterators && browserEnvironment.hasImageCodecs;
1515
if (!supportsChromiumCanvasKit && config.canvasKitVariant == "chromium") {
1616
throw "Chromium CanvasKit variant specifically requested, but unsupported in this browser";
@@ -25,11 +25,24 @@ export const loadCanvasKit = (deps, config, browserEnvironment, canvasKitBaseUrl
2525
canvasKitUrl = deps.flutterTT.policy.createScriptURL(canvasKitUrl);
2626
}
2727
const wasmInstantiator = createWasmInstantiator(joinPathSegments(baseUrl, "canvaskit.wasm"));
28-
const canvasKitModule = await import(canvasKitUrl);
29-
window.flutterCanvasKit = await canvasKitModule.default({
30-
instantiateWasm: wasmInstantiator,
28+
const script = document.createElement("script");
29+
script.src = canvasKitUrl;
30+
if (config.nonce) {
31+
script.nonce = config.nonce;
32+
}
33+
script.addEventListener("load", async () => {
34+
try {
35+
const canvasKit = await CanvasKitInit({
36+
instantiateWasm: wasmInstantiator,
37+
});
38+
window.flutterCanvasKit = canvasKit;
39+
resolve(canvasKit);
40+
} catch (e) {
41+
reject(e);
42+
}
3143
});
32-
return window.flutterCanvasKit;
33-
})();
44+
script.addEventListener("error", reject);
45+
document.head.appendChild(script);
46+
});
3447
return window.flutterCanvasKitLoaded;
3548
}

lib/web_ui/flutter_js/src/skwasm_loader.js

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,43 @@
55
import { createWasmInstantiator } from "./instantiate_wasm.js";
66
import { joinPathSegments } from "./utils.js";
77

8-
export const loadSkwasm = async (deps, config, browserEnvironment, baseUrl) => {
9-
let skwasmUrl = joinPathSegments(baseUrl, "skwasm.js");
10-
if (deps.flutterTT.policy) {
11-
skwasmUrl = deps.flutterTT.policy.createScriptURL(skwasmUrl);
12-
}
13-
const wasmInstantiator = createWasmInstantiator(joinPathSegments(baseUrl, "skwasm.wasm"));
14-
const skwasm = await import(skwasmUrl);
15-
return await skwasm.default({
16-
instantiateWasm: wasmInstantiator,
17-
locateFile: (fileName, scriptDirectory) => {
18-
// When hosted via a CDN or some other url that is not the same
19-
// origin as the main script of the page, we will fail to create
20-
// a web worker with the .worker.js script. This workaround will
21-
// make sure that the worker JS can be loaded regardless of where
22-
// it is hosted.
23-
const url = scriptDirectory + fileName;
24-
if (url.endsWith('.worker.js')) {
25-
return URL.createObjectURL(new Blob(
26-
[`importScripts('${url}');`],
27-
{ 'type': 'application/javascript' }));
28-
}
29-
return url;
8+
export const loadSkwasm = (deps, config, browserEnvironment, baseUrl) => {
9+
return new Promise((resolve, reject) => {
10+
let skwasmUrl = joinPathSegments(baseUrl, "skwasm.js");
11+
if (deps.flutterTT.policy) {
12+
skwasmUrl = deps.flutterTT.policy.createScriptURL(skwasmUrl);
13+
}
14+
const wasmInstantiator = createWasmInstantiator(joinPathSegments(baseUrl, "skwasm.wasm"));
15+
const script = document.createElement("script");
16+
script.src = skwasmUrl;
17+
if (config.nonce) {
18+
script.nonce = config.nonce;
3019
}
20+
script.addEventListener("load", async () => {
21+
try {
22+
const skwasmInstance = await skwasm({
23+
instantiateWasm: wasmInstantiator,
24+
locateFile: (fileName, scriptDirectory) => {
25+
// When hosted via a CDN or some other url that is not the same
26+
// origin as the main script of the page, we will fail to create
27+
// a web worker with the .worker.js script. This workaround will
28+
// make sure that the worker JS can be loaded regardless of where
29+
// it is hosted.
30+
const url = scriptDirectory + fileName;
31+
if (url.endsWith(".worker.js")) {
32+
return URL.createObjectURL(new Blob(
33+
[`importScripts("${url}");`],
34+
{ "type": "application/javascript" }));
35+
}
36+
return url;
37+
}
38+
});
39+
resolve(skwasmInstance);
40+
} catch (e) {
41+
reject(e);
42+
}
43+
});
44+
script.addEventListener("error", reject);
45+
document.head.appendChild(script);
3146
});
3247
}

lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -259,13 +259,12 @@ extension CanvasKitExtension on CanvasKit {
259259
);
260260
}
261261

262-
@JS()
263-
@staticInterop
264-
class CanvasKitModule {}
262+
@JS('window.CanvasKitInit')
263+
external JSAny _CanvasKitInit(CanvasKitInitOptions options);
265264

266-
extension CanvasKitModuleExtension on CanvasKitModule {
267-
@JS('default')
268-
external JSPromise<JSAny> defaultExport(CanvasKitInitOptions options);
265+
Future<CanvasKit> CanvasKitInit(CanvasKitInitOptions options) {
266+
return js_util.promiseToFuture<CanvasKit>(
267+
_CanvasKitInit(options).toObjectShallow);
269268
}
270269

271270
typedef LocateFileCallback = String Function(String file, String unusedBase);
@@ -3662,11 +3661,11 @@ String canvasKitWasmModuleUrl(String file, String canvasKitBase) =>
36623661
/// Downloads the CanvasKit JavaScript, then calls `CanvasKitInit` to download
36633662
/// and intialize the CanvasKit wasm.
36643663
Future<CanvasKit> downloadCanvasKit() async {
3665-
final CanvasKitModule canvasKitModule = await _downloadOneOf(_canvasKitJsUrls);
3664+
await _downloadOneOf(_canvasKitJsUrls);
36663665

3667-
final CanvasKit canvasKit = (await canvasKitModule.defaultExport(CanvasKitInitOptions(
3666+
final CanvasKit canvasKit = await CanvasKitInit(CanvasKitInitOptions(
36683667
locateFile: createLocateFileCallback(canvasKitWasmModuleUrl),
3669-
)).toDart) as CanvasKit;
3668+
));
36703669

36713670
if (canvasKit.ParagraphBuilder.RequiresClientICU() && !browserSupportsCanvaskitChromium) {
36723671
throw Exception(
@@ -3682,12 +3681,10 @@ Future<CanvasKit> downloadCanvasKit() async {
36823681
/// downloads it.
36833682
///
36843683
/// If none of the URLs can be downloaded, throws an [Exception].
3685-
Future<CanvasKitModule> _downloadOneOf(Iterable<String> urls) async {
3684+
Future<void> _downloadOneOf(Iterable<String> urls) async {
36863685
for (final String url in urls) {
3687-
try {
3688-
return await _downloadCanvasKitJs(url);
3689-
} catch (_) {
3690-
continue;
3686+
if (await _downloadCanvasKitJs(url)) {
3687+
return;
36913688
}
36923689
}
36933690

@@ -3701,7 +3698,32 @@ Future<CanvasKitModule> _downloadOneOf(Iterable<String> urls) async {
37013698
///
37023699
/// Returns a [Future] that completes with `true` if the CanvasKit JavaScript
37033700
/// file was successfully downloaded, or `false` if it failed.
3704-
Future<CanvasKitModule> _downloadCanvasKitJs(String url) async {
3705-
final JSAny scriptUrl = createTrustedScriptUrl(url);
3706-
return (await importModule(scriptUrl).toDart) as CanvasKitModule;
3701+
Future<bool> _downloadCanvasKitJs(String url) {
3702+
final DomHTMLScriptElement canvasKitScript =
3703+
createDomHTMLScriptElement(configuration.nonce);
3704+
canvasKitScript.src = createTrustedScriptUrl(url);
3705+
3706+
final Completer<bool> canvasKitLoadCompleter = Completer<bool>();
3707+
3708+
late final DomEventListener loadCallback;
3709+
late final DomEventListener errorCallback;
3710+
3711+
void loadEventHandler(DomEvent _) {
3712+
canvasKitScript.remove();
3713+
canvasKitLoadCompleter.complete(true);
3714+
}
3715+
void errorEventHandler(DomEvent errorEvent) {
3716+
canvasKitScript.remove();
3717+
canvasKitLoadCompleter.complete(false);
3718+
}
3719+
3720+
loadCallback = createDomEventListener(loadEventHandler);
3721+
errorCallback = createDomEventListener(errorEventHandler);
3722+
3723+
canvasKitScript.addEventListener('load', loadCallback);
3724+
canvasKitScript.addEventListener('error', errorCallback);
3725+
3726+
domDocument.head!.appendChild(canvasKitScript);
3727+
3728+
return canvasKitLoadCompleter.future;
37073729
}

lib/web_ui/lib/src/engine/dom.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3407,16 +3407,16 @@ final DomTrustedTypePolicy _ttPolicy = domWindow.trustedTypes!.createPolicy(
34073407

34083408
/// Converts a String `url` into a [DomTrustedScriptURL] object when the
34093409
/// Trusted Types API is available, else returns the unmodified `url`.
3410-
JSAny createTrustedScriptUrl(String url) {
3410+
Object createTrustedScriptUrl(String url) {
34113411
if (domWindow.trustedTypes != null) {
34123412
// Pass `url` through Flutter Engine's TrustedType policy.
34133413
final DomTrustedScriptURL trustedUrl = _ttPolicy.createScriptURL(url);
34143414

34153415
assert(trustedUrl.url != '', 'URL: $url rejected by TrustedTypePolicy');
34163416

3417-
return trustedUrl as JSAny;
3417+
return trustedUrl;
34183418
}
3419-
return url.toJS;
3419+
return url;
34203420
}
34213421

34223422
DomMessageChannel createDomMessageChannel() => DomMessageChannel();

lib/web_ui/test/canvaskit/initialization/does_not_mock_module_exports_test.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ void testMain() {
1818
// Initialize CanvasKit...
1919
await bootstrapAndRunApp();
2020

21+
// CanvasKitInit should be defined...
22+
expect(
23+
js_util.hasProperty(domWindow, 'CanvasKitInit'),
24+
isTrue,
25+
reason: 'CanvasKitInit should be defined on Window',
26+
);
27+
2128
// window.exports and window.module should be undefined!
2229
expect(
2330
js_util.hasProperty(domWindow, 'exports'),

0 commit comments

Comments
 (0)