Jak znaleźć różnice między dwoma plikami HTML
Dwa pliki HTML mogą wyświetlać się identycznie w przeglądarce, a jednocześnie różnić się w dziesiątkach miejsc w źródle. Białe znaki wokół tagów, kolejność atrybutów, encje HTML i składnia samozamykająca to najczęstsze przyczyny. Zwykły diff tekstu oznacza każdą z tych różnic jako zmianę, przez co chowa to, na czym naprawdę zależy. Ten przewodnik pokazuje, jak uzyskać czysty wynik.
Jeśli chcesz od razu przejść do narzędzia, nasza strona do porównywania HTML pozwala wkleić dwa pliki i zobaczyć diff w przeglądarce bez żadnej instalacji. Reszta artykułu wyjaśnia, na co zwrócić uwagę po uzyskaniu wyników.
Dlaczego diff HTML generuje tak dużo szumu
HTML nie jest formatem liniowym. Akapit może być jedną długą linią lub rozciągać się na dziesięć linii — oba warianty są poprawne. Większość edytorów, formaterów kodu i systemów CMS reformatuje HTML przy zapisie, co oznacza, że zmiana jednego słowa może kaskadowo wpłynąć na dziesiątki przeformatowanych linii. Diff widzi je jako zmienione linie, a nie jako "zmianę jednego słowa."
WHATWG HTML Living Standard określa, jak przeglądarki parsują HTML, ale nie mówi, jak powinien on być serializowany z powrotem do tekstu. Dwa narzędzia mogą generować strukturalnie identyczny HTML, który jako surowy tekst wygląda zupełnie inaczej.
Cztery rzeczy odpowiadają za większość szumu:
- Białe znaki między tagami i wewnątrz nich
- Kolejność atrybutów (przeglądarki nie wymagają określonej kolejności)
- Encje HTML a znaki dosłowne
- Składnia elementów void (
<br>a<br />)
Białe znaki: największe źródło fałszywych alarmów
W większości kontekstów kolejne białe znaki w HTML są zwijane do jednej spacji podczas renderowania przez przeglądarkę. Oznacza to, że te dwa fragmenty są wyświetlane identycznie:
<!-- Version 1 -->
<p>Free text comparison tool.</p>
<!-- Version 2 -->
<p>
Free text comparison tool.
</p>
Zwykły diff tekstu oznacza obie linie jako zmienione. Nie są zmienione w żadnym znaczącym sensie. Przed porównaniem zdecyduj, czy białe znaki mają znaczenie w Twoim przypadku. W przypadku szablonów e-mail lub rendererów PDF czasem mają. Dla większości stron internetowych — nie.
Najlepszym rozwiązaniem jest przepuszczenie obu plików przez formater, taki jak Prettier, z tą samą konfiguracją przed porównaniem. Normalizuje to wcięcia, długość linii i spacje w jednym kroku. Gdy oba pliki mają ten sam styl formatowania, zwykły diff tekstu oznacza tylko prawdziwe zmiany w treści.
Kolejność atrybutów
Specyfikacja HTML nie wymaga, aby atrybuty pojawiały się w określonej kolejności.
<div id="main" class="container"> i
<div class="container" id="main"> to ten sam element.
Jednak diff liniowy traktuje je jako różne linie. Jest to szczególnie częste,
gdy szablony są generowane przez różne narzędzia lub gdy ktoś uruchamia
auto-formater sortujący atrybuty alfabetycznie.
Zgodnie ze specyfikacją parsowania WHATWG, atrybuty na tym samym elemencie są z definicji nieuporządkowane. Diff raportujący zmianę kolejności atrybutów jako zmianę jest technicznie poprawny, ale rzadko użyteczny. Znormalizuj kolejność atrybutów w obu plikach przed porównaniem, jeśli powoduje to szum.
Encje HTML
&, <, >,
, odwołania numeryczne takie jak —
— to wszystko sposoby kodowania znaków w źródle HTML. Dwa pliki mogą kodować
ten sam znak w różny sposób i renderować tę samą stronę. Diff tekstu widzi
& i & jako różne ciągi znaków, choć
oba generują ampersand w przeglądarce.
Jeśli różnice w encjach zaśmiecają diff, przepuść oba pliki przez parser HTML
normalizujący encje przed porównaniem. Przeglądarkowe
API DOMParser
to niezawodny sposób na zrobienie tego w JavaScript: sparsuj oba ciągi,
serializuj je z powrotem przez innerHTML i porównaj wynik.
Elementy void
W HTML5 elementy void (elementy bez dzieci) nie potrzebują ukośnika zamykającego.
<br>, <br/> i <br />
są poprawne i parsowane identycznie. To samo dotyczy <img>,
<input>, <meta> i pozostałych. Jeśli
jeden plik używa samozamykających ukośników w stylu XHTML, a drugi zwykłej
składni HTML5, diff tekstu oznaczy każdy taki element.
Pełna lista
elementów void na MDN
obejmuje wszystkie 14. Szybkie wyszukanie /> w wynikach diff
pokaże, ile szumu pochodzi ze składni samozamykającej.
Przykład z życia wzięty
Oto realistyczny przykład przed i po dla nagłówka strony. Trzy rzeczy się zmieniły: do nagłówka dodano klasę CSS, poprawiono cel linku strony głównej i dodano link do strony kontaktowej.
<!-- Version 1 -->
<header class="site-header">
<nav>
<a href="/home" class="nav-link active">Home</a>
<a href="/about" class="nav-link">About</a>
</nav>
</header>
<!-- Version 2 -->
<header class="site-header sticky-top">
<nav>
<a href="/" class="nav-link active">Home</a>
<a href="/about" class="nav-link">About</a>
<a href="/contact" class="nav-link">Contact</a>
</nav>
</header>
Wklej oba do narzędzia do porównywania HTML, a diff podświetli dokładnie te trzy linie: atrybut klasy nagłówka, href strony głównej i nowy tag kotwicy. Bez szumu, bo wcięcia i formatowanie są spójne między dwiema wersjami.
| Element | Wersja 1 | Wersja 2 | Typ zmiany |
|---|---|---|---|
<header> |
class="site-header" |
class="site-header sticky-top" |
Dodano klasę |
| Link strony głównej | href="/home" |
href="/" |
Poprawiono ścieżkę |
| Link kontaktowy | Brak | <a href="/contact">Contact</a> |
Dodano |
Kiedy normalizować przed porównaniem
Nie każde porównanie HTML wymaga normalizacji. Jeśli porównujesz dwa pliki, które sam napisałeś z tymi samymi ustawieniami edytora, zwykły diff tekstu jest zazwyczaj wystarczający. Normalizacja się opłaca, gdy:
- Jeden plik pochodzi z eksportu CMS, a drugi z edytora
- Narzędzie do budowania przeformatowało jeden plik, ale nie drugi
- Porównujesz zminifikowany HTML z czytelnie sformatowanym
- Przeglądasz szablon HTML e-mail od zewnętrznego nadawcy
Usługa walidacji znaczników W3C przydaje się do sprawdzenia, czy oba pliki parsują się poprawnie przed porównaniem. Plik z uszkodzoną strukturą tagów da mylący diff, bo parser naprawia błędy na swój własny sposób, a dwa parsery mogą naprawiać je inaczej.
Porównywanie generowanego HTML
Frameworki renderujące po stronie serwera (Angular, Next.js, Rails) często osadzają w wyjściu HTML znaczniki czasu, nonce'y lub losowe identyfikatory. Dwa rendery tej samej strony będą się różnić w tych liniach, nawet jeśli treść jest identyczna. Jeśli porównujesz generowany HTML, usuń lub znormalizuj te pola przed porównaniem.
Podstawowy silnik diff na tej stronie to diff-match-patch Google'a (Apache 2.0), który działa na surowym tekście. Nie parsuje HTML, więc oznacza różnice formatowania obok różnic w treści. Dlatego normalizacja na początku jest ważna. W większości przypadków bezpośrednie wklejenie obu plików daje wystarczająco użyteczny wynik w kilka sekund. Nasze narzędzie do porównywania XML warto wypróbować, jeśli Twój HTML jest poprawnie sformułowanym XHTML, bo diff z obsługą XML poprawnie obsługuje przestrzenie nazw i kolejność atrybutów.
Często zadawane pytania
- Dlaczego mój diff HTML pokazuje setki zmian, gdy zmieniłem tylko jedną linię?
- Prawie zawsze chodzi o zmianę formatowania. Jeśli edytor lub narzędzie do budowania przeformatowało plik przy zapisie (zmieniło wcięcia, zawinęło długie linie lub zmieniło kolejność atrybutów), zwykły diff tekstu traktuje każdą przeformatowaną linię jako zmianę. Przepuść oba pliki przez ten sam formater, a następnie porównaj. Prawdziwa zmiana będzie jedyną pozostałą linią.
- Czy kolejność atrybutów ma znaczenie w HTML?
- Nie dla przeglądarki. HTML Living Standard nie wymaga, aby atrybuty pojawiały się w określonej kolejności, a przeglądarki parsują je poprawnie niezależnie od niej. Niektóre lintery i formatery sortują atrybuty alfabetycznie jako regułę stylu, co może sprawić, że dwa semantycznie identyczne pliki będą wyglądać różnie w diff tekstu. Jeśli kolejność atrybutów powoduje szum, znormalizuj oba pliki tym samym formaterem przed porównaniem.
- Jaka jest różnica między &amp; a & w źródle HTML?
- Oba generują znak ampersanda, gdy przeglądarka renderuje stronę. W źródle HTML
&to forma zakodowana encją, a&to dosłowny znak. Technicznie&w wartościach atrybutów powinno być zakodowane jako&zgodnie ze specyfikacją, ale przeglądarki akceptują oba warianty. Diff tekstu traktuje je jako różne ciągi. Jeśli kodowanie encji generuje szum, sparsuj oba pliki biblioteką lub przeglądarką DOMParser i serializuj z powrotem przed porównaniem. - Czy mogę porównać zminifikowany HTML z czytelnie sformatowanym?
- Tak, ale najpierw powinieneś sformatować zminifikowany plik. Porównanie zminifikowanego z czytelnie sformatowanym daje wynik, w którym prawie każda linia wygląda na zmienioną, bo minifikacja usuwa wszystkie białe znaki dodane przez formater. Przepuść zminifikowany plik przez Prettier lub równoważny formater, a następnie porównaj. Znaczące zmiany będą widoczne bez szumu białych znaków.
- Jak porównać tylko część pliku HTML, np. konkretny komponent?
- Wyodrębnij odpowiednią sekcję z obu plików i wklej tylko to do narzędzia diff. Na przykład, jeśli przeglądasz zmiany w komponencie nawigacyjnym, skopiuj tylko blok
<nav>z każdego pliku. Porównywanie całego dokumentu, gdy interesuje Cię tylko jedna sekcja, dodaje szum z niepowiązanych części strony. - Czy komentarze HTML są widoczne w diff?
- Tak. Diff oparty na tekście obejmuje wszystko w pliku, w tym komentarze. Jeśli jedna wersja ma blok komentarza, który druga usunęła, lub jeśli deweloper zaktualizował komentarz, diff to pokaże. Jest to zazwyczaj przydatne: usunięty komentarz często sygnalizuje celowe porządkowanie. Jeśli chcesz ignorować komentarze, usuń je z obu plików przed porównaniem.
Gotowy do porównania plików HTML? Wklej oba do darmowego narzędzia do porównywania HTML i zobacz różnice zaznaczone obok siebie, bez rejestracji.