Skip to content

Commit 5157d23

Browse files
authored
Use recompile-restart instruction when hot restarting on the web (#162616)
recompile has been split into recompile and recompile-restart in the frontend server so that DDC can distinguish between hot reload recompiles and hot restart recompiles, and therefore emit rejection errors only on hot reload. dart-lang/webdev#2516 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing.
1 parent f5e8fc3 commit 5157d23

File tree

11 files changed

+107
-39
lines changed

11 files changed

+107
-39
lines changed

packages/flutter_tools/lib/src/compile.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ class _RecompileRequest extends _CompilationRequest {
410410
this.suppressErrors, {
411411
this.additionalSourceUri,
412412
this.nativeAssetsYamlUri,
413+
required this.recompileRestart,
413414
});
414415

415416
Uri mainUri;
@@ -419,6 +420,7 @@ class _RecompileRequest extends _CompilationRequest {
419420
bool suppressErrors;
420421
final Uri? additionalSourceUri;
421422
final Uri? nativeAssetsYamlUri;
423+
final bool recompileRestart;
422424

423425
@override
424426
Future<CompilerOutput?> _run(DefaultResidentCompiler compiler) async => compiler._recompile(this);
@@ -533,6 +535,9 @@ abstract class ResidentCompiler {
533535
/// If [checkDartPluginRegistry] is true, it is the caller's responsibility
534536
/// to ensure that the generated registrant file has been updated such that
535537
/// it is wrapping [mainUri].
538+
///
539+
/// If [recompileRestart] is true, uses the `recompile-restart` instruction
540+
/// intended for a hot restart instead.
536541
Future<CompilerOutput?> recompile(
537542
Uri mainUri,
538543
List<Uri>? invalidatedFiles, {
@@ -544,6 +549,7 @@ abstract class ResidentCompiler {
544549
bool checkDartPluginRegistry = false,
545550
File? dartPluginRegistrant,
546551
Uri? nativeAssetsYaml,
552+
bool recompileRestart = false,
547553
});
548554

549555
Future<CompilerOutput?> compileExpression(
@@ -695,6 +701,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
695701
String? projectRootPath,
696702
FileSystem? fs,
697703
Uri? nativeAssetsYaml,
704+
bool recompileRestart = false,
698705
}) async {
699706
if (!_controller.hasListener) {
700707
_controller.stream.listen(_handleCompilationRequest);
@@ -717,6 +724,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
717724
suppressErrors,
718725
additionalSourceUri: additionalSourceUri,
719726
nativeAssetsYamlUri: nativeAssetsYaml,
727+
recompileRestart: recompileRestart,
720728
),
721729
);
722730
return completer.future;
@@ -759,7 +767,11 @@ class DefaultResidentCompiler implements ResidentCompiler {
759767
server.stdin.writeln('native-assets $nativeAssets');
760768
_logger.printTrace('<- native-assets $nativeAssets');
761769
}
762-
server.stdin.writeln('recompile $mainUri $inputKey');
770+
if (request.recompileRestart) {
771+
server.stdin.writeln('recompile-restart $mainUri $inputKey');
772+
} else {
773+
server.stdin.writeln('recompile $mainUri $inputKey');
774+
}
763775
_logger.printTrace('<- recompile $mainUri $inputKey');
764776
final List<Uri>? invalidatedFiles = request.invalidatedFiles;
765777
if (invalidatedFiles != null) {

packages/flutter_tools/lib/src/isolated/devfs_web.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,7 @@ class WebDevFS implements DevFS {
11381138
projectRootPath: projectRootPath,
11391139
fs: globals.fs,
11401140
dartPluginRegistrant: dartPluginRegistrant,
1141+
recompileRestart: fullRestart,
11411142
);
11421143
if (compilerOutput == null || compilerOutput.errorCount > 0) {
11431144
return UpdateFSReport();

packages/flutter_tools/test/general.shard/devfs_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
966966
bool checkDartPluginRegistry = false,
967967
File? dartPluginRegistrant,
968968
Uri? nativeAssetsYaml,
969+
bool recompileRestart = false,
969970
}) {
970971
return onRecompile?.call(mainUri, invalidatedFiles) ??
971972
Future<CompilerOutput>.value(const CompilerOutput('', 1, <Uri>[]));

packages/flutter_tools/test/general.shard/resident_runner_helpers.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
321321
bool checkDartPluginRegistry = false,
322322
File? dartPluginRegistrant,
323323
Uri? nativeAssetsYaml,
324+
bool recompileRestart = false,
324325
}) async {
325326
recompileCalled = true;
326327
receivedNativeAssetsYaml = nativeAssetsYaml;

packages/flutter_tools/test/general.shard/resident_web_runner_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
16041604
bool checkDartPluginRegistry = false,
16051605
File? dartPluginRegistrant,
16061606
Uri? nativeAssetsYaml,
1607+
bool recompileRestart = false,
16071608
}) async {
16081609
return const CompilerOutput('foo.dill', 0, <Uri>[]);
16091610
}

packages/flutter_tools/test/general.shard/test/test_compiler_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
311311
bool checkDartPluginRegistry = false,
312312
File? dartPluginRegistrant,
313313
Uri? nativeAssetsYaml,
314+
bool recompileRestart = false,
314315
}) async {
315316
if (compilerOutput != null) {
316317
fileSystem!.file(compilerOutput!.outputFilename).createSync(recursive: true);

packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
13861386
bool checkDartPluginRegistry = false,
13871387
File? dartPluginRegistrant,
13881388
Uri? nativeAssetsYaml,
1389+
bool recompileRestart = false,
13891390
}) async {
13901391
return output;
13911392
}

