Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ Simon Binder (simolus3) - Contributor
Mahdi Khodadadifard (xclud) - Contributor
Jamiu Okanlawon (developerjamiu) - Contributor
Harish Anbalagan (harishwarrior) - Contributor
Lewin Pauli (lewinpauli) - Contributor
7 changes: 7 additions & 0 deletions packages/jaspr/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## Unreleased patch

- Fixed `jaspr serve` pinning a CPU core at 100% when the project has no `bin/` or `test/`
directory. The hot reload server used `debounceInterval: Duration.zero`, which is also used
as the polling delay for directory watchers that fall back to polling (e.g. for paths that
don't exist), turning it into a tight busy loop. (#816)

## 0.23.1

- Fixed expression compilation when debugging a client-side application with an AOT installed CLI.
Expand Down
18 changes: 14 additions & 4 deletions packages/jaspr_cli/lib/src/commands/dev_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,13 @@ abstract class DevCommand extends BaseCommand with ProxyHelper, FlutterHelper {

if (useHotReload) {
final import = entryPoint.replaceFirst('lib', 'package:${project.requirePubspecYaml['name']}');
serverTarget.writeAsStringSync(serverEntrypoint(import));
// hotreloader watches 'bin' and 'test' by default. If they don't exist in this
// project, exclude them so it doesn't fall back to a polling watcher for them.
final excludedPaths = [
for (final dir in ['bin', 'test'])
if (!Directory(dir).existsSync()) dir,
];
serverTarget.writeAsStringSync(serverEntrypoint(import, excludedPaths));

args.add(serverTarget.path);
} else {
Expand Down Expand Up @@ -450,18 +456,22 @@ abstract class DevCommand extends BaseCommand with ProxyHelper, FlutterHelper {
}
}

String serverEntrypoint(String import) =>
String serverEntrypoint(String import, List<String> excludedPaths) =>
'''
import '$import' as m;
import 'package:hotreloader/hotreloader.dart';

void main(List<String> args) async {
final mainFunc = m.main as dynamic;
final mainCall = mainFunc is dynamic Function(List<String>) ? () => mainFunc(args) : () => mainFunc();

try {
await HotReloader.create(
debounceInterval: Duration.zero,
// A non-zero interval is required: hotreloader falls back to polling watchers
// for paths that don't exist (e.g. unused bin/ or test/ dirs), and a zero
// pollingDelay there causes a busy loop pinning a CPU core (see #816).
debounceInterval: Duration(milliseconds: 200),
excludedPaths: {${excludedPaths.map((e) => "'$e'").join(', ')}},
onAfterReload: (ctx) => mainCall(),
);
print('[INFO] Server hot reload is enabled.');
Expand Down
Loading