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

Text Diff Laravel Package

mistralys/text-diff

A PHP library for comparing text and rendering differences. It computes diffs between strings or files and presents changes in HTML or plain text via a flexible API, making it easy to add clear diff views to PHP applications.

Deep Wiki
Context7

Getting Started

Install it as a normal Composer dependency:

composer require mistralys/text-diff

Start by reading the package README and vendor/mistralys/text-diff/src/ to confirm the current entry-point and renderer names. This is a small, framework-agnostic utility package, so there is no Laravel service provider, config file, migration, or published assets to expect.

The first useful Laravel use case is an admin/audit “what changed?” view: compare two saved versions of a model field, such as body, description, terms, or a CMS page, and render the result as highlighted HTML.

Keep the package behind a small application service so the rest of Laravel does not depend directly on its API:

namespace App\Services;

use Mistralys\TextDiff\TextDiff;

final class TextDiffService
{
    public function toHtml(?string $before, ?string $after): string
    {
        $before = $this->normalize($before ?? '');
        $after = $this->normalize($after ?? '');

        if ($before === $after) {
            return '';
        }

        // Keep package-specific calls isolated here.
        return TextDiff::create($before, $after)->renderHTML();
    }

    private function normalize(string $text): string
    {
        return str_replace(["\r\n", "\r"], "\n", $text);
    }
}

Then use it from a controller or view model:

public function show(Revision $revision, TextDiffService $diff)
{
    return view('revisions.show', [
        'diffHtml' => $diff->toHtml($revision->before, $revision->after),
    ]);
}
<div class="text-diff">
    {!! $diffHtml !!}
</div>

Only use unescaped Blade output if you have verified that the package escapes the source text correctly. If user-authored HTML can enter the diff, sanitize the result or render plain text instead.

Implementation Patterns

Store source snapshots, render diffs on demand. Persist the before/after text, not the generated HTML. Render the diff when the audit page is opened so renderer/CSS changes do not require data migrations.

Use it for revision history and audit logs. A common model is a revisions table with revisionable_type, revisionable_id, before, after, user_id, and timestamps. The package handles the presentation; your app handles authorization, retention, and audit metadata.

Add a Blade component for repeated use. Wrap the service in a component so views stay clean:

<x-text-diff :before="$revision->before" :after="$revision->after" />

The component can own the wrapper markup, CSS class names, empty-state message, and “no changes” behavior.

Cache expensive diffs. Large documents can be slow to diff. Cache by revision ID plus a hash/version of the renderer options:

$html = Cache::remember(
    "revision-diff:{$revision->id}:v1",
    now()->addHour(),
    fn () => $diff->toHtml($revision->before, $revision->after)
);

Include the package version or renderer settings in the cache key if output can change after upgrades.

Queue large comparisons. For long legal text, documentation, or imported content, generate the diff in a job and store the HTML in cache/object storage. The request should not block on a very large diff.

Normalize before diffing. Decide explicitly whether whitespace, case, tabs, and line endings matter. Normalize CRLF/CR to LF before passing text to the package. If your product treats whitespace-only changes as noise, strip or collapse it before diffing.

Use plain text or structured output where HTML is not appropriate. HTML highlighting is ideal for admin screens. For APIs, emails, logs, or exports, prefer a plain-text renderer if the package exposes one, or return a small JSON payload with the before/after text and a rendered HTML field only for UI consumers.

Test with realistic fixtures. Add feature tests for empty strings, identical content, large paragraphs, Unicode, CRLF input, and HTML-like user content. Snapshot the generated HTML only for stable, trusted fixtures.

Gotchas and Tips

  • Treat HTML output as security-sensitive. Verify whether the renderer escapes user input. If not, run the result through HTMLPurifier or render escaped text. Never assume “diff HTML” is safe just because it came from a library.
  • Do not double-escape. If the package already escapes source text, escaping again will produce visible &lt; noise. If it does not, escaping only the raw input before diffing can break highlighting. Test with <script> and <b> content.
  • Scope the CSS. The package’s HTML classes may be generic. Wrap output in a .text-diff container and scope styles to avoid collisions with your admin theme.
  • Watch memory and time on large inputs. Diff algorithms can degrade badly on huge documents. Set a maximum character/line count, truncate with a clear message, or move the work to a queue.
  • Normalize line endings and trailing whitespace. CRLF/LF mismatches and trailing spaces create noisy diffs. Decide whether those should be visible or ignored.
  • Handle empty and identical values explicitly. Return a friendly “No changes” state rather than an empty highlighted block.
  • Be careful with multibyte text. Ensure inputs are valid UTF-8 and avoid byte-based truncation that can split characters.
  • Pin the Composer version. This is a small utility package; pin a known-good version and upgrade deliberately, especially if you cache rendered HTML or snapshot-test output.
  • Keep the wrapper as the extension point. If you need custom renderers, CSS, truncation, or plain-text output, add it in TextDiffService or a Blade component rather than scattering package calls across controllers.
  • Read the source when behavior is unclear. With a small package, the fastest debugging path is usually the renderer class and its tests, not framework-level documentation.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package