packages/flutter_tools/test/general.shard/web/devfs_web_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
17031703
bool checkDartPluginRegistry = false,
17041704
File? dartPluginRegistrant,
17051705
Uri? nativeAssetsYaml,
1706+
bool recompileRestart = false,
17061707
}) async {
17071708
return output;
17081709
}

packages/flutter_tools/test/integration.shard/hot_reload_errors_test.dart

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,9 @@
55
@Tags(<String>['flutter-test-driver'])
66
library;
77

8-
import 'package:file/file.dart';
9-
108
import '../src/common.dart';
11-
import 'test_data/hot_reload_const_project.dart';
12-
import 'test_driver.dart';
13-
import 'test_utils.dart';
9+
import 'test_data/hot_reload_errors_common.dart';
1410

1511
void main() {
16-
late Directory tempDir;
17-
final HotReloadConstProject project = HotReloadConstProject();
18-
late FlutterRunTestDriver flutter;
19-
20-
setUp(() async {
21-
tempDir = createResolvedTempDirectorySync('hot_reload_test.');
22-
await project.setUpIn(tempDir);
23-
flutter = FlutterRunTestDriver(tempDir);
24-
});
25-
26-
tearDown(() async {
27-
await flutter.stop();
28-
tryToDelete(tempDir);
29-
});
30-
31-
testWithoutContext(
32-
'hot reload displays a formatted error message when removing a field from a const class',
33-
() async {
34-
await flutter.run();
35-
project.removeFieldFromConstClass();
36-
37-
expect(
38-
flutter.hotReload(),
39-
throwsA(
40-
isA<Exception>().having(
41-
(Exception e) => e.toString(),
42-
'message',
43-
contains('Try performing a hot restart instead.'),
44-
),
45-
),
46-
);
47-
},
48-
);
12+
testAll();
4913
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:file/file.dart';
6+
7+
import '../../src/common.dart';
8+
import '../test_driver.dart';
9+
import '../test_utils.dart';
10+
import 'hot_reload_const_project.dart';
11+
12+
void testAll({
13+
bool chrome = false,
14+
List<String> additionalCommandArgs = const <String>[],
15+
String constClassFieldRemovalErrorMessage = 'Try performing a hot restart instead.',
16+
Object? skip = false,
17+
}) {
18+
group('chrome: $chrome'
19+
'${additionalCommandArgs.isEmpty ? '' : ' with args: $additionalCommandArgs'}', () {
20+
late Directory tempDir;
21+
final HotReloadConstProject project = HotReloadConstProject();
22+
late FlutterRunTestDriver flutter;
23+
24+
setUp(() async {
25+
tempDir = createResolvedTempDirectorySync('hot_reload_test.');
26+
await project.setUpIn(tempDir);
27+
flutter = FlutterRunTestDriver(tempDir);
28+
});
29+
30+
tearDown(() async {
31+
await flutter.stop();
32+
tryToDelete(tempDir);
33+
});
34+
35+
testWithoutContext(
36+
'hot reload displays a formatted error message when removing a field from a const class',
37+
() async {
38+
await flutter.run();
39+
project.removeFieldFromConstClass();
40+
41+
expect(
42+
flutter.hotReload(),
43+
throwsA(
44+
isA<Exception>().having(
45+
(Exception e) => e.toString(),
46+
'message',
47+
contains(constClassFieldRemovalErrorMessage),
48+
),
49+
),
50+
);
51+
},
52+
);
53+
54+
testWithoutContext('hot restart succeeds when removing a field from a const class', () async {
55+
await flutter.run(chrome: true, additionalCommandArgs: additionalCommandArgs);
56+
project.removeFieldFromConstClass();
57+
await flutter.hotRestart();
58+
});
59+
});
60+
}

0 commit comments

Comments
 (0)