jQuery vs Vanilla JS w 2026: migracja, ryzyka i wyjątki

jQuery vs Vanilla JS w 2026: migracja, ryzyka i wyjątki

Ostatnio zweryfikowano: 22 września 2026
11 min czytania
Przewodnik
Full-stack developer

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.

#Czy jQuery spowalnia stronę WordPress

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”):

MetrykaZ jQueryBez jQueryPoprawa
Całkowity rozmiar JS142KB55KB-61%
TBT (mobile)480ms180ms-62%
INP (p75)220ms95ms-57%
LCP2.1s1.7s-19%
Lighthouse Performance7294+22 punkty

Te liczby pochodzą z produkcyjnej strony WordPress na GeneratePress z WooCommerce, testowanej na Moto G Power (reprezentatywne urządzenie średniej klasy).

#Jak zastąpić jQuery czystym JavaScriptem

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.

#querySelector zamiast $() z jQuery

// 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.

#addEventListener zamiast .click() z jQuery

// 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.

#classList zamiast addClass z jQuery

// 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');

#Jak zastąpić $.ajax przez fetch 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();
}

#Jak zastąpić fadeIn i slideDown animacjami CSS

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.

#Tworzenie i wstawianie elementów DOM bez jQuery

// 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 bez jQuery

// 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 zamiast 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ą.

#Panel rozwijalny jako Web Component

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 wybrać Web Components, a kiedy framework

ScenariuszRekomendacja
Prosty interaktywny widget (akordeon, zakładki, modal)Web Component
Pełna aplikacja SPAReact / Vue / Svelte
Blok WordPress (Gutenberg)React (standard WordPress)
Współdzielony komponent między serwisamiWeb Component
Złożone zarządzanie stanemFramework z biblioteką stanu

#Jak usunąć jQuery z motywu 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:

  1. Frontend motywu (wpływa na każdego odwiedzającego) - migruj najpierw
  2. Frontend własnej wtyczki - migruj w drugiej kolejności
  3. Dostosowania panelu admina - migruj na końcu (mniejszy ruch)

#Krok 3: Zastępuj wzorce inkrementalnie

Nie przepisuj wszystkiego naraz. Zastępuj plik po pliku:

  1. Usuń array('jquery') z tablicy zależności wp_enqueue_script pliku
  2. Zamień wszystkie wzorce jQuery na odpowiedniki vanilla JS
  3. Przetestuj w Chrome, Firefox, Safari i Edge
  4. Przetestuj z wszystkimi aktywnymi wtyczkami
  5. 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: Dołącz skrypty przez wp_enqueue_script bez jQuery

// 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 warto zostać przy jQuery w 2026

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.

#Natywne odpowiedniki $.extend, $.each i $.Deferred

#Głęboka kopia obiektu bez $.extend

// jQuery
const copy = $.extend(true, {}, original);

// ES2024+
const copy = structuredClone(original);

#forEach zamiast $.each

// 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);

#Promise zamiast $.Deferred

// 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 zamiast scroll handlerów 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));

#Alpine.js lub htmx zamiast jQuery

Jeśli wielokrotnie piszesz te same wzorce vanilla JS, rozważ mikro-bibliotekę zamiast jQuery:

BibliotekaRozmiarPrzeznaczenie
Alpine.js15KBDeklaratywna reaktywność (x-data, x-on)
htmx14KBAJAX, WebSocket, SSE via atrybuty HTML
Petite-Vue6KBSkładnia szablonów kompatybilna z Vue
Brak (vanilla)0KBNajlepsza 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.

#Lista kontrolna migracji z jQuery

  1. Zaudytuj całe użycie jQuery w motywie i własnych wtyczkach
  2. Zmierz aktualne Core Web Vitals jako punkt odniesienia
  3. Zamień kod frontendu motywu jako pierwszy (największy wpływ na odwiedzających)
  4. Używaj querySelector, addEventListener, fetch, classList i Web Animations API
  5. Rozważ Web Components dla wielokrotnego użytku elementów UI
  6. Używaj wp_enqueue_script_module() dla obsługi modułów ES
  7. Testuj we wszystkich głównych przeglądarkach po migracji każdego pliku
  8. Zmierz Core Web Vitals ponownie i udokumentuj poprawę
  9. Zachowaj jQuery tylko dla skryptów admina i zależności wtyczek zewnętrznych
  10. 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.

