Vanilla JavaScript i natywne API DOM jako alternatywa dla Reacta i innych frameworków

Management Summary
Interaktywne funkcje strony można budować z narzędzi dostępnych w przeglądarce albo z frameworkiem, czyli gotowym szkieletem porządkującym aplikację. Małe kalkulatory i niezależne narzędzia często potrzebują niewielu dodatków, a liczne powiązane widoki mogą korzystać ze wspólnej struktury. Artykuł porównuje te podejścia, aby dopasować rozwiązanie do zadania. Mniej pobieranego kodu może pomagać, lecz o wyniku decydują też utrzymanie, dostępność i rzeczywista szybkość reakcji.
Spis treści
Vanilla JavaScript oznacza korzystanie z JavaScriptu i API przeglądarki bez dodatkowej biblioteki interfejsu. W małym kalkulatorze, wskaźniku stanu lub niezależnym narzędziu na stronie takie podejście może ograniczyć zależności i pobierany kod. W aplikacji ze współdzielonym stanem, routingiem i wieloma powiązanymi widokami framework może zapewnić przydatną strukturę. Decyzja zależy od interfejsu i kosztu utrzymania, a nie od uniwersalnego rankingu szybkości.
Koszty renderowania wymagają pomiarów
DOM to uporządkowana reprezentacja elementów strony w przeglądarce, takich jak nagłówki, przyciski i formularze. React podczas renderowania wyznacza oczekiwany interfejs, a następnie wprowadza potrzebne zmiany w DOM. Obliczanie układu i malowanie pozostają zadaniami przeglądarki. React, Angular i Vue nie stosują jednego identycznego mechanizmu aktualizacji. Hydratacja łączy funkcje JavaScriptu z HTML wygenerowanym wcześniej na serwerze. Na przykład widoczny już przycisk otrzymuje wtedy funkcję obsługującą kliknięcie. Nie każda aplikacja korzysta z hydratacji.
Duże skrypty i długie zadania synchroniczne mogą opóźniać interakcje w obu architekturach. Bezpośredni dostęp do DOM również może wywołać kosztowne obliczenia układu, zwłaszcza przy naprzemiennym odczytywaniu i zmienianiu geometrii. Usunięcie biblioteki nie usuwa pracy wykonywanej przez aplikację.
LCP opisuje moment wyrenderowania największego kwalifikującego się widocznego elementu treści. Znaczenie mogą mieć odpowiedź serwera, obrazy, fonty, CSS i JavaScript. INP opisuje responsywność interakcji podczas wizyty na stronie. Mniejsze pakiety mogą pomóc, ale liczba zależności ani CSS Grid nie gwarantują dobrych wyników. Porównanie wymaga takich samych funkcji, reprezentatywnych urządzeń, diagnostyki laboratoryjnej i pomiarów z rzeczywistych wizyt.

