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. https://github.com/dart-lang/webdev/issues/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.
This commit is contained in:
parent
f5e8fc35f0
commit
5157d2314b
@ -410,6 +410,7 @@ class _RecompileRequest extends _CompilationRequest {
|
||||
this.suppressErrors, {
|
||||
this.additionalSourceUri,
|
||||
this.nativeAssetsYamlUri,
|
||||
required this.recompileRestart,
|
||||
});
|
||||
|
||||
Uri mainUri;
|
||||
@ -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);
|
||||
@ -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, {
|
||||
@ -544,6 +549,7 @@ abstract class ResidentCompiler {
|
||||
bool checkDartPluginRegistry = false,
|
||||
File? dartPluginRegistrant,
|
||||
Uri? nativeAssetsYaml,
|
||||
bool recompileRestart = false,
|
||||
});
|
||||
|
||||
Future<CompilerOutput?> compileExpression(
|
||||
@ -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);
|
||||
@ -717,6 +724,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
|
||||
suppressErrors,
|
||||
additionalSourceUri: additionalSourceUri,
|
||||
nativeAssetsYamlUri: nativeAssetsYaml,
|
||||
recompileRestart: recompileRestart,
|
||||
),
|
||||
);
|
||||
return completer.future;
|
||||
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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>[]));
|
||||
|
@ -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;
|
||||
|
@ -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>[]);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -1386,6 +1386,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
|
||||
bool checkDartPluginRegistry = false,
|
||||
File? dartPluginRegistrant,
|
||||
Uri? nativeAssetsYaml,
|
||||
bool recompileRestart = false,
|
||||
}) async {
|
||||
return output;
|
||||
}
|
||||
|
@ -1703,6 +1703,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
|
||||
bool checkDartPluginRegistry = false,
|
||||
File? dartPluginRegistrant,
|
||||
Uri? nativeAssetsYaml,
|
||||
bool recompileRestart = false,
|
||||
}) async {
|
||||
return output;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
}
|
@ -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,
|
||||
);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user