Każdy programista wie, że duplikacja w kodzie źródłowym to zło, gdyż:
- jeśli zduplikowany kod zawiera błąd, trzeba naprawić go w kilku miejscach (i z reguły o którymś się zapomina),
- długi kod trudniej się czyta.
A jednak zadanie przerzucenia powtarzanych fragmentów HTML (jak nagłówek i stopka wyświetlane na wszystkich podstronach) do osobnych, reużywalnych plików wcale nie jest trywialne!
Mój plik index.html w oryginalnej postaci zawierał 71 linii, z czego około 50 było wspólnych z innymi szablonami (nagłówek, stopka, menu, załączane skrypty js). Zależało mi na wyodrębnieniu części wspólnych do własnych plików. Chociażby po to, żeby dodanie pozycji z menu nie musiało być odwzorowywane w pięciu miejscach.
Jakie miałam możliwości?
- Oprogramować operację include w JavaScripcie (lub użyć czyjegoś kodu, np. z W3Schools). Wady:
- dużo JavaScriptu,
- metoda z gatunku nieeleganckich hacków.
- Użyć znaczników HTML:
object
,embed
lub nawetiframe
. Wady:- dwa pierwsze znaczniki zostały zaprojektowane do osadzania na stronach obiektach takich jak filmy, choć da się ich użyć tak że do wstawienia dokumentu HTML,
- wszystkie służą do dodania do strony kompletnego dokumentu, a nie fragmentu,
- styl CSS obowiązujący na stronie nie zadziała na załączone w ten sposób fragmenty.
- Skorzystać z mechanizmu udostępnianego przez silnik szablonów, w tym wypadku Thymeleaf. Wady:
- serwer wykonuje pracę, którą mógłby wykonać klient 🙂
- ewentualna zmiana silnika szablonów staje się jeszcze bardziej kosztowna.
Zdecydowałam się na rozwiązanie numer 3. Jak to wygląda w praktyce?
Na wszystkich moich stronach powtarzał się poniższy fragment:
1 2 3 4 5 6 7 |
<!-- Header --> <header id="header" class="alt"> <h1> <a href="#">Szafbook</a> </h1> <a href="#nav">Menu</a> </header> |
Przeniosłam go (wraz z innymi podobnymi elementami) do osobnego pliku _menus.html:
1 2 3 4 5 6 |
<header th:fragment="title-menu"> <h1> <a href="/">Szafbook</a> </h1> <a href="#nav">Menu</a> </header> |
Dzięki temu mogę załączać go wszędzie tam, gdzie jest potrzebny, w następujący sposób:
1 |
<header id="header" class="alt" th:include="_menus :: title-menu" /> |
Pułapka 1: Na początku umieściłam atrybuty id
i class
we fragmencie załączanym (w _menus.html). Zostały zjedzone 🙂
A co, jeśli fragment, który chcę załączyć, nie jest otoczony sensowną parą znaczników? Mogę wtedy użyć bloku, np.:
1 2 3 4 |
<th:block th:fragment="scripts"> <script src="assets/js/jquery.min.js"></script> ... </th:block> |
I załączyć go w analogiczny sposób:
1 |
<th:block th:include="_others :: scripts" /> |
W obecnej chwili index.html ma tylko 32 niepuste linie i dużo zyskał na czytelności, podobnie jak inne szablony.
Pułapka 2: Po wyodrębnieniu stopki do osobnego pliku, moim oczom ukazał się taki oto widok:

Wszystkie pliki mam zakodowane w UTF-8, takie samo kodowanie deklaruję w nagłówku HTML. Poczytałam trochę o problemach z kodowaniem na linii Spring/Thymeleaf, ale ostatecznie, ponieważ na teraz jest to jedyne wystąpienie polskiego znaku na mojej stronie, po prostu zmieniłam odpowiadającą za to linię na:
1 |
<li>© Na miękko</li> |
Jedna myśl nt. „Pozbywam się powtarzalnych fragmentów HTML przy użyciu Thymeleaf”