8ffc0dddd0
Change-Id: Ibfdf6a7afedaf9e1486624a85e7d04437db13e49 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/494460 Reviewed-by: Nicholas Shahan <nshahan@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com> Auto-Submit: Jonas Jensen <jonasfj@google.com>
186 lines
6.0 KiB
Dart
186 lines
6.0 KiB
Dart
// Copyright 2020 The Dart 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 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:async/async.dart';
|
|
import 'package:frontend_server_client/frontend_server_client.dart';
|
|
import 'package:path/path.dart' as p;
|
|
import 'package:shelf/shelf.dart';
|
|
import 'package:shelf/shelf_io.dart' as shelf_io;
|
|
import 'package:shelf_packages_handler/shelf_packages_handler.dart';
|
|
import 'package:shelf_static/shelf_static.dart';
|
|
|
|
void main(List<String> args) async {
|
|
// Change to package root so relative paths work in CI
|
|
final scriptDir = p.dirname(p.fromUri(Platform.script));
|
|
final packageRoot = p.dirname(scriptDir);
|
|
Directory.current = packageRoot;
|
|
|
|
try {
|
|
watch.start();
|
|
if (args.isNotEmpty) {
|
|
throw ArgumentError('No command line args are supported');
|
|
}
|
|
|
|
_print('compiling the dart sdk');
|
|
final sdkCompileResult = await Process.run(Platform.resolvedExecutable, [
|
|
'compile',
|
|
'js-dev',
|
|
'--multi-root-scheme=org-dartlang-sdk',
|
|
'--modules=amd',
|
|
'--module-name=dart_sdk',
|
|
'-o',
|
|
dartSdkJs,
|
|
p.url.join(sdkDir, sdkKernelPath),
|
|
]);
|
|
if (sdkCompileResult.exitCode != 0) {
|
|
_print(
|
|
'Failed to compile the dart sdk to JS:\n'
|
|
'${sdkCompileResult.stdout}\n'
|
|
'${sdkCompileResult.stderr}',
|
|
);
|
|
exit(sdkCompileResult.exitCode);
|
|
}
|
|
|
|
_print('starting frontend server');
|
|
final packagesPath = findNearestPackageConfigPath();
|
|
final client = await DartDevcFrontendServerClient.start(
|
|
'org-dartlang-root:///$app',
|
|
outputDill,
|
|
// Use an absolute filesystem root so org-dartlang-root:/// URIs resolve reliably in CI
|
|
fileSystemRoots: [Directory.current.path],
|
|
fileSystemScheme: 'org-dartlang-root',
|
|
platformKernel: p.toUri(sdkKernelPath).toString(),
|
|
packagesJson: packagesPath ?? '.dart_tool/package_config.json',
|
|
verbose: true,
|
|
);
|
|
|
|
_print('compiling $app');
|
|
await client.compile([]);
|
|
client.accept();
|
|
_print('done compiling $app');
|
|
|
|
_print('starting shelf server');
|
|
final cascade = Cascade()
|
|
.add(_clientHandler(client))
|
|
.add(createStaticHandler(Directory.current.path))
|
|
.add(createFileHandler(dartSdkJs, url: 'example/app/dart_sdk.js'))
|
|
.add(
|
|
createFileHandler(
|
|
p.join(
|
|
sdkDir,
|
|
'lib',
|
|
'dev_compiler',
|
|
'web',
|
|
'dart_stack_trace_mapper.js',
|
|
),
|
|
url: 'example/app/dart_stack_trace_mapper.js',
|
|
),
|
|
)
|
|
.add(
|
|
createFileHandler(
|
|
p.join(sdkDir, 'lib', 'dev_compiler', 'amd', 'require.js'),
|
|
url: 'example/app/require.js',
|
|
),
|
|
)
|
|
.add(packagesDirHandler());
|
|
final server = await shelf_io.serve(cascade.handler, 'localhost', 8080);
|
|
_print('server ready');
|
|
|
|
// The file we will be editing in the repl
|
|
final appFile = File(app);
|
|
final originalContent = await appFile.readAsString();
|
|
final appLines = const LineSplitter().convert(originalContent);
|
|
final getterText = 'String get message =>';
|
|
final messageLine = appLines.indexWhere(
|
|
(line) => line.startsWith(getterText),
|
|
);
|
|
|
|
final stdinQueue = StreamQueue(
|
|
stdin.transform(utf8.decoder).transform(const LineSplitter()),
|
|
);
|
|
_prompt();
|
|
while (await stdinQueue.hasNext) {
|
|
final newMessage = await stdinQueue.next;
|
|
if (newMessage == 'quit') {
|
|
await server.close();
|
|
await stdinQueue.cancel();
|
|
break;
|
|
} else if (newMessage == 'reset') {
|
|
print('resetting');
|
|
client.reset();
|
|
_print('restoring $app');
|
|
await appFile.writeAsString(originalContent);
|
|
} else {
|
|
_print('editing $app');
|
|
appLines[messageLine] = '$getterText "$newMessage";';
|
|
final newContent = appLines.join('\n');
|
|
await appFile.writeAsString(newContent);
|
|
|
|
_print('recompiling $app with edits');
|
|
final result = await client.compile([
|
|
Uri.parse('org-dartlang-root:///$app'),
|
|
]);
|
|
if (result.errorCount > 0) {
|
|
print('Compile errors: \n${result.compilerOutputLines.join('\n')}');
|
|
await client.reject();
|
|
} else {
|
|
_print('Recompile succeeded for $app');
|
|
client.accept();
|
|
// TODO: support hot restart
|
|
print('reload app to see the new message');
|
|
}
|
|
}
|
|
|
|
_prompt();
|
|
}
|
|
|
|
_print('restoring $app');
|
|
await appFile.writeAsString(originalContent);
|
|
_print('exiting');
|
|
await client.shutdown();
|
|
} finally {
|
|
Directory(p.join('.dart_tool', 'out')).deleteSync(recursive: true);
|
|
}
|
|
}
|
|
|
|
Handler _clientHandler(DartDevcFrontendServerClient client) {
|
|
return (Request request) {
|
|
var path = request.url.path;
|
|
final packagesIndex = path.indexOf('/packages/');
|
|
if (packagesIndex > 0) {
|
|
path = request.url.path.substring(packagesIndex);
|
|
} else {
|
|
path = request.url.path;
|
|
}
|
|
if (!path.startsWith('/')) path = '/$path';
|
|
if (path.endsWith('.dart.js') && path != '/example/app/main.dart.js') {
|
|
path = path.replaceFirst('.dart.js', '.dart.lib.js', path.length - 8);
|
|
}
|
|
final assetBytes = client.assetBytes(path);
|
|
if (assetBytes == null) return Response.notFound('path not found');
|
|
return Response.ok(
|
|
assetBytes,
|
|
headers: {HttpHeaders.contentTypeHeader: 'application/javascript'},
|
|
);
|
|
};
|
|
}
|
|
|
|
void _print(String message) {
|
|
print('${watch.elapsed}: $message');
|
|
}
|
|
|
|
void _prompt() => stdout.write(
|
|
'Enter a new message to print and recompile, or type `quit` to exit:',
|
|
);
|
|
|
|
final app = 'example/app/main.dart';
|
|
final dartSdkJs = p.join('.dart_tool', 'out', 'dart_sdk.js');
|
|
final outputDill = p.join('.dart_tool', 'out', 'example_app.dill');
|
|
final sdkDir = p.dirname(p.dirname(Platform.resolvedExecutable));
|
|
final sdkKernelPath = p.join(sdkDir, 'lib', '_internal', 'ddc_platform.dill');
|
|
final watch = Stopwatch();
|