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

Refactor flutter.js to do dart2wasm bootstrapping and CanvasKit/Skwasm preloading. #49037

Merged
merged 34 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d7c1388
Modularize flutter.js source.
eyebrowsoffire Nov 14, 2023
b25b444
Started new load function.
eyebrowsoffire Nov 21, 2023
766079d
More flutter js loader stuff.
eyebrowsoffire Dec 8, 2023
4157dd5
Some tests running (but hard coded currently).
eyebrowsoffire Dec 9, 2023
43f3c6f
dart2wasm and dart2js both working (although no skwasm yet).
eyebrowsoffire Dec 13, 2023
94d8dfa
Many tests are working.
eyebrowsoffire Dec 13, 2023
4267ee2
Remove hack.
eyebrowsoffire Dec 14, 2023
0103f5e
Fix browsers without Trusted Types.
eyebrowsoffire Dec 14, 2023
9abd044
Update licenses golden.
eyebrowsoffire Dec 14, 2023
1898e0e
Remove old test harnesses.
eyebrowsoffire Dec 14, 2023
406cd6b
Inject engine revision into flutter.js.
eyebrowsoffire Dec 14, 2023
7142f19
Don't copy nonexistent bootstrap scripts anymore.
eyebrowsoffire Dec 14, 2023
770a89d
Remove skwasm_stub tests. No longer pertinent.
eyebrowsoffire Dec 15, 2023
111fdd9
Adjust builder json.
eyebrowsoffire Dec 15, 2023
c249d05
Allow for multiple compile configs.
eyebrowsoffire Dec 15, 2023
06b27a5
Add test for build fallbacks.
eyebrowsoffire Dec 15, 2023
77f2673
Add some additional types and JSDoc comments.
eyebrowsoffire Dec 15, 2023
d603f40
Add nonce support.
eyebrowsoffire Dec 15, 2023
c66b062
Fix service worker's reference to `baseUri`.
eyebrowsoffire Dec 18, 2023
f41f51c
Fix licenses.
eyebrowsoffire Dec 18, 2023
1a19c9c
Set trusted types policy properly on service worker loader.
eyebrowsoffire Dec 19, 2023
180608d
Expect a trailing slash at the end of the canvaskit base url.
eyebrowsoffire Dec 19, 2023
1ff4217
Make sure skwasm works when hosted via CDN.
eyebrowsoffire Dec 19, 2023
1a4a0a6
Optimize loading waterfall for CanvasKit and Skwasm.
eyebrowsoffire Dec 21, 2023
30349fa
Fix whitespace.
eyebrowsoffire Dec 21, 2023
cec8c2c
Remove log messages and add newline at the end of file.
eyebrowsoffire Dec 21, 2023
8df86a5
Fixed licenses golden.
eyebrowsoffire Dec 21, 2023
d3ebe8e
Fix some indentation and formatting on JS files.
eyebrowsoffire Dec 21, 2023
b077685
Addressed another of Yegor's comments.
eyebrowsoffire Dec 21, 2023
7d45ef2
Addressed some PR comments.
eyebrowsoffire Jan 2, 2024
cc79b91
Fix formatting issue.
eyebrowsoffire Jan 2, 2024
b43df31
Merge branch 'main' into flutter_js_modular
eyebrowsoffire Jan 2, 2024
a8954be
Fix analysis error.
eyebrowsoffire Jan 2, 2024
63ead1a
More JS equality stuff.
eyebrowsoffire Jan 4, 2024
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
495 changes: 426 additions & 69 deletions ci/builders/linux_web_engine.json

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -5872,7 +5872,16 @@ ORIGIN: ../../../flutter/lib/ui/window/pointer_data_packet_converter.cc + ../../
ORIGIN: ../../../flutter/lib/ui/window/pointer_data_packet_converter.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/ui/window/viewport_metrics.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/ui/window/viewport_metrics.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/base_uri.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/browser_environment.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/canvaskit_loader.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/flutter.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/instantiate_wasm.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/loader.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/service_worker_loader.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/skwasm_loader.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/flutter_js/src/trusted_types.js + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/annotations.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/canvas.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/channel_buffers.dart + ../../../flutter/LICENSE
Expand Down Expand Up @@ -8692,7 +8701,17 @@ FILE: ../../../flutter/lib/ui/window/pointer_data_packet_converter.cc
FILE: ../../../flutter/lib/ui/window/pointer_data_packet_converter.h
FILE: ../../../flutter/lib/ui/window/viewport_metrics.cc
FILE: ../../../flutter/lib/ui/window/viewport_metrics.h
FILE: ../../../flutter/lib/web_ui/flutter_js/src/base_uri.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/browser_environment.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/canvaskit_loader.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/flutter.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/instantiate_wasm.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/loader.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/service_worker_loader.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/skwasm_loader.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/trusted_types.js
FILE: ../../../flutter/lib/web_ui/flutter_js/src/types.d.ts
FILE: ../../../flutter/lib/web_ui/lib/annotations.dart
FILE: ../../../flutter/lib/web_ui/lib/canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/channel_buffers.dart
Expand Down
13 changes: 1 addition & 12 deletions lib/web_ui/dev/chrome.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,11 @@ import 'package_lock.dart';
/// Provides an environment for desktop Chrome.
class ChromeEnvironment implements BrowserEnvironment {
ChromeEnvironment({
required bool enableWasmGC,
required bool useDwarf,
}) : _enableWasmGC = enableWasmGC,
_useDwarf = useDwarf;
}) : _useDwarf = useDwarf;

