Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Fswatch Laravel Package

slick/fswatch

slick/fswatch integrates the fswatch file-system watcher with Laravel, letting you monitor files and automatically trigger commands, tests, or custom callbacks when changes occur. A lightweight way to streamline local development workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require slick/fswatch

First, look at three places:

  1. composer.json — confirm the PHP version constraint and the autoload namespace (Slick's packages use PSR-4, so expect something like Slick\FsWatch\). This tells you the minimum PHP you can run it on and the fully-qualified class to import.
  2. src/ — the library is small; read the main class(es) end to end before wiring it in. You want to know exactly what the "sum" method returns (int? string?), how it recurses, and whether it excludes anything by default (dotfiles, vendor/, etc.).
  3. README.md / tests — the tests are usually the most accurate documentation of edge-case behavior (empty directory, nested dirs, symlinks).

Typical first use case — fingerprint a directory so you can tell whether it changed between two runs:

use Slick\FsWatch\...; // verify exact class from src/

$before = /* sum of directory */ $tree->sum(storage_path('app/imports'));

// ...do work, receive an upload, run a build...

$after = /* sum of directory */ $tree->sum(storage_path('app/imports'));

if ($after !== $before) {
    // contents changed, re-index / re-queue
}

Persist $before somewhere durable (cache, database, a JSON file) so the comparison survives across requests/processes — the library itself is stateless.

Implementation Patterns

Snapshot-and-compare service. Wrap the package in a small domain class so the rest of your app never imports the vendor namespace:

final class DirectoryFingerprint
{
    public function __construct(private string $path) {}

    public function capture(): string
    {
        return (string) $this->sum($this->path); // delegate to fswatch
    }

    public function hasChangedSince(string $fingerprint): bool
    {
        return $this->capture() !== $fingerprint;
    }
}

This gives you a single seam to swap in a stronger implementation (see Gotchas) without touching call sites.

Laravel console command + scheduler. The most natural day-to-day fit is a scheduled Artisan command that polls a directory and dispatches an event when the fingerprint moves:

// app/Console/Commands/CheckInbox.php
public function handle(DirectoryFingerprint $fp): int
{
    $key = 'fswatch:inbox';
    $previous = Cache::get($key);

    if ($previous !== null && $fp->hasChangedSince($previous)) {
        ProcessInbox::dispatch();
    }

    Cache::forever($key, $fp->capture());

    return self::SUCCESS;
}

Register it in routes/console.php or Kernel::schedule() and run every minute. This is the classic "no inotify on shared hosting" pattern.

Baseline on deploy. Capture the fingerprint after each deploy (php artisan deploy:baseline) and compare at runtime. Works well for "did anything get written into this directory that shouldn't have?" — e.g. detecting tampering in an uploads or config directory.

Chained signals. Treat the size sum as a cheap pre-filter, not a verdict:

if ($fp->hasChangedSince($previous)) {
    // expensive confirmation only when the cheap check trips
    $hash = $this->hashTree($path);
}

Integration tips. Because the library is stateless and side-effect free, it composes cleanly with queues and commands — you don’t need to boot anything. Keep the directory argument explicit (config value, not a hardcoded path) so tests can point at a fixture directory.

Gotchas and Tips

It only sums sizes — collisions are real. Replace a file with a different file of the same byte count and the sum is unchanged. Rename or reorder files: unchanged. Edit a file without changing length: unchanged. This is a change hint, not a correctness guarantee. For anything security- or money-related, pair it with mtime or a content hash.

Large trees are O(n) stat calls every check. On a directory with 100k files this will be slower than you expect, and doing it every minute from the scheduler compounds. Scope the watched path tightly, or cache per-subdirectory sums and only re-scan changed subtrees.

Check recursion and exclusion behavior in src/. Whether it descends into subdirectories, follows symlinks, or skips dotfiles is the single most important thing to confirm — symlink loops will hang a naive recursive counter. If exclusions aren't configurable (likely, given the library's size), you'll need to point it at subdirectories individually or subclass it.

32-bit integer overflow. On 32-bit PHP builds PHP_INT_MAX is ~2.1 GB; a directory total above that silently wraps or becomes a float, and comparisons get flaky. Verify the return type and cast; on 64-bit this is a non-issue.

License is NOASSERTION. That means GitHub couldn't identify a recognized license from the repo, not that it's unlicensed. Open the LICENSE file before shipping this in anything commercial — it may be BSD-3-Clause (typical for Slick) or something custom. This is a blocker to resolve before adoption, not after.

Zero adoption signal. One star, no dependents, last release May 2024. Treat it as a reference implementation rather than infrastructure. Honestly, the entire library is roughly:

$total = 0;
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS)) as $f) {
    $total += $f->getSize();
}

If the license or maintenance story doesn't fit, vendoring 15 lines (or using Symfony\Finder + array_sum) removes the dependency risk entirely and lets you add mtime/hash signals for free.

Debugging drift. When the fingerprint flaps unexpectedly, dump the per-entry sizes and diff two snapshots to isolate the culprit — a log file growing every minute is the usual suspect, and pointing the watcher at a directory containing logs will make it fire constantly.

Extension points. With a library this thin, extension means subclassing and overriding the traversal/summing method rather than configuring it. Keep that override in one place (your wrapper service) so an upstream change or a swap to your own implementation doesn't ripple through the codebase.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons