Skip to content

Commit

Permalink
Lazy load @parcel/watcher and fallback to chokidar (#2414)
Browse files Browse the repository at this point in the history
Co-authored-by: Natalie Weizenbaum <[email protected]>
  • Loading branch information
ntkme and nex3 authored Nov 1, 2024
1 parent a9254df commit 39d3726
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 64 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## 1.80.6-dev
## 1.80.6

* No user-visible changes.
### Command-Line Interface

* Make `@parcel/watcher` an optional dependency so this can still be installed
on operating systems where it's unavailable.

## 1.80.5

Expand Down
50 changes: 25 additions & 25 deletions lib/src/io/js.dart
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,31 @@ Future<Stream<WatchEvent>> watchDir(String path, {bool poll = false}) async {
// Don't assign the controller until after the ready event fires. Otherwise,
// Chokidar will give us a bunch of add events for files that already exist.
StreamController<WatchEvent>? controller;
if (poll) {
var watcher = chokidar.watch(path, ChokidarOptions(usePolling: true));
if (parcelWatcher case var parcel? when !poll) {
var subscription = await parcel.subscribe(path,
(Object? error, List<ParcelWatcherEvent> events) {
if (error != null) {
controller?.addError(error);
} else {
for (var event in events) {
switch (event.type) {
case 'create':
controller?.add(WatchEvent(ChangeType.ADD, event.path));
case 'update':
controller?.add(WatchEvent(ChangeType.MODIFY, event.path));
case 'delete':
controller?.add(WatchEvent(ChangeType.REMOVE, event.path));
}
}
}
});

return (controller = StreamController<WatchEvent>(onCancel: () {
subscription.unsubscribe();
}))
.stream;
} else {
var watcher = chokidar.watch(path, ChokidarOptions(usePolling: poll));
watcher
..on(
'add',
Expand Down Expand Up @@ -286,28 +309,5 @@ Future<Stream<WatchEvent>> watchDir(String path, {bool poll = false}) async {
}));

return completer.future;
} else {
var subscription = await ParcelWatcher.subscribeFuture(path,
(Object? error, List<ParcelWatcherEvent> events) {
if (error != null) {
controller?.addError(error);
} else {
for (var event in events) {
switch (event.type) {
case 'create':
controller?.add(WatchEvent(ChangeType.ADD, event.path));
case 'update':
controller?.add(WatchEvent(ChangeType.MODIFY, event.path));
case 'delete':
controller?.add(WatchEvent(ChangeType.REMOVE, event.path));
}
}
}
});

return (controller = StreamController<WatchEvent>(onCancel: () {
subscription.unsubscribe();
}))
.stream;
}
}
51 changes: 28 additions & 23 deletions lib/src/js/parcel_watcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,48 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import 'package:js/js.dart';
import 'package:node_interop/js.dart';
import 'package:node_interop/util.dart';
import 'dart:js_interop';

@JS()
class ParcelWatcherSubscription {
extension type ParcelWatcherSubscription(JSObject _) implements JSObject {
external void unsubscribe();
}

@JS()
class ParcelWatcherEvent {
extension type ParcelWatcherEvent(JSObject _) implements JSObject {
external String get type;
external String get path;
}

/// The @parcel/watcher module.
///
/// See [the docs on npm](https://www.npmjs.com/package/@parcel/watcher).
@JS('parcel_watcher')
class ParcelWatcher {
external static Promise subscribe(String path, Function callback);
static Future<ParcelWatcherSubscription> subscribeFuture(String path,
@JS()
extension type ParcelWatcher(JSObject _) implements JSObject {
@JS('subscribe')
external JSPromise<ParcelWatcherSubscription> _subscribe(
String path, JSFunction callback);
Future<ParcelWatcherSubscription> subscribe(String path,
void Function(Object? error, List<ParcelWatcherEvent>) callback) =>
promiseToFuture(
subscribe(path, allowInterop((Object? error, List<dynamic> events) {
callback(error, events.cast<ParcelWatcherEvent>());
})));
_subscribe(
path,
(JSObject? error, JSArray<ParcelWatcherEvent> events) {
callback(error, events.toDart);
}.toJS)
.toDart;

external static Promise getEventsSince(String path, String snapshotPath);
static Future<List<ParcelWatcherEvent>> getEventsSinceFuture(
String path, String snapshotPath) async {
List<dynamic> events =
await promiseToFuture(getEventsSince(path, snapshotPath));
return events.cast<ParcelWatcherEvent>();
}
@JS('getEventsSince')
external JSPromise<JSArray<ParcelWatcherEvent>> _getEventsSince(
String path, String snapshotPath);
Future<List<ParcelWatcherEvent>> getEventsSince(
String path, String snapshotPath) async =>
(await _getEventsSince(path, snapshotPath).toDart).toDart;

external static Promise writeSnapshot(String path, String snapshotPath);
static Future<void> writeSnapshotFuture(String path, String snapshotPath) =>
promiseToFuture(writeSnapshot(path, snapshotPath));
@JS('writeSnapshot')
external JSPromise<JSAny> _writeSnapshot(String path, String snapshotPath);
Future<void> writeSnapshot(String path, String snapshotPath) =>
_writeSnapshot(path, snapshotPath).toDart;
}

@JS('parcel_watcher')
external ParcelWatcher? get parcelWatcher;
2 changes: 1 addition & 1 deletion lib/src/parse/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ class Parser {
var span = scanner.spanFrom(state);
return _interpolationMap == null
? span
: LazyFileSpan(() => _interpolationMap!.mapSpan(span));
: LazyFileSpan(() => _interpolationMap.mapSpan(span));
}

/// Throws an error associated with [span].
Expand Down
2 changes: 1 addition & 1 deletion lib/src/visitor/async_evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1812,7 +1812,7 @@ final class _EvaluateVisitor
if (result != null) {
isDependency = _inDependency;
} else {
result = await _nodeImporter!.loadAsync(originalUrl, previous, forImport);
result = await _nodeImporter.loadAsync(originalUrl, previous, forImport);
if (result == null) return null;
isDependency = true;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/src/visitor/evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// DO NOT EDIT. This file was generated from async_evaluate.dart.
// See tool/grind/synchronize.dart for details.
//
// Checksum: 396c8f169d95c601598b8c3be1f4b948ca22effa
// Checksum: 3986f5db33dd220dcd971a39e8587ca4e52d9a3f
//
// ignore_for_file: unused_import

Expand Down Expand Up @@ -1808,7 +1808,7 @@ final class _EvaluateVisitor
if (result != null) {
isDependency = _inDependency;
} else {
result = _nodeImporter!.load(originalUrl, previous, forImport);
result = _nodeImporter.load(originalUrl, previous, forImport);
if (result == null) return null;
isDependency = true;
}
Expand Down
4 changes: 3 additions & 1 deletion package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
"node": ">=14.0.0"
},
"dependencies": {
"@parcel/watcher": "^2.4.1",
"chokidar": "^4.0.0",
"immutable": "^4.0.0",
"source-map-js": ">=0.6.2 <2.0.0"
},
"optionalDependencies": {
"@parcel/watcher": "^2.4.1"
},
"keywords": [
"style",
"scss",
Expand Down
2 changes: 1 addition & 1 deletion pkg/sass-parser/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 0.4.3-dev
## 0.4.3

* Add support for parsing the `@while` rule.

Expand Down
2 changes: 1 addition & 1 deletion pkg/sass-parser/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sass-parser",
"version": "0.4.3-dev",
"version": "0.4.3",
"description": "A PostCSS-compatible wrapper of the official Sass parser",
"repository": "sass/sass",
"author": "Google Inc.",
Expand Down
2 changes: 1 addition & 1 deletion pkg/sass_api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 14.1.2-dev
## 14.1.2

* No user-visible changes.

Expand Down
4 changes: 2 additions & 2 deletions pkg/sass_api/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ name: sass_api
# Note: Every time we add a new Sass AST node, we need to bump the *major*
# version because it's a breaking change for anyone who's implementing the
# visitor interface(s).
version: 14.1.2-dev
version: 14.1.2
description: Additional APIs for Dart Sass.
homepage: https://github.com/sass/dart-sass

environment:
sdk: ">=3.0.0 <4.0.0"
sdk: ">=3.3.0 <4.0.0"

dependencies:
sass: 1.80.6
Expand Down
6 changes: 3 additions & 3 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: sass
version: 1.80.6-dev
version: 1.80.6
description: A Sass implementation in Dart.
homepage: https://github.com/sass/dart-sass

Expand All @@ -8,13 +8,13 @@ executables:
sass: sass

environment:
sdk: ">=3.0.0 <4.0.0"
sdk: ">=3.3.0 <4.0.0"

dependencies:
args: ^2.0.0
async: ^2.5.0
charcode: ^1.2.0
cli_pkg: ^2.8.0
cli_pkg: ^2.11.0
cli_repl: ^0.2.1
collection: ^1.16.0
http: ^1.1.0
Expand Down
3 changes: 2 additions & 1 deletion tool/grind.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ void main(List<String> args) {
pkg.homebrewFormula.value = "Formula/sass.rb";
pkg.homebrewEditFormula.value = _updateHomebrewLanguageRevision;
pkg.jsRequires.value = [
pkg.JSRequire("@parcel/watcher", target: pkg.JSRequireTarget.cli),
pkg.JSRequire("@parcel/watcher",
target: pkg.JSRequireTarget.cli, lazy: true, optional: true),
pkg.JSRequire("immutable", target: pkg.JSRequireTarget.all),
pkg.JSRequire("chokidar", target: pkg.JSRequireTarget.cli),
pkg.JSRequire("readline", target: pkg.JSRequireTarget.cli),
Expand Down

0 comments on commit 39d3726

Please sign in to comment.