Skip to content

Use recompile-restart instruction when hot restarting on the web #162616

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 4, 2025
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
14 changes: 13 additions & 1 deletion packages/flutter_tools/lib/src/compile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ class _RecompileRequest extends _CompilationRequest {
this.suppressErrors, {
this.additionalSourceUri,
this.nativeAssetsYamlUri,
required this.recompileRestart,
});

Uri mainUri;
Expand All @@ -419,6 +420,7 @@ class _RecompileRequest extends _CompilationRequest {
bool suppressErrors;
final Uri? additionalSourceUri;
final Uri? nativeAssetsYamlUri;
final bool recompileRestart;

@override
Future<CompilerOutput?> _run(DefaultResidentCompiler compiler) async => compiler._recompile(this);
Expand Down Expand Up @@ -533,6 +535,9 @@ abstract class ResidentCompiler {
/// If [checkDartPluginRegistry] is true, it is the caller's responsibility
/// to ensure that the generated registrant file has been updated such that
/// it is wrapping [mainUri].
///
/// If [recompileRestart] is true, uses the `recompile-restart` instruction
/// intended for a hot restart instead.
Future<CompilerOutput?> recompile(
Uri mainUri,
List<Uri>? invalidatedFiles, {
Expand All @@ -544,6 +549,7 @@ abstract class ResidentCompiler {
bool checkDartPluginRegistry = false,
File? dartPluginRegistrant,
Uri? nativeAssetsYaml,
bool recompileRestart = false,
});

Future<CompilerOutput?> compileExpression(
Expand Down Expand Up @@ -695,6 +701,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
String? projectRootPath,
FileSystem? fs,
Uri? nativeAssetsYaml,
bool recompileRestart = false,
}) async {
if (!_controller.hasListener) {
_controller.stream.listen(_handleCompilationRequest);
Expand All @@ -717,6 +724,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
suppressErrors,
additionalSourceUri: additionalSourceUri,
nativeAssetsYamlUri: nativeAssetsYaml,
recompileRestart: recompileRestart,
),
);
return completer.future;
Expand Down Expand Up @@ -759,7 +767,11 @@ class DefaultResidentCompiler implements ResidentCompiler {
server.stdin.writeln('native-assets $nativeAssets');
_logger.printTrace('<- native-assets $nativeAssets');
}
server.stdin.writeln('recompile $mainUri $inputKey');
if (request.recompileRestart) {
server.stdin.writeln('recompile-restart $mainUri $inputKey');
} else {
server.stdin.writeln('recompile $mainUri $inputKey');
}
_logger.printTrace('<- recompile $mainUri $inputKey');
final List<Uri>? invalidatedFiles = request.invalidatedFiles;
if (invalidatedFiles != null) {
Expand Down
1 change: 1 addition & 0 deletions packages/flutter_tools/lib/src/isolated/devfs_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,7 @@ class WebDevFS implements DevFS {
projectRootPath: projectRootPath,
fs: globals.fs,
dartPluginRegistrant: dartPluginRegistrant,
recompileRestart: fullRestart,
);
if (compilerOutput == null || compilerOutput.errorCount > 0) {
return UpdateFSReport();
Expand Down
1 change: 1 addition & 0 deletions packages/flutter_tools/test/general.shard/devfs_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
bool checkDartPluginRegistry = false,
File? dartPluginRegistrant,
Uri? nativeAssetsYaml,
bool recompileRestart = false,
}) {
return onRecompile?.call(mainUri, invalidatedFiles) ??
Future<CompilerOutput>.value(const CompilerOutput('', 1, <Uri>[]));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
bool checkDartPluginRegistry = false,
File? dartPluginRegistrant,
Uri? nativeAssetsYaml,
bool recompileRestart = false,
}) async {
recompileCalled = true;
receivedNativeAssetsYaml = nativeAssetsYaml;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1604,6 +1604,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
bool checkDartPluginRegistry = false,
File? dartPluginRegistrant,
Uri? nativeAssetsYaml,
bool recompileRestart = false,
}) async {
return const CompilerOutput('foo.dill', 0, <Uri>[]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
bool checkDartPluginRegistry = false,
File? dartPluginRegistrant,
Uri? nativeAssetsYaml,
bool recompileRestart = false,
}) async {
if (compilerOutput != null) {
fileSystem!.file(compilerOutput!.outputFilename).createSync(recursive: true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
bool checkDartPluginRegistry = false,
File? dartPluginRegistrant,
Uri? nativeAssetsYaml,
bool recompileRestart = false,
}) async {
return output;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1703,6 +1703,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
bool checkDartPluginRegistry = false,
File? dartPluginRegistrant,
Uri? nativeAssetsYaml,
bool recompileRestart = false,
}) async {
return output;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,9 @@
@Tags(<String>['flutter-test-driver'])
library;

import 'package:file/file.dart';

import '../src/common.dart';
import 'test_data/hot_reload_const_project.dart';
import 'test_driver.dart';
import 'test_utils.dart';
import 'test_data/hot_reload_errors_common.dart';

void main() {
late Directory tempDir;
final HotReloadConstProject project = HotReloadConstProject();
late FlutterRunTestDriver flutter;

setUp(() async {
tempDir = createResolvedTempDirectorySync('hot_reload_test.');
await project.setUpIn(tempDir);
flutter = FlutterRunTestDriver(tempDir);
});

tearDown(() async {
await flutter.stop();
tryToDelete(tempDir);
});

testWithoutContext(
'hot reload displays a formatted error message when removing a field from a const class',
() async {
await flutter.run();
project.removeFieldFromConstClass();

expect(
flutter.hotReload(),
throwsA(
isA<Exception>().having(
(Exception e) => e.toString(),
'message',
contains('Try performing a hot restart instead.'),
),
),
);
},
);
testAll();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:file/file.dart';

import '../../src/common.dart';
import '../test_driver.dart';
import '../test_utils.dart';
import 'hot_reload_const_project.dart';

void testAll({
bool chrome = false,
List<String> additionalCommandArgs = const <String>[],
String constClassFieldRemovalErrorMessage = 'Try performing a hot restart instead.',
Object? skip = false,
}) {
group('chrome: $chrome'
'${additionalCommandArgs.isEmpty ? '' : ' with args: $additionalCommandArgs'}', () {
late Directory tempDir;
final HotReloadConstProject project = HotReloadConstProject();
late FlutterRunTestDriver flutter;

setUp(() async {
tempDir = createResolvedTempDirectorySync('hot_reload_test.');
await project.setUpIn(tempDir);
flutter = FlutterRunTestDriver(tempDir);
});

tearDown(() async {
await flutter.stop();
tryToDelete(tempDir);
});

testWithoutContext(
'hot reload displays a formatted error message when removing a field from a const class',
() async {
await flutter.run();
project.removeFieldFromConstClass();

expect(
flutter.hotReload(),
throwsA(
isA<Exception>().having(
(Exception e) => e.toString(),
'message',
contains(constClassFieldRemovalErrorMessage),
),
),
);
},
);

testWithoutContext('hot restart succeeds when removing a field from a const class', () async {
await flutter.run(chrome: true, additionalCommandArgs: additionalCommandArgs);
project.removeFieldFromConstClass();
await flutter.hotRestart();
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@Tags(<String>['flutter-test-driver'])
library;

import 'dart:io';

import '../integration.shard/test_data/hot_reload_errors_common.dart';
import '../src/common.dart';

void main() {
testAll(
chrome: true,
additionalCommandArgs: <String>[
'--extra-front-end-options=--dartdevc-canary,--dartdevc-module-format=ddc',
],
// TODO(srujzs): Remove this custom message once we have the delta inspector emitting the same
// string as the VM.
constClassFieldRemovalErrorMessage: 'Const class cannot remove fields',
// https://github.com/flutter/flutter/issues/162567
skip: Platform.isWindows,
);
}