Natywne elementy konstrukcyjne
- Semantyczny HTML: natywne przyciski, pola formularzy i rozwijane sekcje stanowią dobry punkt wyjścia przed własnymi skryptami.
- Custom elements: elementy wielokrotnego użytku mogą reagować na dołączenie i zmiany atrybutów. Opcjonalny Shadow DOM wydziela wewnętrzne drzewo oraz style; custom element nie wymaga Shadow DOM.
- Szablony: zwykły
<template>przechowuje nieaktywny fragment do klonowania. Klonowanie i wstawianie dużego drzewa nadal zajmuje czas. - Delegacja zdarzeń: kontener może obsługiwać odpowiednie zdarzenia potomków propagujące w górę. Na przykład lista może obsługiwać kliknięcia swoich przycisków jedną wspólną funkcją. Zdarzenia bez takiej propagacji i granice Shadow DOM wymagają osobnego uwzględnienia.
Te funkcje należą do standardów HTML i DOM. ECMAScript definiuje język JavaScript, a nie cały model komponentów przeglądarki.
Wskaźnik z jawną obsługą stanu
Poniższy komponent light DOM zarządza własną zawartością potomną i przyjmuje wyłącznie idle, ready oraz error. Nieznane wartości dają idle. Zmiany atrybutu aktualizują widoczny tekst po wstawieniu elementu, a ponowne dołączenie zachowuje istniejące węzły.
class CustomStatusBadge extends HTMLElement {
static observedAttributes = ['data-status'];
connectedCallback() {
if (!this.badge) {
this.badge = document.createElement('span');
this.dot = document.createElement('span');
this.dot.className = 'dot';
this.dot.setAttribute('aria-hidden', 'true');
this.label = document.createElement('span');
this.label.className = 'label';
this.badge.append(this.dot, this.label);
this.replaceChildren(this.badge);
}
this.render();
}
attributeChangedCallback() {
if (this.badge) this.render();
}
render() {
const raw = this.getAttribute('data-status');
const status = ['idle', 'ready', 'error'].includes(raw) ? raw : 'idle';
this.badge.className = 'badge badge-' + status;
this.label.textContent = 'Status: ' + status.toUpperCase();
}
}
customElements.define('status-badge', CustomStatusBadge);
Rejestracja następuje raz, najlepiej w zewnętrznym module. Przykładowy HTML: <status-badge data-status="ready">Status: READY</status-badge>. Tekst zastępczy jest dostępny przed uruchomieniem modułu. Style .badge, .dot i klas stanu zależą od aplikacji. Angielskie etykiety przykładu wymagają lokalizacji w interfejsie wielojęzycznym.
Budowanie DOM nie wymaga parsowania ciągu HTML, a textContent wstawia tekst. Lista dozwolonych wartości zapobiega także dodawaniu obcych klas CSS przez dowolne wartości stanu. To lokalna reguła komponentu, a nie pełna polityka bezpieczeństwa: adresy URL, formatowany HTML i inne konteksty wyjściowe wymagają odpowiedniej obsługi. Ozdobna kropka jest ukryta przed technologiami asystującymi; tekst przekazuje stan niezależnie od koloru. Automatyczne ogłaszanie zmian wymaga świadomie zaprojektowanego i przetestowanego regionu live.
Pytania i odpowiedzi
Kiedy framework jest opłacalny?
Stan współdzielony między wieloma widokami, złożona nawigacja, konwencje zespołu i gotowe dostępne komponenty mogą uzasadniać bibliotekę. Obok kosztu ładowania liczą się utrzymanie i poprawność. Niezależne narzędzia często potrzebują mniej infrastruktury; duża aplikacja nie staje się automatycznie prostsza po usunięciu zależności.
Czy Shadow DOM wysyła wewnętrzne pole z zewnętrznym formularzem?
Pole wewnątrz drzewa Shadow DOM nie należy automatycznie do zewnętrznego formularza. Element powiązany z formularzem może wykorzystać ElementInternals i setFormValue. Walidacja, resetowanie, etykiety i obsługa klawiatury nadal wymagają implementacji oraz testów. Natywne pola pozostają wartościową opcją.
Czy escapowanie we frameworku zapobiega każdemu wstrzyknięciu kodu?
Nie. Zwykła interpolacja tekstu i jawne API surowego HTML działają inaczej. Wskaźnik korzysta ze wstawiania tekstu oraz stałych klas; dowolny niezaufany HTML nie może być traktowany jak zwykła interpolacja tekstu.
Źródła
- React: wyznaczanie interfejsu i wprowadzanie zmian
- React hydrateRoot: łączenie funkcji z HTML serwera
- Angular: cykl życia komponentów
- Google web.dev: czas reakcji na interakcje (INP)
- Google web.dev: największy widoczny element treści (LCP)
- Standard HTML WHATWG: własne elementy
- Standard HTML WHATWG: element template
- Standard DOM WHATWG: Node.textContent
- MDN Web Docs: dokumentacja technologii WWW
- Google web.dev: ograniczanie kosztownych i powtarzanych obliczeń układu
- React: wstawianie surowego HTML