late final BrowserInstallation _installation;

final bool _enableWasmGC;
final bool _useDwarf;

@override
Expand All @@ -42,7 +39,6 @@ class ChromeEnvironment implements BrowserEnvironment {
url,
_installation,
debug: debug,
enableWasmGC: _enableWasmGC,
useDwarf: _useDwarf
);
}
Expand Down Expand Up @@ -83,7 +79,6 @@ class Chrome extends Browser {
Uri url,
BrowserInstallation installation, {
required bool debug,
required bool enableWasmGC,
required bool useDwarf,
}) {
final Completer<Uri> remoteDebuggerCompleter = Completer<Uri>.sync();
Expand All @@ -101,13 +96,7 @@ class Chrome extends Browser {
final bool isChromeNoSandbox =
Platform.environment['CHROME_NO_SANDBOX'] == 'true';
final String dir = await generateUserDirectory(installation, useDwarf);
final String jsFlags = enableWasmGC ? <String>[
'--experimental-wasm-gc',
'--experimental-wasm-stack-switching',
'--experimental-wasm-type-reflection',
].join(' ') : '';
final List<String> args = <String>[
if (jsFlags.isNotEmpty) '--js-flags=$jsFlags',
'--user-data-dir=$dir',
url.toString(),
if (!debug)
Expand Down
3 changes: 1 addition & 2 deletions lib/web_ui/dev/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,11 @@ const List<String> kAllBrowserNames = <String>[
/// The [browserName] matches the browser name passed as the `--browser` option.
BrowserEnvironment getBrowserEnvironment(
BrowserName browserName, {
required bool enableWasmGC,
required bool useDwarf,
}) {
switch (browserName) {
case BrowserName.chrome:
return ChromeEnvironment(enableWasmGC: enableWasmGC, useDwarf: useDwarf);
return ChromeEnvironment(useDwarf: useDwarf);
case BrowserName.edge:
return EdgeEnvironment();
case BrowserName.firefox:
Expand Down
23 changes: 11 additions & 12 deletions lib/web_ui/dev/felt_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ class TestSet {
}

class TestBundle {
TestBundle(this.name, this.testSet, this.compileConfig);
TestBundle(this.name, this.testSet, this.compileConfigs);

final String name;
final TestSet testSet;
final CompileConfiguration compileConfig;
final List<CompileConfiguration> compileConfigs;
}

enum CanvasKitVariant {
Expand Down Expand Up @@ -157,12 +157,16 @@ class FeltConfig {
if (testSet == null) {
throw AssertionError('Test set not found with name: `$testSetName` (referenced by test bundle: `$name`)');
}
final String compileConfigName = testBundleYaml['compile-config'] as String;
final CompileConfiguration? compileConfig = compileConfigsByName[compileConfigName];
if (compileConfig == null) {
throw AssertionError('Compile config not found with name: `$compileConfigName` (referenced by test bundle: `$name`)');
final dynamic compileConfigsValue = testBundleYaml['compile-configs'];
final List<CompileConfiguration> compileConfigs;
if (compileConfigsValue is String) {
compileConfigs = <CompileConfiguration>[compileConfigsByName[compileConfigsValue]!];
} else {
compileConfigs = (compileConfigsValue as List<dynamic>).map(
(dynamic configName) => compileConfigsByName[configName as String]!
).toList();
}
final TestBundle bundle = TestBundle(name, testSet, compileConfig);
final TestBundle bundle = TestBundle(name, testSet, compileConfigs);
testBundles.add(bundle);
if (testBundlesByName.containsKey(name)) {
throw AssertionError('Duplicate test bundle name: $name');
Expand Down Expand Up @@ -202,11 +206,6 @@ class FeltConfig {
if (runConfig == null) {
throw AssertionError('Run config not found with name: `$runConfigName` (referenced by test suite: `$name`)');
}
if (bundle.compileConfig.renderer == Renderer.canvaskit && runConfig.variant == null) {
throw AssertionError(
'Run config `$runConfigName` was used with a CanvasKit test bundle `$testBundleName` '
'but did not specify a CanvasKit variant (referenced by test suite: `$name`)');
}
bool canvasKit = false;
bool canvasKitChromium = false;
bool skwasm = false;
Expand Down
6 changes: 1 addition & 5 deletions lib/web_ui/dev/generate_builder_json.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,7 @@ Iterable<dynamic> _getAllTestSteps(List<TestSuite> suites) {
suite.runConfig.browser == BrowserName.safari
),
..._getTestStepsForPlatform(suites, 'Windows', (TestSuite suite) =>
suite.runConfig.browser == BrowserName.chrome &&

// TODO(jacksongardner): Enable dart2wasm tests on Windows
// https://github.com/flutter/flutter/issues/124082
suite.testBundle.compileConfig.compiler != Compiler.dart2wasm
suite.runConfig.browser == BrowserName.chrome
),
];
}
Expand Down
61 changes: 34 additions & 27 deletions lib/web_ui/dev/steps/compile_bundle_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,20 @@ class CompileBundleStep implements PipelineStep {
.toList();
}

TestCompiler _createCompiler() {
switch (bundle.compileConfig.compiler) {
TestCompiler _createCompiler(CompileConfiguration config) {
switch (config.compiler) {
case Compiler.dart2js:
return Dart2JSCompiler(
testSetDirectory,
outputBundleDirectory,
renderer: bundle.compileConfig.renderer,
renderer: config.renderer,
isVerbose: isVerbose,
);
case Compiler.dart2wasm:
return Dart2WasmCompiler(
testSetDirectory,
outputBundleDirectory,
renderer: bundle.compileConfig.renderer,
renderer: config.renderer,
isVerbose: isVerbose,
);
}
Expand All @@ -84,7 +84,9 @@ class CompileBundleStep implements PipelineStep {
Future<void> run() async {
print('Compiling test bundle ${bundle.name.ansiMagenta}...');
final List<FilePath> allTests = _findTestFiles();
final TestCompiler compiler = _createCompiler();
final List<TestCompiler> compilers = bundle.compileConfigs.map(
(CompileConfiguration config) => _createCompiler(config)
).toList();
final Stopwatch stopwatch = Stopwatch()..start();
final String testSetDirectoryPath = testSetDirectory.path;

Expand All @@ -94,35 +96,40 @@ class CompileBundleStep implements PipelineStep {
}

final List<Future<MapEntry<String, CompileResult>>> pendingResults = <Future<MapEntry<String, CompileResult>>>[];
for (final FilePath testFile in allTests) {
final String relativePath = pathlib.relative(
testFile.absolute,
from: testSetDirectoryPath);
final Future<MapEntry<String, CompileResult>> result = compilePool.withResource(() async {
if (testFiles != null && !testFiles!.contains(testFile)) {
return MapEntry<String, CompileResult>(relativePath, CompileResult.filtered);
}
final bool success = await compiler.compileTest(testFile);
const int maxTestNameLength = 80;
final String truncatedPath = relativePath.length > maxTestNameLength
? relativePath.replaceRange(maxTestNameLength - 3, relativePath.length, '...')
: relativePath;
final String expandedPath = truncatedPath.padRight(maxTestNameLength);
io.stdout.write('\r ${success ? expandedPath.ansiGreen : expandedPath.ansiRed}');
return success
? MapEntry<String, CompileResult>(relativePath, CompileResult.success)
: MapEntry<String, CompileResult>(relativePath, CompileResult.compilationFailure);
});
pendingResults.add(result);
for (final TestCompiler compiler in compilers) {
for (final FilePath testFile in allTests) {
final String relativePath = pathlib.relative(
testFile.absolute,
from: testSetDirectoryPath);
final Future<MapEntry<String, CompileResult>> result = compilePool.withResource(() async {
if (testFiles != null && !testFiles!.contains(testFile)) {
return MapEntry<String, CompileResult>(relativePath, CompileResult.filtered);
}
final bool success = await compiler.compileTest(testFile);
const int maxTestNameLength = 80;
final String truncatedPath = relativePath.length > maxTestNameLength
? relativePath.replaceRange(maxTestNameLength - 3, relativePath.length, '...')
: relativePath;
final String expandedPath = truncatedPath.padRight(maxTestNameLength);
io.stdout.write('\r ${success ? expandedPath.ansiGreen : expandedPath.ansiRed}');
return success
? MapEntry<String, CompileResult>(relativePath, CompileResult.success)
: MapEntry<String, CompileResult>(relativePath, CompileResult.compilationFailure);
});
pendingResults.add(result);
}
}
final Map<String, CompileResult> results = Map<String, CompileResult>.fromEntries(await Future.wait(pendingResults));
stopwatch.stop();

final String resultsJson = const JsonEncoder.withIndent(' ').convert(<String, dynamic>{
'name': bundle.name,
'directory': bundle.testSet.directory,
'compiler': bundle.compileConfig.compiler.name,
'renderer': bundle.compileConfig.renderer.name,
'builds': bundle.compileConfigs.map(
(CompileConfiguration config) => <String, dynamic>{
'compiler': config.compiler.name,
'renderer': config.renderer.name,
}).toList(),
'compileTimeInMs': stopwatch.elapsedMilliseconds,
'results': results.map((String k, CompileResult v) => MapEntry<String, String>(k, v.name)),
});
Expand Down
18 changes: 0 additions & 18 deletions lib/web_ui/dev/steps/copy_artifacts_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ class CopyArtifactsStep implements PipelineStep {
@override
Future<void> run() async {
await environment.webTestsArtifactsDir.create(recursive: true);
await copyTestBootstrapScripts();
await buildHostPage();
await copyTestFonts();
await copySkiaTestImages();
Expand All @@ -52,23 +51,6 @@ class CopyArtifactsStep implements PipelineStep {
}
}

Future<void> copyTestBootstrapScripts() async {
for (final String filename in <String>[
'test_dart2js.js',
'test_dart2wasm.js',
]) {
final io.File sourceFile = io.File(pathlib.join(
environment.webUiDevDir.path,
filename,
));
final io.File targetFile = io.File(pathlib.join(
environment.webTestsArtifactsDir.path,
filename,
));
await sourceFile.copy(targetFile.path);
}
}

Future<void> copyTestFonts() async {
const Map<String, String> testFonts = <String, String>{
'Ahem': 'ahem.ttf',
Expand Down
11 changes: 7 additions & 4 deletions lib/web_ui/dev/steps/run_suite_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ class RunSuiteStep implements PipelineStep {
/// Require Skia Gold to be available and reachable.
final bool requireSkiaGold;

bool get isWasm => suite.testBundle.compileConfig.compiler == Compiler.dart2wasm;

@override
String get description => 'run_suite';

Expand All @@ -65,7 +63,6 @@ class RunSuiteStep implements PipelineStep {
_prepareTestResultsDirectory();
final BrowserEnvironment browserEnvironment = getBrowserEnvironment(
suite.runConfig.browser,
enableWasmGC: isWasm,
useDwarf: useDwarf,
);
await browserEnvironment.prepare();
Expand Down Expand Up @@ -177,12 +174,18 @@ class RunSuiteStep implements PipelineStep {
}

Future<SkiaGoldClient?> _createSkiaClient() async {
final Renderer renderer = suite.testBundle.compileConfig.renderer;
if (suite.testBundle.compileConfigs.length > 1) {
// Multiple compile configs are only used for our fallback tests, which
// do not collect goldens.
return null;
}
final Renderer renderer = suite.testBundle.compileConfigs.first.renderer;
final CanvasKitVariant? variant = suite.runConfig.variant;
final io.Directory workDirectory = getSkiaGoldDirectoryForSuite(suite);
if (workDirectory.existsSync()) {
workDirectory.deleteSync(recursive: true);
}
final bool isWasm = suite.testBundle.compileConfigs.first.compiler == Compiler.dart2wasm;
final SkiaGoldClient skiaClient = SkiaGoldClient(
workDirectory,
dimensions: <String, String> {
Expand Down
22 changes: 16 additions & 6 deletions lib/web_ui/dev/suite_filter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,28 @@ class FileFilter extends BundleNameFilter {
}
}

class CompilerFilter extends AllowListSuiteFilter<Compiler> {
CompilerFilter({required super.allowList});
class CompilerFilter extends SuiteFilter {
CompilerFilter({required this.allowList});

final Set<Compiler> allowList;

@override
Compiler getAttributeForSuite(TestSuite suite) => suite.testBundle.compileConfig.compiler;
SuiteFilterResult filterSuite(TestSuite suite) => suite.testBundle.compileConfigs.any(
(CompileConfiguration config) => allowList.contains(config.compiler)
) ? SuiteFilterResult.accepted()
: SuiteFilterResult.rejected('Selected compilers not used in suite.');
}

class RendererFilter extends AllowListSuiteFilter<Renderer> {
RendererFilter({required super.allowList});
class RendererFilter extends SuiteFilter {
RendererFilter({required this.allowList});

final Set<Renderer> allowList;

@override
Renderer getAttributeForSuite(TestSuite suite) => suite.testBundle.compileConfig.renderer;
SuiteFilterResult filterSuite(TestSuite suite) => suite.testBundle.compileConfigs.any(
(CompileConfiguration config) => allowList.contains(config.renderer)
) ? SuiteFilterResult.accepted()
: SuiteFilterResult.rejected('Selected renderers not used in suite.');
}

class CanvasKitVariantFilter extends AllowListSuiteFilter<CanvasKitVariant> {
Expand Down
Loading