praneshr / react-diff-viewer

A simple and beautiful text diff viewer component made with Diff and React.
https://praneshravi.in/react-diff-viewer/
MIT License
1.39k stars 261 forks source link

big data cause Page jammed #144

Open vincent-tian opened 2 years ago

vincent-tian commented 2 years ago

use react-diff-viewer data size :1m

LeePiaPia commented 2 years ago

1.open node_modules/react-diff-viewer/lib/compute-lines.js 2.find the function computeLineInformation

  1. replace my functionvar computeLineInformation = function (oldString, newString, disableWordDiff, compareMethod, linesOffset) { if (disableWordDiff === void 0) { disableWordDiff = false; } if (compareMethod === void 0) { compareMethod = DiffMethod.CHARS; } if (linesOffset === void 0) { linesOffset = 0; } var diffArray = [] var type = 3 var num = 100 if (oldString.length > 1000 || newString.length > 1000) { type = 1 } if (type == 1) { var oldarr = getArr(oldString, { newlineIsToken: true, ignoreWhitespace: false, ignoreCase: false, }) var newarr = getArr(newString, { newlineIsToken: true, ignoreWhitespace: false, ignoreCase: false, }) var oa = oldarr.splice(0, num) var na = newarr.splice(0, num) while (oa.length > 0 || na.length > 0) { var o = oa.join('') var n = na.join('') diffArray = diffArray.concat(diff.diffLines(o, n, { newlineIsToken: true, ignoreWhitespace: false, ignoreCase: false, })); oa = oldarr.splice(0, num) na = newarr.splice(0, num) } } else if (type == 2) { var oldarr = oldString.split('\n') var newarr = newString.split('\n') var oa = oldarr.splice(0, num) var na = newarr.splice(0, num) while (oa.length > 0 || na.length > 0) { var o = '' var n = '' for (var i = 0; i < oa.length; i++) { o += '\n' + oa[i] } for (var i = 0; i < na.length; i++) { n += '\n' + na[i] } diffArray = diffArray.concat(diff.diffLines(o, n, { newlineIsToken: true, ignoreWhitespace: false, ignoreCase: false, })); oa = oldarr.splice(0, num) na = newarr.splice(0, num) } } else { diffArray = diffArray.concat(diff.diffLines(oldString, newString, { newlineIsToken: true, ignoreWhitespace: false, ignoreCase: false, })); } var rightLineNumber = linesOffset; var leftLineNumber = linesOffset; var lineInformation = []; var counter = 0; var diffLines = []; var ignoreDiffIndexes = []; var getLineInformation = function (value, diffIndex, added, removed, evaluateOnlyFirstLine) { var lines = constructLines(value); return lines .map(function (line, lineIndex) { var left = {}; var right = {}; if (ignoreDiffIndexes.includes(diffIndex + "-" + lineIndex) || (evaluateOnlyFirstLine && lineIndex !== 0)) { return undefined; } if (added || removed) { if (!diffLines.includes(counter)) { diffLines.push(counter); } if (removed) { leftLineNumber += 1; left.lineNumber = leftLineNumber; left.type = DiffType.REMOVED; left.value = line || ' '; // When the current line is of type REMOVED, check the next item in // the diff array whether it is of type ADDED. If true, the current // diff will be marked as both REMOVED and ADDED. Meaning, the // current line is a modification. var nextDiff = diffArray[diffIndex + 1]; if (nextDiff && nextDiff.added) { var nextDiffLines = constructLines(nextDiff.value)[lineIndex]; if (nextDiffLines) { var _a = getLineInformation(nextDiff.value, diffIndex, true, false, true)[0].right, rightValue = _a.value, lineNumber = _a.lineNumber, type = _a.type; // When identified as modification, push the next diff to ignore // list as the next value will be added in this line computation as // right and left values. ignoreDiffIndexes.push(diffIndex + 1 + "-" + lineIndex); right.lineNumber = lineNumber; right.type = type; // Do word level diff and assign the corresponding values to the // left and right diff information object. if (disableWordDiff) { right.value = rightValue; } else { var computedDiff = computeDiff(line, rightValue, compareMethod); right.value = computedDiff.right; left.value = computedDiff.left; } } } } else { rightLineNumber += 1; right.lineNumber = rightLineNumber; right.type = DiffType.ADDED; right.value = line; } } else { leftLineNumber += 1; rightLineNumber += 1; left.lineNumber = leftLineNumber; left.type = DiffType.DEFAULT; left.value = line; right.lineNumber = rightLineNumber; right.type = DiffType.DEFAULT; right.value = line; } counter += 1; return { right: right, left: left }; }) .filter(Boolean); }; diffArray.forEach(function (_a, index) { var added = _a.added, removed = _a.removed, value = _a.value; lineInformation = __spread(lineInformation, getLineInformation(value, index, added, removed)); }); return { lineInformation: lineInformation, diffLines: diffLines, }; };
  2. if it dosent work, make sure the node_modules cache is cleaned
Monster12138 commented 2 years ago

var newarr = getArr(newString, { newlineIsToken: true, ignoreWhitespace: false, ignoreCase: false, }) var oa = oldarr.splice(0, num)

I tried replace code, but can't find the getArr() function, where is it defined

LeePiaPia commented 2 years ago

var newarr = getArr(newString, { newlineIsToken: true, ignoreWhitespace: false, ignoreCase: false, }) var oa = oldarr.splice(0, num)

I tried replace code, but can't find the getArr() function, where is it defined

var getArr = (value, options) => { let retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);

// Ignore the final empty token that occurs if the string ends with a new line
if (!linesAndNewlines[linesAndNewlines.length - 1]) {
    linesAndNewlines.pop();
}

// Merge the content and line separators into single tokens
for (let i = 0; i < linesAndNewlines.length; i++) {
    let line = linesAndNewlines[i];

    if (i % 2 && !options.newlineIsToken) {
        retLines[retLines.length - 1] += line;
    } else {
        if (options.ignoreWhitespace) {
            line = line.trim();
        }
        retLines.push(line);
    }
}

return retLines;

}

var spliceArray = function (arr, num) { var len = arr.length var n = num var lineNum = len % n === 0 ? len / n : Math.floor((len / n) + 1); var result = [] for (var i = 0; i < lineNum; i++) { var temp = arr.slice(i n, i n + n); result.push(temp); } return result }

lucyfeifei commented 2 years ago

var newarr = getArr(newString, { newlineIsToken: true, ignoreWhitespace: false, ignoreCase: false, }) var oa = oldarr.splice(0, num)

I tried replace code, but can't find the getArr() function, where is it defined

Has your problem been solved?

tylersiemers commented 2 years ago

Will this be fixed in a future release? The above changes did work.

TristanSpeakEasy commented 1 year ago

Any update on getting this issue fixed in the repo? We are trying to diff large files but not files I would consider too big (ie ~2000 lines of code) and it is causing the browser to hang in most cases

TristanSpeakEasy commented 1 year ago

@praneshr I have created a PR to fix this issue https://github.com/praneshr/react-diff-viewer/pull/172

@LeePiaPia would be great to get a review as it was based on your provided code (with some cleanup)

erothmayer commented 1 year ago

This code should not be used. It is faster, but it is incorrect.

Because the new approach is "chunking" the diff processing into sets of 100 it gives incorrect results on inputs over 100 lines long. For example, you can use the following inputs to simulate a pair of input files 302 lines long where the only difference is that a single line has been removed from the new value.

const range = (start, end) => [...Array(end).keys()].slice(start, end);
const oldValue = `{\n${range(0, 300).join('\n')}\n}`;
const newValue = `{\n${[...range(0, 50), ...range(51, 300)].join('\n')}\n}`;

When I try this in the original version of the code it works fine, and reports only the line containing "50" as removed and no other changes. When I try it with the suggested change above it correctly reports the line containing "50" as removed on the left, but then reports the lines containing "99", "149", "199", "249", and "299" as removed on the left and added on the right.

This problem will become worse the larger the difference in line counts between the files. Once you get past 100 lines difference on a given side, every line will be reported as a difference even when all the lines exist with no changes elsewhere in each file.

Note: I did this testing with the cleaned up version in the linked PR.