Wait until all scripts are loaded in the page before running main for the DDC library bundle format (#162707)
https://github.com/flutter/flutter/issues/162567 - Uses the `bootstrapScript` field in `loadConfig` to run a script after all scripts have loaded. - This script just calls a callback that is set up beforehand and calls main. - Modifies the callback that calls `dartDevEmbedder.runMain` to wait until both DWDS called main and all scripts have loaded. - Unskips hot reload tests now that the race condition should no longer exist. ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing.
This commit is contained in:
parent
44785daf01
commit
d3c96c65e5
@ -1087,6 +1087,10 @@ class WebDevFS implements DevFS {
|
|||||||
generateLoadingIndicator: enableDwds,
|
generateLoadingIndicator: enableDwds,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
const String onLoadEndBootstrap = 'on_load_end_bootstrap.js';
|
||||||
|
if (ddcModuleSystem) {
|
||||||
|
webAssetServer.writeFile(onLoadEndBootstrap, generateDDCLibraryBundleOnLoadEndBootstrap());
|
||||||
|
}
|
||||||
webAssetServer.writeFile(
|
webAssetServer.writeFile(
|
||||||
'main_module.bootstrap.js',
|
'main_module.bootstrap.js',
|
||||||
ddcModuleSystem
|
ddcModuleSystem
|
||||||
@ -1094,6 +1098,7 @@ class WebDevFS implements DevFS {
|
|||||||
entrypoint: entrypoint,
|
entrypoint: entrypoint,
|
||||||
nullAssertions: nullAssertions,
|
nullAssertions: nullAssertions,
|
||||||
nativeNullAssertions: nativeNullAssertions,
|
nativeNullAssertions: nativeNullAssertions,
|
||||||
|
onLoadEndBootstrap: onLoadEndBootstrap,
|
||||||
)
|
)
|
||||||
: generateMainModule(
|
: generateMainModule(
|
||||||
entrypoint: entrypoint,
|
entrypoint: entrypoint,
|
||||||
|
@ -505,10 +505,13 @@ String generateDDCMainModule({
|
|||||||
''';
|
''';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const String _onLoadEndCallback = r'$onLoadEndCallback';
|
||||||
|
|
||||||
String generateDDCLibraryBundleMainModule({
|
String generateDDCLibraryBundleMainModule({
|
||||||
required String entrypoint,
|
required String entrypoint,
|
||||||
required bool nullAssertions,
|
required bool nullAssertions,
|
||||||
required bool nativeNullAssertions,
|
required bool nativeNullAssertions,
|
||||||
|
required String onLoadEndBootstrap,
|
||||||
}) {
|
}) {
|
||||||
// The typo below in "EXTENTION" is load-bearing, package:build depends on it.
|
// The typo below in "EXTENTION" is load-bearing, package:build depends on it.
|
||||||
return '''
|
return '''
|
||||||
@ -519,21 +522,48 @@ String generateDDCLibraryBundleMainModule({
|
|||||||
|
|
||||||
dartDevEmbedder.debugger.registerDevtoolsFormatter();
|
dartDevEmbedder.debugger.registerDevtoolsFormatter();
|
||||||
|
|
||||||
let child = {};
|
// Set up a final script that lets us know when all scripts have been loaded.
|
||||||
child.main = function() {
|
let onLoadEndSrc = '$onLoadEndBootstrap';
|
||||||
let sdkOptions = {
|
window.\$dartLoader.loadConfig.bootstrapScript = {
|
||||||
nonNullAsserts: $nullAssertions,
|
src: onLoadEndSrc,
|
||||||
nativeNonNullAsserts: $nativeNullAssertions,
|
id: onLoadEndSrc,
|
||||||
};
|
};
|
||||||
dartDevEmbedder.runMain(appName, sdkOptions);
|
window.\$dartLoader.loadConfig.tryLoadBootstrapScript = true;
|
||||||
|
let dwdsCalledMain = false;
|
||||||
|
let dartSrcsLoaded = false;
|
||||||
|
let runMainWhenBoth = function() {
|
||||||
|
// Only run once both all the scripts are loaded and DWDS triggers main.
|
||||||
|
if (dwdsCalledMain && dartSrcsLoaded) {
|
||||||
|
let sdkOptions = {
|
||||||
|
nonNullAsserts: $nullAssertions,
|
||||||
|
nativeNonNullAsserts: $nativeNullAssertions,
|
||||||
|
};
|
||||||
|
dartDevEmbedder.runMain(appName, sdkOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DWDS expects the main function to be lowercase.
|
||||||
|
// TODO(srujzs): DWDS should be more robust to not have to require that.
|
||||||
|
dwdsmain = function() {
|
||||||
|
dwdsCalledMain = true;
|
||||||
|
runMainWhenBoth();
|
||||||
|
}
|
||||||
|
// Should be called by $onLoadEndBootstrap once all the scripts have been
|
||||||
|
// loaded.
|
||||||
|
window.$_onLoadEndCallback = function() {
|
||||||
|
dartSrcsLoaded = true;
|
||||||
|
runMainWhenBoth();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MAIN_EXTENSION_MARKER */
|
/* MAIN_EXTENSION_MARKER */
|
||||||
child.main();
|
dwdsmain();
|
||||||
})();
|
})();
|
||||||
''';
|
''';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String generateDDCLibraryBundleOnLoadEndBootstrap() {
|
||||||
|
return '''window.$_onLoadEndCallback();''';
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate a synthetic main module which captures the application's main
|
/// Generate a synthetic main module which captures the application's main
|
||||||
/// method.
|
/// method.
|
||||||
///
|
///
|
||||||
|
@ -273,6 +273,7 @@ void main() {
|
|||||||
entrypoint: 'main.js',
|
entrypoint: 'main.js',
|
||||||
nullAssertions: false,
|
nullAssertions: false,
|
||||||
nativeNullAssertions: false,
|
nativeNullAssertions: false,
|
||||||
|
onLoadEndBootstrap: 'on_load_end_bootstrap.js',
|
||||||
);
|
);
|
||||||
// bootstrap main module has correct defined module.
|
// bootstrap main module has correct defined module.
|
||||||
expect(result, contains('let appName = "org-dartlang-app:/main.js";'));
|
expect(result, contains('let appName = "org-dartlang-app:/main.js";'));
|
||||||
@ -284,6 +285,7 @@ void main() {
|
|||||||
entrypoint: 'main.js',
|
entrypoint: 'main.js',
|
||||||
nullAssertions: true,
|
nullAssertions: true,
|
||||||
nativeNullAssertions: true,
|
nativeNullAssertions: true,
|
||||||
|
onLoadEndBootstrap: 'on_load_end_bootstrap.js',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result, contains('nonNullAsserts: true'));
|
expect(result, contains('nonNullAsserts: true'));
|
||||||
@ -295,6 +297,7 @@ void main() {
|
|||||||
entrypoint: 'main.js',
|
entrypoint: 'main.js',
|
||||||
nullAssertions: false,
|
nullAssertions: false,
|
||||||
nativeNullAssertions: false,
|
nativeNullAssertions: false,
|
||||||
|
onLoadEndBootstrap: 'on_load_end_bootstrap.js',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result, contains('nonNullAsserts: false'));
|
expect(result, contains('nonNullAsserts: false'));
|
||||||
|
@ -12,11 +12,7 @@ import '../test_driver.dart';
|
|||||||
import '../test_utils.dart';
|
import '../test_utils.dart';
|
||||||
import 'hot_reload_project.dart';
|
import 'hot_reload_project.dart';
|
||||||
|
|
||||||
void testAll({
|
void testAll({bool chrome = false, List<String> additionalCommandArgs = const <String>[]}) {
|
||||||
bool chrome = false,
|
|
||||||
List<String> additionalCommandArgs = const <String>[],
|
|
||||||
Object? skip = false,
|
|
||||||
}) {
|
|
||||||
group('chrome: $chrome'
|
group('chrome: $chrome'
|
||||||
'${additionalCommandArgs.isEmpty ? '' : ' with args: $additionalCommandArgs'}', () {
|
'${additionalCommandArgs.isEmpty ? '' : ' with args: $additionalCommandArgs'}', () {
|
||||||
late Directory tempDir;
|
late Directory tempDir;
|
||||||
@ -235,7 +231,7 @@ void testAll({
|
|||||||
// isolates, so this test will wait forever.
|
// isolates, so this test will wait forever.
|
||||||
skip: chrome,
|
skip: chrome,
|
||||||
);
|
);
|
||||||
}, skip: skip);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isHotReloadCompletionEvent(Map<String, Object?>? event) {
|
bool _isHotReloadCompletionEvent(Map<String, Object?>? event) {
|
||||||
|
@ -11,11 +11,7 @@ import '../test_driver.dart';
|
|||||||
import '../test_utils.dart';
|
import '../test_utils.dart';
|
||||||
import 'hot_reload_with_asset.dart';
|
import 'hot_reload_with_asset.dart';
|
||||||
|
|
||||||
void testAll({
|
void testAll({bool chrome = false, List<String> additionalCommandArgs = const <String>[]}) {
|
||||||
bool chrome = false,
|
|
||||||
List<String> additionalCommandArgs = const <String>[],
|
|
||||||
Object? skip = false,
|
|
||||||
}) {
|
|
||||||
group('chrome: $chrome'
|
group('chrome: $chrome'
|
||||||
'${additionalCommandArgs.isEmpty ? '' : ' with args: $additionalCommandArgs'}', () {
|
'${additionalCommandArgs.isEmpty ? '' : ' with args: $additionalCommandArgs'}', () {
|
||||||
late Directory tempDir;
|
late Directory tempDir;
|
||||||
@ -86,5 +82,5 @@ void testAll({
|
|||||||
await flutter.hotRestart();
|
await flutter.hotRestart();
|
||||||
await onSecondLoad.future;
|
await onSecondLoad.future;
|
||||||
});
|
});
|
||||||
}, skip: skip);
|
});
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,7 @@ import '../test_utils.dart';
|
|||||||
|
|
||||||
// This test verifies that we can hot reload a stateless widget into a
|
// This test verifies that we can hot reload a stateless widget into a
|
||||||
// stateful one and back.
|
// stateful one and back.
|
||||||
void testAll({
|
void testAll({bool chrome = false, List<String> additionalCommandArgs = const <String>[]}) {
|
||||||
bool chrome = false,
|
|
||||||
List<String> additionalCommandArgs = const <String>[],
|
|
||||||
Object? skip = false,
|
|
||||||
}) {
|
|
||||||
group('chrome: $chrome'
|
group('chrome: $chrome'
|
||||||
'${additionalCommandArgs.isEmpty ? '' : ' with args: $additionalCommandArgs'}', () {
|
'${additionalCommandArgs.isEmpty ? '' : ' with args: $additionalCommandArgs'}', () {
|
||||||
late Directory tempDir;
|
late Directory tempDir;
|
||||||
@ -60,5 +56,5 @@ void testAll({
|
|||||||
expect(logs, contains('STATEFUL'));
|
expect(logs, contains('STATEFUL'));
|
||||||
await subscription.cancel();
|
await subscription.cancel();
|
||||||
});
|
});
|
||||||
}, skip: skip);
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
@Tags(<String>['flutter-test-driver'])
|
@Tags(<String>['flutter-test-driver'])
|
||||||
library;
|
library;
|
||||||
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import '../integration.shard/test_data/hot_reload_errors_common.dart';
|
import '../integration.shard/test_data/hot_reload_errors_common.dart';
|
||||||
import '../src/common.dart';
|
import '../src/common.dart';
|
||||||
|
|
||||||
@ -19,7 +17,5 @@ void main() {
|
|||||||
// TODO(srujzs): Remove this custom message once we have the delta inspector emitting the same
|
// TODO(srujzs): Remove this custom message once we have the delta inspector emitting the same
|
||||||
// string as the VM.
|
// string as the VM.
|
||||||
constClassFieldRemovalErrorMessage: 'Const class cannot remove fields',
|
constClassFieldRemovalErrorMessage: 'Const class cannot remove fields',
|
||||||
// https://github.com/flutter/flutter/issues/162567
|
|
||||||
skip: Platform.isWindows,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,5 @@ void main() {
|
|||||||
additionalCommandArgs: <String>[
|
additionalCommandArgs: <String>[
|
||||||
'--extra-front-end-options=--dartdevc-canary,--dartdevc-module-format=ddc',
|
'--extra-front-end-options=--dartdevc-canary,--dartdevc-module-format=ddc',
|
||||||
],
|
],
|
||||||
// https://github.com/flutter/flutter/issues/162567
|
|
||||||
skip: true,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,5 @@ void main() {
|
|||||||
additionalCommandArgs: <String>[
|
additionalCommandArgs: <String>[
|
||||||
'--extra-front-end-options=--dartdevc-canary,--dartdevc-module-format=ddc',
|
'--extra-front-end-options=--dartdevc-canary,--dartdevc-module-format=ddc',
|
||||||
],
|
],
|
||||||
// https://github.com/flutter/flutter/issues/162567
|
|
||||||
skip: true,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,5 @@ void main() {
|
|||||||
additionalCommandArgs: <String>[
|
additionalCommandArgs: <String>[
|
||||||
'--extra-front-end-options=--dartdevc-canary,--dartdevc-module-format=ddc',
|
'--extra-front-end-options=--dartdevc-canary,--dartdevc-module-format=ddc',
|
||||||
],
|
],
|
||||||
// https://github.com/flutter/flutter/issues/162567
|
|
||||||
skip: true,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user