This commit is contained in:
thosakwe 2017-06-12 15:26:45 -04:00
parent b09682f515
commit cf0c3c9262
4 changed files with 46 additions and 5 deletions

View file

@ -1,5 +1,5 @@
# hot
[![version 1.0.0-rc.2](https://img.shields.io/badge/pub-1.0.0--rc.2-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink)
[![Pub](https://img.shields.io/pub/v/angel_hot.svg)](https://pub.dartlang.org/packages/angel_hot)
Supports *hot reloading* of Angel servers on file changes. This is faster and
more reliable than merely reactively restarting a `Process`.

View file

@ -9,6 +9,7 @@ import 'src/foo.dart';
main() async {
var hot = new HotReloader(createServer, [
new Directory('src'),
new Directory('src'),
'server.dart',
Uri.parse('package:angel_hot/angel_hot.dart')

View file

@ -16,6 +16,8 @@ typedef FutureOr<Angel> AngelGenerator();
class HotReloader {
VMServiceClient _client;
final StreamController<WatchEvent> _onChange =
new StreamController<WatchEvent>.broadcast();
final List _paths = [];
final StringRenderer _renderer = new StringRenderer(pretty: false);
final Queue<HttpRequest> _requestQueue = new Queue<HttpRequest>();
@ -25,6 +27,10 @@ class HotReloader {
/// Invoked to load a new instance of [Angel] on file changes.
final AngelGenerator generator;
/// Fires whenever a file change. You might consider using this to trigger
/// page reloads in a client.
Stream<WatchEvent> get onChange => _onChange.stream;
/// The maximum amount of time to queue incoming requests for if there is no [server] available.
///
/// If the timeout expires, then the request will be immediately terminated with a `502 Bad Gateway` error.
@ -46,6 +52,10 @@ class HotReloader {
_paths.addAll(paths ?? []);
}
Future close() async {
_onChange.close();
}
Future handleRequest(HttpRequest request) async {
if (_server != null)
return await _server.handleRequest(request);
@ -109,6 +119,10 @@ class HotReloader {
var s = _server = await _generateServer();
while (!_requestQueue.isEmpty)
await s.handleRequest(_requestQueue.removeFirst());
_onChange.stream
.transform(new _Debounce(new Duration(seconds: 1)))
.listen(_handleWatchEvent);
await _listenToFilesystem();
var server = await HttpServer.bind(
@ -130,7 +144,10 @@ class HotReloader {
} else if (path is Uri) {
if (path.scheme == 'package') {
var uri = await Isolate.resolvePackageUri(path);
await _listenToStat(uri.toFilePath());
if (uri != null)
await _listenToStat(uri.toFilePath());
else
await _listenToStat(path.toFilePath());
} else
await _listenToStat(path.toFilePath());
} else {
@ -158,8 +175,11 @@ class HotReloader {
return null;
var watcher = new Watcher(path);
//await watcher.ready;
watcher.events.listen(_handleWatchEvent);
watcher.events.listen(_onChange.add, onError: (e) {
stderr.writeln('Could not listen to file changes at ${path}: $e');
});
print('Listening for file changes at ${path}...');
return true;
} catch (e) {
@ -218,3 +238,23 @@ class HotReloader {
await s.handleRequest(_requestQueue.removeFirst());
}
}
class _Debounce<S> implements StreamTransformer<S, S> {
final Duration _delay;
const _Debounce(this._delay);
Stream<S> bind(Stream<S> stream) {
var initial = new DateTime.now();
var next = initial.subtract(this._delay);
return stream.where((S data) {
var now = new DateTime.now();
if (now.isAfter(next)) {
next = now.add(this._delay);
return true;
} else {
return false;
}
});
}
}

View file

@ -1,6 +1,6 @@
name: angel_hot
description: Supports hot reloading of Angel servers on file changes.
version: 1.0.0-rc.3
version: 1.0.0
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/hot
environment: