mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
[flutter_tools] Reland initialize frontend_sever with build (#51477)
This commit is contained in:
parent
421056ee54
commit
53457c2241
|
@ -469,7 +469,6 @@ abstract class ResidentCompiler {
|
|||
// See: https://github.com/flutter/flutter/issues/50494
|
||||
void addFileSystemRoot(String root);
|
||||
|
||||
|
||||
/// If invoked for the first time, it compiles Dart script identified by
|
||||
/// [mainPath], [invalidatedFiles] list is ignored.
|
||||
/// On successive runs [invalidatedFiles] indicates which files need to be
|
||||
|
|
|
@ -488,6 +488,9 @@ class DevFS {
|
|||
if (fullRestart) {
|
||||
generator.reset();
|
||||
}
|
||||
// On a full restart, or on an initial compile for the attach based workflow,
|
||||
// this will produce a full dill. Subsequent invocations will produce incremental
|
||||
// dill files that depend on the invalidated files.
|
||||
globals.printTrace('Compiling dart to kernel with ${invalidatedFiles.length} updated files');
|
||||
final CompilerOutput compilerOutput = await generator.recompile(
|
||||
mainPath,
|
||||
|
|
|
@ -629,16 +629,6 @@ abstract class ResidentRunner {
|
|||
if (!artifactDirectory.existsSync()) {
|
||||
artifactDirectory.createSync(recursive: true);
|
||||
}
|
||||
// TODO(jonahwilliams): this is a temporary work around to regain some of
|
||||
// the initialize from dill performance. Longer term, we should have a
|
||||
// better way to determine where the appropriate dill file is, as this
|
||||
// doesn't work for Android or macOS builds.}
|
||||
if (dillOutputPath == null) {
|
||||
final File existingDill = globals.fs.file(globals.fs.path.join('build', 'app.dill'));
|
||||
if (existingDill.existsSync()) {
|
||||
existingDill.copySync(globals.fs.path.join(artifactDirectory.path, 'app.dill'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
|
|
|
@ -16,6 +16,7 @@ import 'base/file_system.dart';
|
|||
import 'base/logger.dart';
|
||||
import 'base/utils.dart';
|
||||
import 'build_info.dart';
|
||||
import 'bundle.dart';
|
||||
import 'compile.dart';
|
||||
import 'convert.dart';
|
||||
import 'devfs.dart';
|
||||
|
@ -329,14 +330,36 @@ class HotRunner extends ResidentRunner {
|
|||
|
||||
firstBuildTime = DateTime.now();
|
||||
|
||||
final List<Future<bool>> startupTasks = <Future<bool>>[];
|
||||
for (final FlutterDevice device in flutterDevices) {
|
||||
final int result = await device.runHot(
|
||||
// Here we initialize the frontend_server concurrently with the platform
|
||||
// build, reducing overall initialization time. This is safe because the first
|
||||
// invocation of the frontend server produces a full dill file that the
|
||||
// subsequent invocation in devfs will not overwrite.
|
||||
if (device.generator != null) {
|
||||
startupTasks.add(
|
||||
device.generator.recompile(
|
||||
mainPath,
|
||||
<Uri>[],
|
||||
outputPath: dillOutputPath ??
|
||||
getDefaultApplicationKernelPath(trackWidgetCreation: device.trackWidgetCreation),
|
||||
packagesFilePath : packagesFilePath,
|
||||
).then((CompilerOutput output) => output?.errorCount == 0)
|
||||
);
|
||||
}
|
||||
startupTasks.add(device.runHot(
|
||||
hotRunner: this,
|
||||
route: route,
|
||||
);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
).then((int result) => result == 0));
|
||||
}
|
||||
try {
|
||||
final List<bool> results = await Future.wait(startupTasks);
|
||||
if (!results.every((bool passed) => passed)) {
|
||||
return 1;
|
||||
}
|
||||
} on Exception catch (err) {
|
||||
globals.printError(err.toString());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return attach(
|
||||
|
|
|
@ -84,47 +84,6 @@ void main() {
|
|||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('Forces fast start off for devices that do not support it', () async {
|
||||
final MockDevice mockDevice = MockDevice(TargetPlatform.android_arm);
|
||||
when(mockDevice.name).thenReturn('mockdevice');
|
||||
when(mockDevice.supportsFastStart).thenReturn(false);
|
||||
when(mockDevice.supportsHotReload).thenReturn(true);
|
||||
when(mockDevice.isLocalEmulator).thenAnswer((Invocation invocation) async => false);
|
||||
when(deviceManager.hasSpecifiedAllDevices).thenReturn(false);
|
||||
when(deviceManager.findTargetDevices(any)).thenAnswer((Invocation invocation) {
|
||||
return Future<List<Device>>.value(<Device>[mockDevice]);
|
||||
});
|
||||
when(deviceManager.getDevices()).thenAnswer((Invocation invocation) {
|
||||
return Future<List<Device>>.value(<Device>[mockDevice]);
|
||||
});
|
||||
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
|
||||
globals.fs.file('pubspec.yaml').createSync();
|
||||
globals.fs.file('.packages').createSync();
|
||||
|
||||
final RunCommand command = RunCommand();
|
||||
applyMocksToCommand(command);
|
||||
try {
|
||||
await createTestCommandRunner(command).run(<String>[
|
||||
'run',
|
||||
'--fast-start',
|
||||
'--no-pub',
|
||||
]);
|
||||
fail('Expect exception');
|
||||
} catch (e) {
|
||||
expect(e, isA<ToolExit>());
|
||||
}
|
||||
|
||||
final BufferLogger bufferLogger = globals.logger as BufferLogger;
|
||||
expect(bufferLogger.statusText, isNot(contains(
|
||||
'Using --fast-start option with device mockdevice, but this device '
|
||||
'does not support it. Overriding the setting to false.'
|
||||
)));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => MemoryFileSystem(),
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
DeviceManager: () => MockDeviceManager(),
|
||||
});
|
||||
|
||||
testUsingContext('Walks upward looking for a pubspec.yaml and succeeds if found', () async {
|
||||
globals.fs.file('pubspec.yaml').createSync();
|
||||
globals.fs.file('.packages')
|
||||
|
|
|
@ -234,10 +234,6 @@ void main() {
|
|||
Usage: () => MockUsage(),
|
||||
}));
|
||||
|
||||
test('ResidentRunner copies dill file from build output into temp directory', () => testbed.run(() async {
|
||||
expect(residentRunner.artifactDirectory.childFile('app.dill').readAsStringSync(), 'ABC');
|
||||
}));
|
||||
|
||||
test('ResidentRunner can send target platform to analytics from hot reload', () => testbed.run(() async {
|
||||
when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation invocation) async {
|
||||
return 'Example';
|
||||
|
|
|
@ -36,10 +36,10 @@ void main() {
|
|||
});
|
||||
|
||||
test('newly added code executes during hot reload', () async {
|
||||
await _flutter.run();
|
||||
_project.uncommentHotReloadPrint();
|
||||
final StringBuffer stdout = StringBuffer();
|
||||
final StreamSubscription<String> subscription = _flutter.stdout.listen(stdout.writeln);
|
||||
await _flutter.run();
|
||||
_project.uncommentHotReloadPrint();
|
||||
try {
|
||||
await _flutter.hotReload();
|
||||
expect(stdout.toString(), contains('(((((RELOAD WORKED)))))'));
|
||||
|
@ -49,10 +49,10 @@ void main() {
|
|||
});
|
||||
|
||||
test('reloadMethod triggers hot reload behavior', () async {
|
||||
await _flutter.run();
|
||||
_project.uncommentHotReloadPrint();
|
||||
final StringBuffer stdout = StringBuffer();
|
||||
final StreamSubscription<String> subscription = _flutter.stdout.listen(stdout.writeln);
|
||||
await _flutter.run();
|
||||
_project.uncommentHotReloadPrint();
|
||||
try {
|
||||
final String libraryId = _project.buildBreakpointUri.toString();
|
||||
await _flutter.reloadMethod(libraryId: libraryId, classId: 'MyApp');
|
||||
|
@ -72,7 +72,6 @@ void main() {
|
|||
|
||||
test('breakpoints are hit after hot reload', () async {
|
||||
Isolate isolate;
|
||||
await _flutter.run(withDebugger: true, startPaused: true);
|
||||
final Completer<void> sawTick1 = Completer<void>();
|
||||
final Completer<void> sawTick3 = Completer<void>();
|
||||
final Completer<void> sawDebuggerPausedMessage = Completer<void>();
|
||||
|
@ -92,6 +91,7 @@ void main() {
|
|||
}
|
||||
},
|
||||
);
|
||||
await _flutter.run(withDebugger: true, startPaused: true);
|
||||
await _flutter.resume(); // we start paused so we can set up our TICK 1 listener before the app starts
|
||||
unawaited(sawTick1.future.timeout(
|
||||
const Duration(seconds: 5),
|
||||
|
@ -125,16 +125,15 @@ void main() {
|
|||
});
|
||||
|
||||
test("hot reload doesn't reassemble if paused", () async {
|
||||
await _flutter.run(withDebugger: true);
|
||||
final Completer<void> sawTick2 = Completer<void>();
|
||||
final Completer<void> sawTick1 = Completer<void>();
|
||||
final Completer<void> sawTick3 = Completer<void>();
|
||||
final Completer<void> sawDebuggerPausedMessage1 = Completer<void>();
|
||||
final Completer<void> sawDebuggerPausedMessage2 = Completer<void>();
|
||||
final StreamSubscription<String> subscription = _flutter.stdout.listen(
|
||||
(String line) {
|
||||
if (line.contains('((((TICK 2))))')) {
|
||||
expect(sawTick2.isCompleted, isFalse);
|
||||
sawTick2.complete();
|
||||
if (line.contains('(((TICK 1)))')) {
|
||||
expect(sawTick1.isCompleted, isFalse);
|
||||
sawTick1.complete();
|
||||
}
|
||||
if (line.contains('The application is paused in the debugger on a breakpoint.')) {
|
||||
expect(sawDebuggerPausedMessage1.isCompleted, isFalse);
|
||||
|
@ -146,13 +145,14 @@ void main() {
|
|||
}
|
||||
},
|
||||
);
|
||||
await _flutter.run(withDebugger: true);
|
||||
await sawTick1.future;
|
||||
await _flutter.addBreakpoint(
|
||||
_project.buildBreakpointUri,
|
||||
_project.buildBreakpointLine,
|
||||
);
|
||||
bool reloaded = false;
|
||||
final Future<void> reloadFuture = _flutter.hotReload().then((void value) { reloaded = true; });
|
||||
await sawTick2.future; // this should happen before it pauses
|
||||
final Isolate isolate = await _flutter.waitForPause();
|
||||
expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint));
|
||||
expect(reloaded, isFalse);
|
||||
|
|
Loading…
Reference in a new issue