crodas/watch-files
A lightweight PHP file watcher that monitors files and directories for changes, firing callbacks when they are created, modified, or deleted. Useful for auto-rebuilding assets, clearing caches, or rerunning tests during development without relying on external tools.
Architecture fit. The package's core proposition — stateless file/directory change detection — is actually well-aligned with PHP's share-nothing execution model. Unlike inotify-based watchers, which require a long-lived daemon holding watch descriptors, a stateless snapshot/diff approach can be invoked from a scheduled command, a queue job, or a one-shot CLI call. That is the right shape for Laravel, where the request/console lifecycle is short and persistent processes are the exception (Horizon, Octane, Supervisor-managed workers). However, the package is a generic PHP library, not a Laravel package: there is no service provider, facade, config file, or publishable assets. Architectural fit is therefore "plausible primitive, not a solution."
Integration feasibility. Composer-installable and small surface area, but adoption signals are near-zero: 9 stars, 0 dependents, no evidence of production use. There is no visible test suite, CI badge, or release cadence to inspect, and no Laravel version constraints to validate against. Integration would require writing an adapter layer, a config surface, and our own tests — meaning we absorb the integration cost of a first-party package without getting first-party support.
Technical risk. High, concentrated in four areas:
each()/dynamic property removals) becomes our problem.vendor/, node_modules/, storage/) this is expensive and needs explicit exclusion.Key questions.
ext-inotify, polling, or snapshot hashing — and is the "stateless" claim about no daemon, no in-memory state, or both?Stack fit. Marginal as-is. It is a PHP primitive that would sit beneath a Laravel service boundary. The correct pattern is to define a narrow internal contract — e.g. FileChangeDetector::changesSince(Snapshot): ChangeSet — implement it once with this package, and keep at least one alternative implementation behind the same interface. Candidate alternatives: a Symfony Finder + xxh3/md5 manifest diff we control outright, spatie/file-watcher for local dev use, or an OS-level inotifywait/fswatch sidecar where a daemon is acceptable.
Migration path. Do not rewrite existing logic around this package. Introduce the interface first, back it with a naive in-house implementation to prove the contract, then evaluate crodas/watch-files as a swap-in behind the same interface. This keeps the decision reversible at near-zero cost and caps the blast radius if the package is abandoned mid-flight.
Compatibility. Validate against the PHP versions and Laravel LTS releases we actually run, in a throwaway branch: install, run the full test matrix, and explicitly check for deprecation notices under E_ALL. Inspect composer.json for open-ended constraints and transitive dependencies. Confirm behavior on our filesystem types — network mounts (NFS/EFS) frequently break both mtime semantics and inotify, so the storage backend matters as much as the code.
Sequencing.
crodas/watch-files behind the interface in a non-critical path — local dev tooling, cache warming, or an ingestion staging directory.Maintenance. Assume we own the code from day one. With zero dependents and minimal community, there is no upstream to lean on for bug fixes or PHP version bumps. Budget for a fork under an internal namespace with our own CI, changelog, and deprecation policy. This is a reasonable cost for ~200 lines of file-scanning logic; it is not reasonable if the package turns out to have a large or opaque internals surface.
Support. No vendor, no SLA, no security advisory channel. Any CVE or PHP-incompatibility event is discovered by us. Mitigation: keep the dependency behind an interface so removal is a one-file change, and add a dependency-review step to the standard intake process.
Scaling. Cost scales with tree size per invocation, not with change volume — the opposite of what most teams expect. Practical controls: restrict scans to explicit allowlisted subtrees; hard-exclude vendor/, node_modules/, storage/framework, and log directories; tune poll interval against acceptable detection latency; prefer manifest hashing only on directories where mtime is unreliable; and never run the scan inside a request path. On a large monorepo this can be seconds per tick, which drives the scheduling design.
Failure modes.
Ramp-up. Low conceptual overhead — the API is small and the file-watching mental model is familiar to most engineers. The real ramp-up cost is in operational understanding: why mtime is not a reliable signal, how atomic renames appear to a scanner, and why the scan cost profile differs from inotify. Plan for roughly a day of team onboarding plus the shadow-evaluation period before anyone trusts the output.
How can I help you explore Laravel packages today?