Replace @pierre/diffs with custom diff viewer to fix freeze

The @pierre/diffs library was causing the browser to freeze when
comparing certain versions. Implemented a simple line-based diff
that only shows added/removed lines.
This commit is contained in:
cc
2026-04-14 17:17:02 +02:00
parent 47835803e6
commit c13f83e3f7
3 changed files with 69 additions and 1167 deletions
-1143
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -9,7 +9,6 @@
"lint": "eslint"
},
"dependencies": {
"@pierre/diffs": "^1.1.15",
"@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12",
+69 -23
View File
@@ -1,10 +1,7 @@
"use client";
import { useMemo } from "react";
import { FileDiff } from "@pierre/diffs/react";
import { parseDiffFromFile } from "@pierre/diffs";
import { diffPlistKeys, normalizePlist, type PlistDiff } from "@/lib/plist";
import { diffPlistKeys, type PlistDiff } from "@/lib/plist";
interface DiffViewerProps {
oldXml: string;
@@ -13,27 +10,61 @@ interface DiffViewerProps {
newLabel: string;
}
type DiffLine = {
type: "context" | "add" | "remove";
content: string;
oldNum?: number;
newNum?: number;
};
function computeDiff(oldText: string, newText: string): DiffLine[] {
const oldLines = oldText.split("\n");
const newLines = newText.split("\n");
const oldSet = new Set(oldLines);
const newSet = new Set(newLines);
const result: DiffLine[] = [];
let oi = 0,
ni = 0;
while (oi < oldLines.length || ni < newLines.length) {
const oldLine = oldLines[oi];
const newLine = newLines[ni];
if (oi < oldLines.length && ni < newLines.length && oldLine === newLine) {
// Skip context lines - only show changes
oi++;
ni++;
} else if (oi < oldLines.length && !newSet.has(oldLine)) {
result.push({ type: "remove", content: oldLine, oldNum: oi + 1 });
oi++;
} else if (ni < newLines.length && !oldSet.has(newLine)) {
result.push({ type: "add", content: newLine, newNum: ni + 1 });
ni++;
} else {
oi++;
ni++;
}
}
return result;
}
export function DiffViewer({
oldXml,
newXml,
oldLabel,
newLabel,
}: DiffViewerProps) {
const normalizedOld = useMemo(() => normalizePlist(oldXml), [oldXml]);
const normalizedNew = useMemo(() => normalizePlist(newXml), [newXml]);
const keysDiff = useMemo(
() => diffPlistKeys(oldXml, newXml),
[oldXml, newXml],
);
const fileDiff = useMemo(
() =>
parseDiffFromFile(
{ name: `${oldLabel}.plist`, contents: normalizedOld },
{ name: `${newLabel}.plist`, contents: normalizedNew },
),
[normalizedOld, normalizedNew, oldLabel, newLabel],
const diffLines = useMemo(
() => computeDiff(oldXml, newXml),
[oldXml, newXml],
);
const hasChanges =
@@ -52,15 +83,30 @@ export function DiffViewer({
return (
<div className="space-y-4">
<DiffSummary diff={keysDiff} />
<div className="rounded-lg overflow-hidden border">
<FileDiff
fileDiff={fileDiff}
options={{
diffStyle: "split",
expandUnchanged: false,
collapsedContextThreshold: 0,
}}
/>
<div className="rounded-lg overflow-hidden border bg-gray-900 text-gray-100">
<div className="flex justify-between px-4 py-2 bg-gray-800 text-sm font-medium border-b border-gray-700">
<span className="text-red-400">- {oldLabel}</span>
<span className="text-green-400">+ {newLabel}</span>
</div>
<pre className="p-4 overflow-x-auto text-xs font-mono">
{diffLines.map((line, i) => (
<div
key={i}
className={
line.type === "remove"
? "bg-red-900/40 text-red-200"
: line.type === "add"
? "bg-green-900/40 text-green-200"
: ""
}
>
<span className="select-none opacity-50 mr-2">
{line.type === "remove" ? "-" : line.type === "add" ? "+" : " "}
</span>
{line.content}
</div>
))}
</pre>
</div>
</div>
);