Unverified Commit ffbca11f authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] delete BuildRunnerWebCompilationProxy and WebCompilationProxy (#70914)

parent 18167785
...@@ -50,10 +50,8 @@ import 'src/globals.dart' as globals; ...@@ -50,10 +50,8 @@ import 'src/globals.dart' as globals;
import 'src/isolated/devtools_launcher.dart'; import 'src/isolated/devtools_launcher.dart';
import 'src/isolated/mustache_template.dart'; import 'src/isolated/mustache_template.dart';
import 'src/isolated/resident_web_runner.dart'; import 'src/isolated/resident_web_runner.dart';
import 'src/isolated/web_compilation_delegate.dart';
import 'src/resident_runner.dart'; import 'src/resident_runner.dart';
import 'src/runner/flutter_command.dart'; import 'src/runner/flutter_command.dart';
import 'src/web/compile.dart';
import 'src/web/web_runner.dart'; import 'src/web/web_runner.dart';
/// Main entry point for commands. /// Main entry point for commands.
...@@ -145,7 +143,6 @@ Future<void> main(List<String> args) async { ...@@ -145,7 +143,6 @@ Future<void> main(List<String> args) async {
muteCommandLogging: muteCommandLogging, muteCommandLogging: muteCommandLogging,
verboseHelp: verboseHelp, verboseHelp: verboseHelp,
overrides: <Type, Generator>{ overrides: <Type, Generator>{
WebCompilationProxy: () => BuildRunnerWebCompilationProxy(),
// The web runner is not supported in google3 because it depends // The web runner is not supported in google3 because it depends
// on dwds. // on dwds.
WebRunnerFactory: () => DwdsWebRunnerFactory(), WebRunnerFactory: () => DwdsWebRunnerFactory(),
......
...@@ -9,6 +9,7 @@ import 'package:pool/pool.dart'; ...@@ -9,6 +9,7 @@ import 'package:pool/pool.dart';
import 'asset.dart'; import 'asset.dart';
import 'base/common.dart'; import 'base/common.dart';
import 'base/config.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/logger.dart'; import 'base/logger.dart';
import 'build_info.dart'; import 'build_info.dart';
...@@ -40,6 +41,8 @@ String getDefaultCachedKernelPath({ ...@@ -40,6 +41,8 @@ String getDefaultCachedKernelPath({
@required bool trackWidgetCreation, @required bool trackWidgetCreation,
@required List<String> dartDefines, @required List<String> dartDefines,
@required List<String> extraFrontEndOptions, @required List<String> extraFrontEndOptions,
FileSystem fileSystem,
Config config,
}) { }) {
final StringBuffer buffer = StringBuffer(); final StringBuffer buffer = StringBuffer();
buffer.writeAll(dartDefines); buffer.writeAll(dartDefines);
...@@ -51,7 +54,10 @@ String getDefaultCachedKernelPath({ ...@@ -51,7 +54,10 @@ String getDefaultCachedKernelPath({
buildPrefix = '${hex.encode(digest.bytes)}.'; buildPrefix = '${hex.encode(digest.bytes)}.';
} }
return getKernelPathForTransformerOptions( return getKernelPathForTransformerOptions(
globals.fs.path.join(getBuildDirectory(), '${buildPrefix}cache.dill'), (fileSystem ?? globals.fs).path.join(getBuildDirectory(
config ?? globals.config,
fileSystem ?? globals.fs
), '${buildPrefix}cache.dill'),
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
); );
} }
......
...@@ -12,12 +12,12 @@ import '../build_info.dart'; ...@@ -12,12 +12,12 @@ import '../build_info.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../project.dart'; import '../project.dart';
import '../web/chrome.dart'; import '../web/chrome.dart';
import '../web/compile.dart';
import '../web/memory_fs.dart'; import '../web/memory_fs.dart';
import 'flutter_platform.dart' as loader; import 'flutter_platform.dart' as loader;
import 'flutter_web_platform.dart'; import 'flutter_web_platform.dart';
import 'test_wrapper.dart'; import 'test_wrapper.dart';
import 'watcher.dart'; import 'watcher.dart';
import 'web_test_compiler.dart';
/// A class that abstracts launching the test process from the test runner. /// A class that abstracts launching the test process from the test runner.
abstract class FlutterTestRunner { abstract class FlutterTestRunner {
...@@ -123,7 +123,14 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { ...@@ -123,7 +123,14 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
.absolute .absolute
.uri .uri
.toFilePath(); .toFilePath();
final WebMemoryFS result = await webCompilationProxy.initialize( final WebMemoryFS result = await WebTestCompiler(
logger: globals.logger,
fileSystem: globals.fs,
platform: globals.platform,
artifacts: globals.artifacts,
processManager: globals.processManager,
config: globals.config,
).initialize(
projectDirectory: flutterProject.directory, projectDirectory: flutterProject.directory,
testOutputDir: tempBuildDir, testOutputDir: tempBuildDir,
testFiles: testFiles, testFiles: testFiles,
......
...@@ -4,25 +4,44 @@ ...@@ -4,25 +4,44 @@
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart'; import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/config.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/logger.dart';
import '../base/platform.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../bundle.dart'; import '../bundle.dart';
import '../compile.dart'; import '../compile.dart';
import '../dart/language_version.dart'; import '../dart/language_version.dart';
import '../globals.dart' as globals; import '../web/bootstrap.dart';
import '../web/compile.dart';
import '../web/memory_fs.dart'; import '../web/memory_fs.dart';
// TODO(jonahwilliams): this class was kept around to reduce the diff in the migration /// A web compiler for the test runner.
// from build_runner to the frontend_server, but should be removed/refactored to be class WebTestCompiler {
// similar to the test_compiler pattern used for regular flutter tests WebTestCompiler({
class BuildRunnerWebCompilationProxy extends WebCompilationProxy { @required FileSystem fileSystem,
BuildRunnerWebCompilationProxy(); @required Logger logger,
@required Artifacts artifacts,
@required Platform platform,
@required ProcessManager processManager,
@required Config config,
}) : _logger = logger,
_fileSystem = fileSystem,
_artifacts = artifacts,
_platform = platform,
_processManager = processManager,
_config = config;
final Logger _logger;
final FileSystem _fileSystem;
final Artifacts _artifacts;
final Platform _platform;
final ProcessManager _processManager;
final Config _config;
@override
Future<WebMemoryFS> initialize({ Future<WebMemoryFS> initialize({
@required Directory projectDirectory, @required Directory projectDirectory,
@required String testOutputDir, @required String testOutputDir,
...@@ -47,32 +66,43 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy { ...@@ -47,32 +66,43 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy {
} }
} }
final Directory outputDirectory = globals.fs.directory(testOutputDir) final Directory outputDirectory = _fileSystem.directory(testOutputDir)
..createSync(recursive: true); ..createSync(recursive: true);
final List<File> generatedFiles = <File>[]; final List<File> generatedFiles = <File>[];
for (final String testFilePath in testFiles) { for (final String testFilePath in testFiles) {
final List<String> relativeTestSegments = globals.fs.path.split( final List<String> relativeTestSegments = _fileSystem.path.split(
globals.fs.path.relative(testFilePath, from: projectDirectory.childDirectory('test').path)); _fileSystem.path.relative(testFilePath, from: projectDirectory.childDirectory('test').path));
final File generatedFile = globals.fs.file( final File generatedFile = _fileSystem.file(
globals.fs.path.join(outputDirectory.path, '${relativeTestSegments.join('_')}.test.dart')); _fileSystem.path.join(outputDirectory.path, '${relativeTestSegments.join('_')}.test.dart'));
generatedFile generatedFile
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync(_generateEntrypoint(relativeTestSegments.join('/'), testFilePath, languageVersion)); ..writeAsStringSync(generateTestEntrypoint(
relativeTestPath: relativeTestSegments.join('/'),
absolutePath: testFilePath,
languageVersion: languageVersion,
));
generatedFiles.add(generatedFile); generatedFiles.add(generatedFile);
} }
// Generate a fake main file that imports all tests to be executed. This will force // Generate a fake main file that imports all tests to be executed. This will force
// each of them to be compiled. // each of them to be compiled.
final StringBuffer buffer = StringBuffer('// @dart=${languageVersion.major}.${languageVersion.minor}\n'); final StringBuffer buffer = StringBuffer('// @dart=${languageVersion.major}.${languageVersion.minor}\n');
for (final File generatedFile in generatedFiles) { for (final File generatedFile in generatedFiles) {
buffer.writeln('import "${globals.fs.path.basename(generatedFile.path)}";'); buffer.writeln('import "${_fileSystem.path.basename(generatedFile.path)}";');
} }
buffer.writeln('void main() {}'); buffer.writeln('void main() {}');
globals.fs.file(globals.fs.path.join(outputDirectory.path, 'main.dart')) _fileSystem.file(_fileSystem.path.join(outputDirectory.path, 'main.dart'))
..createSync() ..createSync()
..writeAsStringSync(buffer.toString()); ..writeAsStringSync(buffer.toString());
final String cachedKernelPath = getDefaultCachedKernelPath(
trackWidgetCreation: buildInfo.trackWidgetCreation,
dartDefines: buildInfo.dartDefines,
extraFrontEndOptions: extraFrontEndOptions,
fileSystem: _fileSystem,
config: _config,
);
final ResidentCompiler residentCompiler = ResidentCompiler( final ResidentCompiler residentCompiler = ResidentCompiler(
globals.artifacts.getArtifactPath(Artifact.flutterWebSdk, mode: buildInfo.mode), _artifacts.getArtifactPath(Artifact.flutterWebSdk, mode: buildInfo.mode),
buildMode: buildInfo.mode, buildMode: buildInfo.mode,
trackWidgetCreation: buildInfo.trackWidgetCreation, trackWidgetCreation: buildInfo.trackWidgetCreation,
fileSystemRoots: <String>[ fileSystemRoots: <String>[
...@@ -82,24 +112,20 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy { ...@@ -82,24 +112,20 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy {
// Override the filesystem scheme so that the frontend_server can find // Override the filesystem scheme so that the frontend_server can find
// the generated entrypoint code. // the generated entrypoint code.
fileSystemScheme: 'org-dartlang-app', fileSystemScheme: 'org-dartlang-app',
initializeFromDill: getDefaultCachedKernelPath( initializeFromDill: cachedKernelPath,
trackWidgetCreation: buildInfo.trackWidgetCreation,
dartDefines: buildInfo.dartDefines,
extraFrontEndOptions: extraFrontEndOptions,
),
targetModel: TargetModel.dartdevc, targetModel: TargetModel.dartdevc,
extraFrontEndOptions: extraFrontEndOptions, extraFrontEndOptions: extraFrontEndOptions,
platformDill: globals.fs.file(globals.artifacts platformDill: _fileSystem.file(_artifacts
.getArtifactPath(platformDillArtifact, mode: buildInfo.mode)) .getArtifactPath(platformDillArtifact, mode: buildInfo.mode))
.absolute.uri.toString(), .absolute.uri.toString(),
dartDefines: buildInfo.dartDefines, dartDefines: buildInfo.dartDefines,
librariesSpec: globals.fs.file(globals.artifacts librariesSpec: _fileSystem.file(_artifacts
.getArtifactPath(Artifact.flutterWebLibrariesJson)).uri.toString(), .getArtifactPath(Artifact.flutterWebLibrariesJson)).uri.toString(),
packagesPath: buildInfo.packagesPath, packagesPath: buildInfo.packagesPath,
artifacts: globals.artifacts, artifacts: _artifacts,
processManager: globals.processManager, processManager: _processManager,
logger: globals.logger, logger: _logger,
platform: globals.platform, platform: _platform,
); );
final CompilerOutput output = await residentCompiler.recompile( final CompilerOutput output = await residentCompiler.recompile(
...@@ -111,6 +137,10 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy { ...@@ -111,6 +137,10 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy {
if (output.errorCount > 0) { if (output.errorCount > 0) {
throwToolExit('Failed to compile'); throwToolExit('Failed to compile');
} }
// Cache the output kernel file to speed up subsequent compiles.
_fileSystem.file(cachedKernelPath).parent.createSync(recursive: true);
_fileSystem.file(output.outputFilename).copySync(cachedKernelPath);
final File codeFile = outputDirectory.childFile('${output.outputFilename}.sources'); final File codeFile = outputDirectory.childFile('${output.outputFilename}.sources');
final File manifestFile = outputDirectory.childFile('${output.outputFilename}.json'); final File manifestFile = outputDirectory.childFile('${output.outputFilename}.json');
final File sourcemapFile = outputDirectory.childFile('${output.outputFilename}.map'); final File sourcemapFile = outputDirectory.childFile('${output.outputFilename}.map');
...@@ -118,70 +148,4 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy { ...@@ -118,70 +148,4 @@ class BuildRunnerWebCompilationProxy extends WebCompilationProxy {
return WebMemoryFS() return WebMemoryFS()
..write(codeFile, manifestFile, sourcemapFile, metadataFile); ..write(codeFile, manifestFile, sourcemapFile, metadataFile);
} }
String _generateEntrypoint(String relativeTestPath, String absolutePath, LanguageVersion languageVersion) {
return '''
// @dart = ${languageVersion.major}.${languageVersion.minor}
import 'org-dartlang-app:///$relativeTestPath' as test;
import 'dart:ui' as ui;
import 'dart:html';
import 'dart:js';
import 'package:stream_channel/stream_channel.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:test_api/src/backend/stack_trace_formatter.dart'; // ignore: implementation_imports
import 'package:test_api/src/remote_listener.dart'; // ignore: implementation_imports
import 'package:test_api/src/suite_channel_manager.dart'; // ignore: implementation_imports
// Extra initialization for flutter_web.
// The following parameters are hard-coded in Flutter's test embedder. Since
// we don't have an embedder yet this is the lowest-most layer we can put
// this stuff in.
Future<void> main() async {
ui.debugEmulateFlutterTesterEnvironment = true;
await ui.webOnlyInitializePlatform();
webGoldenComparator = DefaultWebGoldenComparator(Uri.parse('$absolutePath'));
(ui.window as dynamic).debugOverrideDevicePixelRatio(3.0);
(ui.window as dynamic).webOnlyDebugPhysicalSizeOverride = const ui.Size(2400, 1800);
internalBootstrapBrowserTest(() => test.main);
}
void internalBootstrapBrowserTest(Function getMain()) {
var channel = serializeSuite(getMain, hidePrints: false);
postMessageChannel().pipe(channel);
}
StreamChannel serializeSuite(Function getMain(), {bool hidePrints = true}) => RemoteListener.start(getMain, hidePrints: hidePrints);
StreamChannel suiteChannel(String name) {
var manager = SuiteChannelManager.current;
if (manager == null) {
throw StateError('suiteChannel() may only be called within a test worker.');
}
return manager.connectOut(name);
}
StreamChannel postMessageChannel() {
var controller = StreamChannelController(sync: true);
window.onMessage.firstWhere((message) {
return message.origin == window.location.origin && message.data == "port";
}).then((message) {
var port = message.ports.first;
var portSubscription = port.onMessage.listen((message) {
controller.local.sink.add(message.data);
});
controller.local.stream.listen((data) {
port.postMessage({"data": data});
}, onDone: () {
port.postMessage({"event": "done"});
portSubscription.cancel();
});
});
context['parent'].callMethod('postMessage', [
JsObject.jsify({"href": window.location.href, "ready": true}),
window.location.origin,
]);
return controller.foreign;
}
''';
}
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
/// The JavaScript bootstrap script to support in-browser hot restart. /// The JavaScript bootstrap script to support in-browser hot restart.
/// ///
...@@ -95,6 +96,75 @@ define("$bootstrapModule", ["$entrypoint", "dart_sdk"], function(app, dart_sdk) ...@@ -95,6 +96,75 @@ define("$bootstrapModule", ["$entrypoint", "dart_sdk"], function(app, dart_sdk)
'''; ''';
} }
/// Generates the bootstrap logic required for a flutter test running in a browser.
///
/// This hard-codes the device pixel ratio to 3.0 and a 2400 x 1800 window size.
String generateTestEntrypoint({
@required String relativeTestPath,
@required String absolutePath,
@required LanguageVersion languageVersion,
}) {
return '''
// @dart = ${languageVersion.major}.${languageVersion.minor}
import 'org-dartlang-app:///$relativeTestPath' as test;
import 'dart:ui' as ui;
import 'dart:html';
import 'dart:js';
import 'package:stream_channel/stream_channel.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:test_api/src/backend/stack_trace_formatter.dart'; // ignore: implementation_imports
import 'package:test_api/src/remote_listener.dart'; // ignore: implementation_imports
import 'package:test_api/src/suite_channel_manager.dart'; // ignore: implementation_imports
Future<void> main() async {
ui.debugEmulateFlutterTesterEnvironment = true;
await ui.webOnlyInitializePlatform();
webGoldenComparator = DefaultWebGoldenComparator(Uri.parse('$absolutePath'));
(ui.window as dynamic).debugOverrideDevicePixelRatio(3.0);
(ui.window as dynamic).webOnlyDebugPhysicalSizeOverride = const ui.Size(2400, 1800);
internalBootstrapBrowserTest(() => test.main);
}
void internalBootstrapBrowserTest(Function getMain()) {
var channel = serializeSuite(getMain, hidePrints: false);
postMessageChannel().pipe(channel);
}
StreamChannel serializeSuite(Function getMain(), {bool hidePrints = true}) => RemoteListener.start(getMain, hidePrints: hidePrints);
StreamChannel suiteChannel(String name) {
var manager = SuiteChannelManager.current;
if (manager == null) {
throw StateError('suiteChannel() may only be called within a test worker.');
}
return manager.connectOut(name);
}
StreamChannel postMessageChannel() {
var controller = StreamChannelController(sync: true);
window.onMessage.firstWhere((message) {
return message.origin == window.location.origin && message.data == "port";
}).then((message) {
var port = message.ports.first;
var portSubscription = port.onMessage.listen((message) {
controller.local.sink.add(message.data);
});
controller.local.stream.listen((data) {
port.postMessage({"data": data});
}, onDone: () {
port.postMessage({"event": "done"});
portSubscription.cancel();
});
});
context['parent'].callMethod('postMessage', [
JsObject.jsify({"href": window.location.href, "ready": true}),
window.location.origin,
]);
return controller.foreign;
}
''';
}
/// Generate the unit test bootstrap file. /// Generate the unit test bootstrap file.
String generateTestBootstrapFileContents(String mainUri, String requireUrl, String mapperUrl) { String generateTestBootstrapFileContents(String mainUri, String requireUrl, String mapperUrl) {
return ''' return '''
......
...@@ -2,11 +2,8 @@ ...@@ -2,11 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:meta/meta.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../build_info.dart'; import '../build_info.dart';
...@@ -19,10 +16,6 @@ import '../globals.dart' as globals; ...@@ -19,10 +16,6 @@ import '../globals.dart' as globals;
import '../platform_plugins.dart'; import '../platform_plugins.dart';
import '../plugins.dart'; import '../plugins.dart';
import '../project.dart'; import '../project.dart';
import '../web/memory_fs.dart';
/// The [WebCompilationProxy] instance.
WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
Future<void> buildWeb( Future<void> buildWeb(
FlutterProject flutterProject, FlutterProject flutterProject,
...@@ -91,23 +84,6 @@ Future<void> buildWeb( ...@@ -91,23 +84,6 @@ Future<void> buildWeb(
globals.flutterUsage.sendTiming('build', 'dart2js', Duration(milliseconds: sw.elapsedMilliseconds)); globals.flutterUsage.sendTiming('build', 'dart2js', Duration(milliseconds: sw.elapsedMilliseconds));
} }
/// An indirection on web compilation.
///
/// Avoids issues with syncing build_runner_core to other repos.
class WebCompilationProxy {
const WebCompilationProxy();
/// Initialize the web compiler from the `projectDirectory`.
Future<WebMemoryFS> initialize({
@required Directory projectDirectory,
@required String testOutputDir,
@required List<String> testFiles,
@required BuildInfo buildInfo,
}) async {
throw UnimplementedError();
}
}
/// Web rendering backend mode. /// Web rendering backend mode.
enum WebRendererMode { enum WebRendererMode {
/// Auto detects which rendering backend to use. /// Auto detects which rendering backend to use.
......
...@@ -14,9 +14,9 @@ import 'package:flutter_tools/src/test/test_compiler.dart'; ...@@ -14,9 +14,9 @@ import 'package:flutter_tools/src/test/test_compiler.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:package_config/package_config_types.dart'; import 'package:package_config/package_config_types.dart';
import '../src/common.dart'; import '../../src/common.dart';
import '../src/context.dart'; import '../../src/context.dart';
import '../src/testbed.dart'; import '../../src/testbed.dart';
final Platform linuxPlatform = FakePlatform( final Platform linuxPlatform = FakePlatform(
operatingSystem: 'linux', operatingSystem: 'linux',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment