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

Reverts "Reland "Output .js files as ES6 modules. (#52023)" (#53688)" #53709

Merged
merged 1 commit into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
33 changes: 23 additions & 10 deletions lib/web_ui/flutter_js/src/canvaskit_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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;
}
59 changes: 37 additions & 22 deletions lib/web_ui/flutter_js/src/skwasm_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
}
56 changes: 39 additions & 17 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<JSAny> defaultExport(CanvasKitInitOptions options);
Future<CanvasKit> CanvasKitInit(CanvasKitInitOptions options) {
return js_util.promiseToFuture<CanvasKit>(
_CanvasKitInit(options).toObjectShallow);
}

typedef LocateFileCallback = String Function(String file, String unusedBase);
Expand Down Expand Up @@ -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<CanvasKit> 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(
Expand All @@ -3682,12 +3681,10 @@ Future<CanvasKit> downloadCanvasKit() async {
/// downloads it.
///
/// If none of the URLs can be downloaded, throws an [Exception].
Future<CanvasKitModule> _downloadOneOf(Iterable<String> urls) async {
Future<void> _downloadOneOf(Iterable<String> urls) async {
for (final String url in urls) {
try {
return await _downloadCanvasKitJs(url);
} catch (_) {
continue;
if (await _downloadCanvasKitJs(url)) {
return;
}
}

Expand All @@ -3701,7 +3698,32 @@ Future<CanvasKitModule> _downloadOneOf(Iterable<String> urls) async {
///
/// Returns a [Future] that completes with `true` if the CanvasKit JavaScript
/// file was successfully downloaded, or `false` if it failed.
Future<CanvasKitModule> _downloadCanvasKitJs(String url) async {
final JSAny scriptUrl = createTrustedScriptUrl(url);
return (await importModule(scriptUrl).toDart) as CanvasKitModule;
Future<bool> _downloadCanvasKitJs(String url) {
final DomHTMLScriptElement canvasKitScript =
createDomHTMLScriptElement(configuration.nonce);
canvasKitScript.src = createTrustedScriptUrl(url);

final Completer<bool> canvasKitLoadCompleter = Completer<bool>();

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;
}
2 changes: 1 addition & 1 deletion lib/web_ui/lib/src/engine/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions lib/web_ui/lib/src/engine/dom.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
14 changes: 7 additions & 7 deletions lib/web_ui/test/engine/configuration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,30 @@ 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(<String, Object?>{
'canvasKitBaseUrl': '/some_other_url/',
'canvasKitBaseUrl': 'some_other_url/',
}) as JsFlutterConfiguration);

expect(config.canvasKitBaseUrl, '/some_other_url/');
expect(config.canvasKitBaseUrl, 'some_other_url/');
});
});

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

expect(() {
config.setUserConfiguration(
js_util.jsify(<String, Object?>{
'canvasKitBaseUrl': '/yet_another_url/',
'canvasKitBaseUrl': 'yet_another_url/',
}) as JsFlutterConfiguration);
}, throwsAssertionError);
});
Expand All @@ -55,10 +55,10 @@ void testMain() {

config.setUserConfiguration(
js_util.jsify(<String, Object?>{
'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 {
Expand Down