
* Use source list from the compiler to track invalidated files. * Revert accidental change * Fix first-time-seen-the-file logic * Fix/simplify invalidate logic now that we can rely on compiler to let us know what is the cut-off point for invalidation. * Update devfs mock to accommodate for new fields * Fix deleted files case * Analyzer found missing final
206 lines
5.7 KiB
Dart
206 lines
5.7 KiB
Dart
// Copyright 2019 The Chromium 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 '../application_package.dart';
|
|
import '../base/context.dart';
|
|
import '../base/file_system.dart';
|
|
import '../base/io.dart';
|
|
import '../base/logger.dart';
|
|
import '../base/platform.dart';
|
|
import '../base/process_manager.dart';
|
|
import '../build_info.dart';
|
|
import '../device.dart';
|
|
import '../globals.dart';
|
|
import '../project.dart';
|
|
import '../web/compile.dart';
|
|
|
|
ChromeLauncher get chromeLauncher => context[ChromeLauncher];
|
|
|
|
/// Only launch or display web devices if `FLUTTER_WEB`
|
|
/// environment variable is set to true.
|
|
bool get flutterWebEnabled {
|
|
_flutterWebEnabled = platform.environment['FLUTTER_WEB']?.toLowerCase() == 'true';
|
|
return _flutterWebEnabled;
|
|
}
|
|
bool _flutterWebEnabled;
|
|
|
|
|
|
class WebApplicationPackage extends ApplicationPackage {
|
|
WebApplicationPackage(this._flutterProject) : super(id: _flutterProject.manifest.appName);
|
|
|
|
final FlutterProject _flutterProject;
|
|
|
|
@override
|
|
String get name => _flutterProject.manifest.appName;
|
|
|
|
/// The location of the web source assets.
|
|
Directory get webSourcePath => _flutterProject.directory.childDirectory('web');
|
|
}
|
|
|
|
|
|
class WebDevice extends Device {
|
|
WebDevice() : super('web');
|
|
|
|
HttpServer _server;
|
|
WebApplicationPackage _package;
|
|
|
|
@override
|
|
bool get supportsHotReload => false;
|
|
|
|
@override
|
|
bool get supportsHotRestart => false;
|
|
|
|
@override
|
|
bool get supportsStartPaused => true;
|
|
|
|
@override
|
|
bool get supportsStopApp => true;
|
|
|
|
@override
|
|
bool get supportsScreenshot => false;
|
|
|
|
@override
|
|
void clearLogs() { }
|
|
|
|
@override
|
|
DeviceLogReader getLogReader({ApplicationPackage app}) {
|
|
return NoOpDeviceLogReader(app.name);
|
|
}
|
|
|
|
@override
|
|
Future<bool> installApp(ApplicationPackage app) async => true;
|
|
|
|
@override
|
|
Future<bool> isAppInstalled(ApplicationPackage app) async => true;
|
|
|
|
@override
|
|
Future<bool> isLatestBuildInstalled(ApplicationPackage app) async => true;
|
|
|
|
@override
|
|
Future<bool> get isLocalEmulator async => false;
|
|
|
|
@override
|
|
bool isSupported() => flutterWebEnabled;
|
|
|
|
@override
|
|
String get name => 'web';
|
|
|
|
@override
|
|
DevicePortForwarder get portForwarder => const NoOpDevicePortForwarder();
|
|
|
|
@override
|
|
Future<String> get sdkNameAndVersion async => 'web';
|
|
|
|
@override
|
|
Future<LaunchResult> startApp(
|
|
covariant WebApplicationPackage package, {
|
|
String mainPath,
|
|
String route,
|
|
DebuggingOptions debuggingOptions,
|
|
Map<String, Object> platformArgs,
|
|
bool prebuiltApplication = false,
|
|
bool usesTerminalUi = true,
|
|
bool ipv6 = false,
|
|
}) async {
|
|
final Status status = logger.startProgress('Compiling ${package.name} to JavaScript...', timeout: null);
|
|
final int result = await webCompiler.compile(target: mainPath, minify: false, enabledAssertions: true);
|
|
status.stop();
|
|
if (result != 0) {
|
|
printError('Failed to compile ${package.name} to JavaScript');
|
|
return LaunchResult.failed();
|
|
}
|
|
_package = package;
|
|
_server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
|
_server.listen(_basicAssetServer);
|
|
printStatus('Serving assets from http:localhost:${_server.port}');
|
|
await chromeLauncher.launch('http:localhost:${_server.port}');
|
|
return LaunchResult.succeeded(observatoryUri: null);
|
|
}
|
|
|
|
// Note: we don't currently have a way to track which chrome processes
|
|
// belong to the flutter tool, so we'll err on the side of caution by
|
|
// keeping these open.
|
|
@override
|
|
Future<bool> stopApp(ApplicationPackage app) async {
|
|
await _server?.close();
|
|
_server = null;
|
|
return true;
|
|
}
|
|
|
|
@override
|
|
Future<TargetPlatform> get targetPlatform async => TargetPlatform.web;
|
|
|
|
@override
|
|
Future<bool> uninstallApp(ApplicationPackage app) async => true;
|
|
|
|
Future<void> _basicAssetServer(HttpRequest request) async {
|
|
if (request.method != 'GET') {
|
|
request.response.statusCode = HttpStatus.forbidden;
|
|
await request.response.close();
|
|
return;
|
|
}
|
|
// Resolve all get requests to the build/web/asset directory.
|
|
final Uri uri = request.uri;
|
|
File file;
|
|
String contentType;
|
|
if (uri.path == '/') {
|
|
file = _package.webSourcePath.childFile('index.html');
|
|
contentType = 'text/html';
|
|
} else if (uri.path == '/main.dart.js') {
|
|
file = fs.file(fs.path.join(getWebBuildDirectory(), 'main.dart.js'));
|
|
contentType = 'text/javascript';
|
|
} else {
|
|
file = fs.file(fs.path.join(getAssetBuildDirectory(), uri.path));
|
|
}
|
|
if (!file.existsSync()) {
|
|
request.response.statusCode = HttpStatus.notFound;
|
|
await request.response.close();
|
|
return;
|
|
}
|
|
request.response.statusCode = HttpStatus.ok;
|
|
if (contentType != null) {
|
|
request.response.headers.add(HttpHeaders.contentTypeHeader, contentType);
|
|
}
|
|
await request.response.addStream(file.openRead());
|
|
await request.response.close();
|
|
}
|
|
}
|
|
|
|
class WebDevices extends PollingDeviceDiscovery {
|
|
WebDevices() : super('web');
|
|
|
|
final WebDevice _webDevice = WebDevice();
|
|
|
|
@override
|
|
bool get canListAnything => flutterWebEnabled;
|
|
|
|
@override
|
|
Future<List<Device>> pollingGetDevices() async {
|
|
return <Device>[
|
|
_webDevice,
|
|
];
|
|
}
|
|
|
|
@override
|
|
bool get supportsPlatform => flutterWebEnabled;
|
|
|
|
}
|
|
|
|
// Responsible for launching chrome with devtools configured.
|
|
class ChromeLauncher {
|
|
const ChromeLauncher();
|
|
|
|
static const String _kMacosLocation = '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome';
|
|
|
|
Future<void> launch(String host) async {
|
|
if (platform.isMacOS) {
|
|
await processManager.start(<String>[
|
|
_kMacosLocation,
|
|
host,
|
|
]);
|
|
}
|
|
throw UnsupportedError('$platform is not supported');
|
|
}
|
|
}
|