Skip to content

Commit 01e806b

Browse files
Reland (x2) "Output .js files as ES6 modules. (flutter#52023)"
1 parent c9a6ca0 commit 01e806b

File tree

8 files changed

+61
-118
lines changed

8 files changed

+61
-118
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' + '@' + '8c2d66fa4e6298894425f5bdd0591bc5b1154c53',
280+
'src': 'https://github.com/flutter/buildroot.git' + '@' + 'e265c359126b24351f534080fb22edaa159f2215',
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: 10 additions & 23 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-
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) => {
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+
}
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,24 +25,11 @@ 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 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-
}
28+
const canvasKitModule = await import(canvasKitUrl);
29+
window.flutterCanvasKit = await canvasKitModule.default({
30+
instantiateWasm: wasmInstantiator,
4331
});
44-
script.addEventListener("error", reject);
45-
document.head.appendChild(script);
46-
});
32+
return window.flutterCanvasKit;
33+
})();
4734
return window.flutterCanvasKitLoaded;
4835
}

lib/web_ui/flutter_js/src/skwasm_loader.js

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

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;
19-
}
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);
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' }));
4228
}
43-
});
44-
script.addEventListener("error", reject);
45-
document.head.appendChild(script);
29+
return url;
30+
}
4631
});
4732
}

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

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

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

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

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

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

36703671
if (canvasKit.ParagraphBuilder.RequiresClientICU() && !browserSupportsCanvaskitChromium) {
36713672
throw Exception(
@@ -3681,10 +3682,12 @@ Future<CanvasKit> downloadCanvasKit() async {
36813682
/// downloads it.
36823683
///
36833684
/// If none of the URLs can be downloaded, throws an [Exception].
3684-
Future<void> _downloadOneOf(Iterable<String> urls) async {
3685+
Future<CanvasKitModule> _downloadOneOf(Iterable<String> urls) async {
36853686
for (final String url in urls) {
3686-
if (await _downloadCanvasKitJs(url)) {
3687-
return;
3687+
try {
3688+
return await _downloadCanvasKitJs(url);
3689+
} catch (_) {
3690+
continue;
36883691
}
36893692
}
36903693

@@ -3698,32 +3701,7 @@ Future<void> _downloadOneOf(Iterable<String> urls) async {
36983701
///
36993702
/// Returns a [Future] that completes with `true` if the CanvasKit JavaScript
37003703
/// file was successfully downloaded, or `false` if it failed.
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;
3704+
Future<CanvasKitModule> _downloadCanvasKitJs(String url) async {
3705+
final JSAny scriptUrl = createTrustedScriptUrl(url);
3706+
return (await importModule(scriptUrl).toDart) as CanvasKitModule;
37293707
}

lib/web_ui/lib/src/engine/configuration.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ class FlutterConfiguration {
241241
_configuration?.canvasKitBaseUrl ?? _defaultCanvasKitBaseUrl;
242242
static const String _defaultCanvasKitBaseUrl = String.fromEnvironment(
243243
'FLUTTER_WEB_CANVASKIT_URL',
244-
defaultValue: 'canvaskit/',
244+
defaultValue: '/canvaskit/',
245245
);
246246

247247
/// The variant of CanvasKit to download.

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

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

33843384
/// Converts a String `url` into a [DomTrustedScriptURL] object when the
33853385
/// Trusted Types API is available, else returns the unmodified `url`.
3386-
Object createTrustedScriptUrl(String url) {
3386+
JSAny createTrustedScriptUrl(String url) {
33873387
if (domWindow.trustedTypes != null) {
33883388
// Pass `url` through Flutter Engine's TrustedType policy.
33893389
final DomTrustedScriptURL trustedUrl = _ttPolicy.createScriptURL(url);
33903390

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

3393-
return trustedUrl;
3393+
return trustedUrl as JSAny;
33943394
}
3395-
return url;
3395+
return url.toJS;
33963396
}
33973397

33983398
DomMessageChannel createDomMessageChannel() => DomMessageChannel();

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,6 @@ 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-
2821
// window.exports and window.module should be undefined!
2922
expect(
3023
js_util.hasProperty(domWindow, 'exports'),

lib/web_ui/test/engine/configuration_test.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,30 @@ void testMain() {
2222
test('initializes with null', () async {
2323
final FlutterConfiguration config = FlutterConfiguration.legacy(null);
2424

25-
expect(config.canvasKitBaseUrl, 'canvaskit/'); // _defaultCanvasKitBaseUrl
25+
expect(config.canvasKitBaseUrl, '/canvaskit/'); // _defaultCanvasKitBaseUrl
2626
});
2727

2828
test('legacy constructor initializes with a Js Object', () async {
2929
final FlutterConfiguration config = FlutterConfiguration.legacy(
3030
js_util.jsify(<String, Object?>{
31-
'canvasKitBaseUrl': 'some_other_url/',
31+
'canvasKitBaseUrl': '/some_other_url/',
3232
}) as JsFlutterConfiguration);
3333

34-
expect(config.canvasKitBaseUrl, 'some_other_url/');
34+
expect(config.canvasKitBaseUrl, '/some_other_url/');
3535
});
3636
});
3737

3838
group('setUserConfiguration', () {
3939
test('throws assertion error if already initialized from JS', () async {
4040
final FlutterConfiguration config = FlutterConfiguration.legacy(
4141
js_util.jsify(<String, Object?>{
42-
'canvasKitBaseUrl': 'some_other_url/',
42+
'canvasKitBaseUrl': '/some_other_url/',
4343
}) as JsFlutterConfiguration);
4444

4545
expect(() {
4646
config.setUserConfiguration(
4747
js_util.jsify(<String, Object?>{
48-
'canvasKitBaseUrl': 'yet_another_url/',
48+
'canvasKitBaseUrl': '/yet_another_url/',
4949
}) as JsFlutterConfiguration);
5050
}, throwsAssertionError);
5151
});
@@ -55,10 +55,10 @@ void testMain() {
5555

5656
config.setUserConfiguration(
5757
js_util.jsify(<String, Object?>{
58-
'canvasKitBaseUrl': 'one_more_url/',
58+
'canvasKitBaseUrl': '/one_more_url/',
5959
}) as JsFlutterConfiguration);
6060

61-
expect(config.canvasKitBaseUrl, 'one_more_url/');
61+
expect(config.canvasKitBaseUrl, '/one_more_url/');
6262
});
6363

6464
test('can receive non-existing properties without crashing', () async {

0 commit comments

Comments
 (0)