ssddanbrown/htmldiff
A PHP library for generating a visual diff between two HTML strings. It compares content word by word while preserving HTML structure, outputting marked-up HTML with inserted and deleted content highlighted, useful for showing edits to rich-text content.
Architecture fit. ssddanbrown/htmldiff is a framework-agnostic PHP library, not a Laravel package in the conventional sense: no service provider, no config file, no facade. It exposes a small object API that takes two HTML fragments and returns a display-ready HTML document with insertions/deletions marked up. For a Laravel codebase this is a low-ceremony fit — Composer autoloads it, and if we want container injection we write a thin binding ourselves. The absence of framework coupling is a genuine positive: it will not constrain Laravel upgrades or drag in transitive dependencies.
Integration feasibility. High on the technical axis, low on the confidence axis. Technically it is a composer require and three lines of code. The blockers are organizational and lifecycle-related:
Technical risk. Medium-to-high, concentrated in lifecycle rather than correctness. The algorithm itself is likely adequate for document-revision diffing (prose, markup, CMS content), which is the realistic use case. Risks worth naming: performance and memory on large or deeply nested documents, behavior on malformed/unbalanced HTML (common with user-edited content), multibyte and entity handling, and CSS/attribute-level changes being handled less gracefully than text nodes. MIT licensing removes legal friction and permits forking.
Key questions.
caxy/php-htmldiff or similar) wins on a bake-off, and does either produce output we can trust without sanitization?Stack fit. Good. It slots into the Laravel layer as a pure domain utility: a HtmlDiffService wrapper bound in a service provider, injected into the controller or job that renders version comparisons. Because it has no framework opinions, it can be swapped for an alternative behind the same interface with no changes to call sites. That interface is the single most important design decision here.
Migration path. Given the archived status, do not depend on the upstream package directly in composer.json long-term. The pragmatic path is:
diff(string $old, string $new): string) and never call the library from application code directly. This is the hedge that makes replacement cheap.Compatibility. Verify against the PHP versions in our support matrix (8.1–8.4 typical) before committing; an archived package will not have been tested past whatever PHP was current at the March 2024 release. Composer constraint should be pinned exactly, not ranged, since we control the source.
Sequencing. Spike and fork in the same sprint — do not adopt the upstream package "temporarily" and defer the fork, because that is how archived dependencies become permanent. Sanitization and the wrapper interface land before the first production call site. Any UI work (diff toggle, side-by-side view) comes after the service is proven on real data.
Maintenance. Low routine cost, non-zero ownership cost. The codebase is small and single-purpose; a mid-level PHP developer can read all of it. Realistically we are adopting it, not consuming it — budget a few hours per PHP minor release to confirm it still runs, and a half-day if we ever need to patch it. No dependency tree means no supply-chain churn, which is a real advantage over heavier diff libraries.
Support. Effectively self-support. There is no vendor, no SLA, and the upstream channel has moved to a platform where the project may be dormant. Documentation is whatever the README says. Internal knowledge must be captured deliberately — a short ADR plus a runbook entry — because there is no external source to consult later.
Scaling. CPU- and memory-bound, not I/O-bound. Diffing is the kind of workload that degrades non-linearly with document size, so it belongs in a queued job with a timeout and a size guard, not in a synchronous request. Cache diff results keyed on the pair of revision hashes; revision comparisons are immutable, so cache hit rates should be high. If diffing is a core user-facing feature, set an explicit max-document threshold and degrade to a "changes too large to display" message rather than timing out.
Failure modes.
Ramp-up. Low. A developer unfamiliar with the package can be productive in under a day; the API is small and the wrapper interface means most engineers never touch the library itself. The real onboarding cost is the fork's ownership model — who merges vendor updates, who reviews patches — and that is an organizational decision to make at adoption time, not a technical one to discover later.
Recommendation. Adopt only if HTML diffing is a genuine product requirement, and adopt it as an internally owned fork behind a sanitizing wrapper with a queued, size-capped execution path. If the need is speculative, defer and revisit alongside a bake-off against maintained alternatives.
How can I help you explore Laravel packages today?