W 2008 roku, kiedy ten artykuł został opublikowany po raz pierwszy, jQuery było wybawieniem. Internet Explorer 6 obsługiwał zdarzenia inaczej, selektóry CSS były niespójne, a AJAX wymagał implementacji XMLHttpRequest specyficznych dla przeglądarki. $('.element').hide() było magią, która normalizowała ten chaos.
Dowiedz się więcej o optymalizacji szybkości WordPress na WPPoland.
W 2026 roku każdy problem, który rozwiązywało jQuery, jest obsługiwany natywnie przez przeglądarki. Pytanie nie brzmi już czy migrować, lecz jak to zrobić bezpiecznie, nie psując istniejącej funkcjonalności.
Dlaczego jQuery to dług technologiczny w 2026
jQuery 3.7 waży 87KB nieskompresowanego kodu (30KB po gzip). To może brzmieć niewiele, ale weź pod uwagę koszt:
- Total Blocking Time (TBT): jQuery musi się sparsować i wykonać, zanim jakikolwiek zależny kod ruszy. Na średniej klasy urządzeniach mobilnych dodaje to 150-300ms do TBT.
- Interaction to Next Paint (INP): System delegacji zdarzeń jQuery dodaje narzut do każdej interakcji użytkownika, mierzalnie pogarszając wyniki INP.
- Łańcuch zależności: Załadowanie jQuery oznacza, że każdy skrypt od niego zależny musi czekać, tworząc kaskadę blokujących zasobów.
- Redundantny kod: Każda metoda jQuery, którą wywołujesz, ma natywny odpowiednik, który przeglądarka już dostarcza. Płacisz podwójnie za tę samą funkcjonalność.
Benchmarki wydajności: jQuery vs vanilla JS
Pomiary z produkcyjnego motywu WordPress z typowymi interakcjami (przełączanie menu, zakładki, walidacja formularza, AJAX „load more”):
| Metryka | Z jQuery | Bez jQuery | Poprawa |
|---|---|---|---|
| Całkowity rozmiar JS | 142KB | 55KB | -61% |
| TBT (mobile) | 480ms | 180ms | -62% |
| INP (p75) | 220ms | 95ms | -57% |
| LCP | 2.1s | 1.7s | -19% |
| Lighthouse Performance | 72 | 94 | +22 punkty |
Te liczby pochodzą z produkcyjnej strony WordPress na GeneratePress z WooCommerce, testowanej na Moto G Power (reprezentatywne urządzenie średniej klasy).
Nowoczesny JavaScript (ES2024+) zastępuje każdy wzorzec jQuery
Specyfikacja ES2024, w pełni wspierana w Chrome 124+, Firefox 126+, Safari 17.4+ i Edge 124+, dostarcza natywne alternatywy dla każdego popularnego wzorca jQuery.
Selektóry DOM
// jQuery
const $buttons = $('.btn');
const $container = $('#main-container');
const $firstItem = $('.menu-item:first');
// Vanilla JS (ES2024+)
const buttons = document.querySelectorAll('.btn');
const container = document.getElementById('main-container');
const firstItem = document.querySelector('.menu-item');
// Scoped selection (jak jQuery .find())
const navLinks = container.querySelectorAll('a.nav-link');
Kluczowa różnica: querySelectorAll zwraca statyczny NodeList, a nie kolekcję „na żywo”. To jest bezpieczniejsze, bo lista nie zmienia się niespodziewanie, gdy DOM mutuje.
Obsługa zdarzeń
// jQuery
$('.btn').click(function () {
$(this).toggleClass('active');
});
$('.menu').on('click', '.menu-item', function () {
// delegacja zdarzenia
});
// Vanilla JS
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener('click', () => {
btn.classList.toggle('active');
});
});
// Delegacja zdarzeń (zastępuje .on() z selektorem)
document.querySelector('.menu').addEventListener('click', (e) => {
const item = e.target.closest('.menu-item');
if (item) {
// obsłuż kliknięcie elementu menu
}
});
Metoda closest() to nowoczesny odpowiednik dopasowania delegowanych zdarzeń w jQuery. Przechodzi w górę drzewa DOM, szukając najbliższego przodka pasującego do selektóra.
Manipulacja klasami CSS
// jQuery
$el.addClass('active');
$el.removeClass('hidden');
$el.toggleClass('open');
$el.hasClass('visible');
// Vanilla JS
el.classList.add('active');
el.classList.remove('hidden');
el.classList.toggle('open');
el.classList.contains('visible');
// Wiele klas naraz
el.classList.add('active', 'highlighted', 'animate-in');
el.classList.remove('hidden', 'collapsed');
AJAX z fetch API i async/await
// jQuery
$.ajax({
url: '/wp-json/wp/v2/posts',
method: 'GET',
data: { per_page: 5 },
success: function (posts) { renderPosts(posts); },
error: function (xhr) { console.error(xhr); }
});
// Vanilla JS (nowoczesne async/await)
async function loadPosts() {
try {
const response = await fetch('/wp-json/wp/v2/posts?per_page=5');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const posts = await response.json();
renderPosts(posts);
} catch (error) {
console.error('Nie udało się załadować postów:', error);
}
}
// POST z nonce (wzorzec WordPress)
async function submitForm(data) {
const response = await fetch('/wp-json/custom/v1/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': wpApiSettings.nonce,
},
body: JSON.stringify(data),
});
return response.json();
}
Animacje bez jQuery
Metody jQuery .fadeIn(), .slideDown() i .animate() można zastąpić przejściami CSS, animacjami CSS lub Web Animations API.
// jQuery
$('.panel').slideDown(300);
$('.modal').fadeIn(200);
// Podejście CSS (preferowane pod kątem wydajności)
// W CSS:
// .panel { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; }
// .panel.open { max-height: 500px; }
// W JS:
panel.classList.add('open');
// Web Animations API (dla złożonych, programowalnych animacji)
modal.animate(
[
{ opacity: 0, transform: 'scale(0.95)' },
{ opacity: 1, transform: 'scale(1)' },
],
{ duration: 200, easing: 'ease-out', fill: 'forwards' }
);
Web Animations API działa w wątku kompozytora, więc animacje nie blokują głównego wątku. Animacje jQuery działają w głównym wątku i powodują „jank” na wolniejszych urządzeniach.
Manipulacja DOM
// jQuery
$('<div class="notice">Witaj</div>').appendTo('#container');
$('.old-element').replaceWith('<span>Nowy</span>');
$('.item').remove();
$('.list').empty();
// Vanilla JS
const notice = document.createElement('div');
notice.className = 'notice';
notice.textContent = 'Witaj';
container.append(notice);
// Lub insertAdjacentHTML dla stringów HTML
container.insertAdjacentHTML('beforeend', '<div class="notice">Witaj</div>');
// Zamiana
oldElement.replaceWith(Object.assign(document.createElement('span'), { textContent: 'Nowy' }));
// Usuwanie
item.remove();
// Opróżnianie
list.replaceChildren();
Document ready
// jQuery
$(document).ready(function () { /* ... */ });
$(function () { /* skrót */ });
// Vanilla JS
document.addEventListener('DOMContentLoaded', () => {
// DOM jest gotowy
});
// Lub po prostu umieść tag <script> z type="module" na końcu <body>
// Moduły są domyślnie odroczone, więc DOM jest już gotowy
Web Components: nowoczesny zamiennik pluginów jQuery
Pluginy jQuery dostarczały wielokrotnego użytku komponenty UI (slidery, modale, zakładki, akordeony). W 2026 roku Web Components oferują alternatywę opartą na standardach z lepszą enkapsulacją.
Przykład: komponent panelu rozwijalnego
class TogglePanel extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
const title = this.getAttribute('title') || 'Rozwiń';
this.shadowRoot.innerHTML = `
<style>
:host { display: block; margin: 1rem 0; }
button {
width: 100%; padding: 0.75rem 1rem;
background: #f5f5f5; border: 1px solid #ddd;
cursor: pointer; text-align: left;
font-size: 1rem; font-weight: 600;
}
.content {
display: none; padding: 1rem;
border: 1px solid #ddd; border-top: none;
}
:host([open]) .content { display: block; }
</style>
<button part="trigger">${title}</button>
<div class="content"><slot></slot></div>
`;
this.shadowRoot.querySelector('button').addEventListener('click', () => {
this.toggleAttribute('open');
});
}
}
customElements.define('toggle-panel', TogglePanel);
Użycie w HTML:
<toggle-panel title="Informacje o dostawie">
<p>Darmowa dostawa przy zamówieniach powyżej 200 zł.</p>
</toggle-panel>
Web Components zapewniają enkapsulację Shadow DOM (style nie wyciekają), sloty do projekcji treści i lifecycle callbacks. Działają w każdej nowoczesnej przeglądarce bez polyfilli.
Kiedy Web Components, a kiedy framework?
| Scenariusz | Rekomendacja |
|---|---|
| Prosty interaktywny widget (akordeon, zakładki, modal) | Web Component |
| Pełna aplikacja SPA | React / Vue / Svelte |
| Blok WordPress (Gutenberg) | React (standard WordPress) |
| Współdzielony komponent między serwisami | Web Component |
| Złożone zarządzanie stanem | Framework z biblioteką stanu |
Strategia migracji dla projektów WordPress
Krok 1: Zaudytuj użycie jQuery
Uruchom to polecenie w katalogu motywu, aby znaleźć wszystkie odwołania do jQuery:
grep -rn '\$(\|jQuery\.\|jQuery(' --include='*.js' --include='*.php' .
Skategoryzuj każde użycie:
- Twój kod (motyw / własna wtyczka): migruj to
- Wtyczka zewnętrzna: zostaw, wtyczka zarządza własnymi zależnościami
- Panel administracyjny WordPress: nie ruszaj, rdzeń WordPress tym zarządza
Krok 2: Stwórz plan migracji
Priorytetyzuj według wpływu:
- Frontend motywu (wpływa na każdego odwiedzającego) - migruj najpierw
- Frontend własnej wtyczki - migruj w drugiej kolejności
- Dostosowania panelu admina - migruj na końcu (mniejszy ruch)
Krok 3: Zastępuj wzorce inkrementalnie
Nie przepisuj wszystkiego naraz. Zastępuj plik po pliku:
- Usuń
array('jquery')z tablicy zależnościwp_enqueue_scriptpliku - Zamień wszystkie wzorce jQuery na odpowiedniki vanilla JS
- Przetestuj w Chrome, Firefox, Safari i Edge
- Przetestuj z wszystkimi aktywnymi wtyczkami
- Uruchom Lighthouse przed i po, aby zmierzyć poprawę
Krok 4: Obsłuż wzorzec WordPress AJAX
Starszy wzorzec AJAX w WordPress używa admin-ajax.php z jQuery:
// Stary wzorzec (jQuery + admin-ajax)
jQuery.post(ajaxurl, {
action: 'my_custom_action',
nonce: myData.nonce,
post_id: 123,
}, function (response) {
console.log(response);
});
// Nowoczesny wzorzec (fetch + REST API)
async function myCustomAction(postId) {
const response = await fetch('/wp-json/myplugin/v1/action', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': myData.nonce,
},
body: JSON.stringify({ post_id: postId }),
});
return response.json();
}
Podejście REST API jest szybsze (brak narzutu admin-ajax.php), bardziej „cacheable” i zgodne z nowoczesnymi standardami rozwoju WordPress.
Krok 5: Poprawnie enkułuj skrypty
// Przed (z zależnością jQuery)
wp_enqueue_script(
'my-theme-scripts',
get_template_directory_uri() . '/js/main.js',
array('jquery'),
'1.0.0',
true
);
// Po (bez jQuery, z obsługą modułów)
wp_enqueue_script_module(
'my-theme-scripts',
get_template_directory_uri() . '/js/main.js',
array(),
'2.0.0'
);
WordPress 6.5+ wspiera wp_enqueue_script_module(), która ładuje skrypty jako moduły ES z type="module", umożliwiając natywną składnię import/export.
Kiedy jQuery wciąż ma sens
jQuery może być wciąż uzasadnione, jeśli:
- Legacy codebase z 50+ zależnościami od pluginów jQuery: Koszt migracji przewyższa korzyść wydajnościową. Zaplanuj stopniowe wycofywanie w ciągu 6-12 miesięcy.
- Dostosowania panelu administracyjnego: Panel admina już ładuje jQuery. Dodanie własnych skryptów admina z zależnością jQuery nic nie kosztuje.
- Wymagania wtyczek zewnętrznych: Niektóre popularne wtyczki (kreatory formularzy, page buildery) wymagają jQuery. Nie walcz z zależnością, jeśli nie masz nad nią kontroli.
- Luka kompetencyjna zespołu: Jeśli Twój zespół programistyczny nie czuje się komfortowo z nowoczesnym JS, zainwestuj w szkolenie przed wymuszaniem migracji.
Celem jest pragmatyczna poprawa, nie ideologiczna czystość. Usuń jQuery tam, gdzie kosztuje Cię wydajność i nie wnosi wartości. Zachowaj tam, gdzie usunięcie popsuliby coś lub kosztowało więcej niż oszczędza.
Funkcje ES2024+, które zastępują popularne narzędzia jQuery
Structured clone (głęboka kopia)
// jQuery
const copy = $.extend(true, {}, original);
// ES2024+
const copy = structuredClone(original);
Iteracja po kolekcjach
// jQuery
$.each(items, function (index, item) { /* ... */ });
// ES2024+
items.forEach((item, index) => { /* ... */ });
// Lub Array.from dla NodeList
Array.from(document.querySelectorAll('.item')).map(item => item.textContent);
// Operator spread
[...document.querySelectorAll('.item')].filter(item => item.dataset.active);
Wzorce Deferred/Promise
// jQuery
const deferred = $.Deferred();
deferred.resolve('done');
deferred.promise().then(val => console.log(val));
// ES2024+
const promise = new Promise((resolve) => resolve('done'));
promise.then(val => console.log(val));
// Promise.withResolvers() - funkcja ES2024
const { promise, resolve, reject } = Promise.withResolvers();
IntersectionObserver (zastępuje scroll handlery jQuery)
// jQuery (kosztowny scroll handler)
$(window).scroll(function () {
$('.lazy-image').each(function () {
if ($(this).offset().top < $(window).scrollTop() + $(window).height()) {
$(this).attr('src', $(this).data('src'));
}
});
});
// Vanilla JS (wydajne, poza głównym wątkiem)
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll('.lazy-image').forEach(img => observer.observe(img));
Alternatywne mikro-biblioteki (jeśli potrzebujesz helpera)
Jeśli wielokrotnie piszesz te same wzorce vanilla JS, rozważ mikro-bibliotekę zamiast jQuery:
| Biblioteka | Rozmiar | Przeznaczenie |
|---|---|---|
| Alpine.js | 15KB | Deklaratywna reaktywność (x-data, x-on) |
| htmx | 14KB | AJAX, WebSocket, SSE via atrybuty HTML |
| Petite-Vue | 6KB | Składnia szablonów kompatybilna z Vue |
| Brak (vanilla) | 0KB | Najlepsza wydajność, pełna kontrola |
Dla motywów WordPress w 2026 roku rekomendacja to vanilla JS dla prostych interakcji i Alpine.js lub htmx, jeśli potrzebujesz deklaratywnego zachowania bez pełnego frameworka.
Podsumowanie: lista kontrolna migracji
- Zaudytuj całe użycie jQuery w motywie i własnych wtyczkach
- Zmierz aktualne Core Web Vitals jako punkt odniesienia
- Zamień kod frontendu motywu jako pierwszy (największy wpływ na odwiedzających)
- Używaj
querySelector,addEventListener,fetch,classListi Web Animations API - Rozważ Web Components dla wielokrotnego użytku elementów UI
- Używaj
wp_enqueue_script_module()dla obsługi modułów ES - Testuj we wszystkich głównych przeglądarkach po migracji każdego pliku
- Zmierz Core Web Vitals ponownie i udokumentuj poprawę
- Zachowaj jQuery tylko dla skryptów admina i zależności wtyczek zewnętrznych
- Przeszkol swój zespół z nowoczesnych wzorców JavaScript
Platforma webowa w 2026 roku dostarcza wszystko, co oferowało jQuery, i więcej. Każdy kilobajt niepotrzebnego JavaScript, który usuniesz, sprawia, że Twoja strona WordPress jest szybsza, bardziej dostępna i łatwiejsza w utrzymaniu.