#Co sprawdzić, gdy po usunięciu jQuery coś przestaje działać

Po usunięciu array('jquery') z pierwszego pliku otwórz konsolę przeglądarki. Błąd $ is not defined albo jQuery is not defined znaczy, że inny skrypt motywu lub wtyczki nadal korzysta z biblioteki i trzeba go dopisać do audytu z kroku 1.

  • Kliknięcia działają tylko na elementach z pierwszego renderu. Treść doładowana przez AJAX, na przykład przyciskiem “load more”, potrzebuje listenera na elemencie nadrzędnym i delegacji zdarzeń.
  • Nowy endpoint REST odrzuca żądania. Sprawdź, czy nonce trafia do nagłówka X-WP-Nonce, tak jak w przykładzie z kroku 4, i czy trasa /wp-json/ jest zarejestrowana.
  • Kreator formularzy albo page builder przestał działać. To zależność wtyczki zewnętrznej. Przywróć jQuery dla tej wtyczki i migruj tylko własny kod.
  • Lighthouse pokazuje ten sam wynik co przed migracją. Jeśli jQuery nadal ładuje się na froncie, ściąga je któraś z aktywnych wtyczek. Zobacz w zakładce Network, który skrypt je wymaga.

Każdy z tych testów powtórz w Chrome, Firefox, Safari i Edge, zanim przejdziesz do następnego pliku.

Następny krok

Przekuj artykuł w realne wdrożenie

Pod tym wpisem dokładam linki, które domykają intencję użytkownika i prowadzą dalej w strukturze serwisu.

Chcesz wdrożyć ten temat na swojej stronie?

Jeśli planujesz architekturę Headless WordPress, decoupling frontendu lub migrację na Astro, przygotuję architekturę, backend WP i superszybki frontend.

Powiązany klaster

Sprawdź inne usługi WordPress i bazę wiedzy

Wzmocnij swój biznes dzięki profesjonalnemu wsparciu technicznemu w kluczowych obszarach ekosystemu WordPress.

Czy w 2026 roku jQuery jest jeszcze potrzebne w WordPress?#
Nie. Nowoczesne przeglądarki natywnie wspierają querySelector, addEventListener, classList, fetch, IntersectionObserver i Web Animations API. WordPress 6.7+ zachowuje warstwę kompatybilności jQuery, ale zachęca deweloperów do pisania nowego kodu w vanilla JS.
Jaki jest najbezpieczniejszy sposób migracji z jQuery w WordPress?#
Podejście inkrementalne: zaudytuj, które skrypty zależą od jQuery, zamień najprostsze wzorce (selektóry, przełączanie klas, obsługa kliknięć), przetestuj każdą zmianę w przeglądarce i dopiero wtedy usuń zależność jQuery z wp_enqueue_script.
Czy usunięcie jQuery poprawi Core Web Vitals?#
Tak. Usunięcie jQuery eliminuje 87KB nieskompresowanego JavaScript (30KB gzip), zmniejsza Total Blocking Time (TBT) i poprawia Interaction to Next Paint (INP). W benchmarkach strony bez jQuery ładują się 200-400ms szybciej na urządzeniach mobilnych.
Czy Web Components mogą zastąpić wtyczki jQuery?#
W wielu przypadkach tak. Web Components zapewniają enkapsulowane, wielokrotnego użytku elementy UI z Shadow DOM, custom events i lifecycle callbacks. Działają natywnie we wszystkich nowoczesnych przeglądarkach bez żadnych bibliotek.
Czy rdzeń WordPress wciąż zależy od jQuery?#
WordPress aktywnie redukuje zależności od jQuery. Edytor Bloków (Gutenberg) używa React, nie jQuery. Jednak panel administracyjny i wiele starszych wtyczek nadal ładują jQuery. Mapa drogowa WordPress 7.x zakłada dalszą redukcję jQuery.

Potrzebujesz FAQ dopasowanego do branży i rynku? Przygotujemy wersję pod Twoje cele biznesowe.

Porozmawiajmy

Polecane artykuły

Jak dodać Google Maps do WordPressa

Przestań używać iframe. Dowiedz się, jak poprawnie zintegrować Google Maps Platform API, obsłużyć zgody RODO, zoptymalizować Core Web Vitals i wybrać najlepszą wtyczkę lub implementację customową.