JavaScript - kompendium
JavaScript jest językiem przeglądarki i jednocześnie podstawą dużej części współczesnego webowego toolingu. Warto najpierw rozumieć język, DOM, zdarzenia, fetch i moduły, a frameworki traktować jako kolejną warstwę.
Kompendium obejmuje vanilla JS, Node/npm/Vite oraz orientacyjny przegląd React, Vue, Angular, PixiJS i TypeScript.
Powiązane tematy: Nowoczesny HTML i CSS, Browser DevTools, API i integracje systemów, Node.js i Testowanie oprogramowania.
> Praktyczne kompendium do tworzenia zwykłych, interaktywnych stron i małych aplikacji webowych.
Spis treści
- Co właściwie robi JavaScript
- Jak osadzić JavaScript na stronie
- Pierwszy skrypt
- Zmienne, typy i operatory
- Warunki i pętle
- Funkcje
- Tablice i obiekty
- Destrukturyzacja, spread i rest
- DOM - sterowanie stroną
- Zdarzenia
- Formularze
- Tworzenie i usuwanie elementów
- Klasy CSS i style z JavaScriptu
- Timery
- JSON
- Fetch i komunikacja z API
- Promise i async/await
- Obsługa błędów
- localStorage i sessionStorage
- Moduły ES
- Klasy i programowanie obiektowe
- Przydatne metody tablic
- Event loop - dlaczego async działa tak, jak działa
- Nowoczesne środowisko: Node.js, npm i Vite
- package.json i zależności
- DevTools i debugowanie
- Struktura małego projektu
- Przykład kompletnej aplikacji Vanilla JS
- React
- Vue
- Angular
- PixiJS
- TypeScript
- Testy
- Bezpieczeństwo
- Dostępność
- Wydajność
- Czego nie robić
- Jak wybrać technologię
- Plan nauki
- Projekty ćwiczeniowe
- Ściąga
- Oficjalne źródła
1. Co właściwie robi JavaScript
HTML opisuje strukturę strony.
CSS opisuje wygląd.
JavaScript opisuje zachowanie.
Przykładowo:
- kliknięcie przycisku,
- rozwinięcie menu,
- walidacja formularza,
- pobranie danych z API,
- filtrowanie listy produktów,
- dynamiczne dodawanie elementów,
- modal,
- slider,
- licznik,
- zapis ustawień użytkownika,
- komunikacja z backendem,
- renderowanie grafiki 2D,
- obsługa części interfejsu bez przeładowania strony.
JavaScript wykonywany w przeglądarce ma dostęp m.in. do:
window
document
location
history
navigator
localStorage
fetch()
setTimeout()
Najważniejszy z punktu widzenia zwykłej strony jest document, czyli obiekt reprezentujący dokument HTML.
2. Jak osadzić JavaScript na stronie
Są trzy podstawowe sposoby.
2.1. Kod bezpośrednio w HTML
<script>
console.log("Cześć");
</script>
Dobre do szybkiego testu.
W prawdziwym projekcie zwykle lepiej trzymać JS osobno.
2.2. Zewnętrzny plik JavaScript
index.html:
<!doctype html>
<html lang="pl">
<head>
<meta charset="utf-8">
<title>Moja strona</title>
</head>
<body>
<h1>Test</h1>
<script src="script.js"></script>
</body>
</html>
script.js:
console.log("JavaScript działa");
Jeśli <script> znajduje się na końcu <body>, DOM jest już zwykle zbudowany.
2.3. Nowoczesny sposób: moduł
<script type="module" src="./src/main.js"></script>
To jest obecnie bardzo dobry domyślny wybór.
Moduły:
- obsługują
importiexport, - mają własny zakres zmiennych,
- działają automatycznie w trybie strict,
- są wykonywane po sparsowaniu HTML.
Przykład:
import { add } from "./math.js";
console.log(add(2, 3));
math.js:
export function add(a, b) {
return a + b;
}
3. async, defer i type="module"
Klasyczny skrypt:
<script src="app.js"></script>
może zatrzymać parsowanie HTML, dopóki nie zostanie pobrany i wykonany.
defer
<script defer src="app.js"></script>
Skrypt pobiera się równolegle, ale uruchamia po sparsowaniu dokumentu.
Dobre dla klasycznych skryptów zależnych od DOM.
async
<script async src="analytics.js"></script>
Skrypt uruchomi się natychmiast po pobraniu.
Kolejność nie jest gwarantowana.
Dobre np. dla niezależnych skryptów analitycznych.
type="module"
<script type="module" src="main.js"></script>
W praktyce zachowuje się pod względem parsowania strony podobnie do defer.
Dla nowoczesnego projektu:
<script type="module" src="/src/main.js"></script>
jest sensownym standardem.
4. Pierwszy skrypt
HTML:
<button id="helloButton">Kliknij mnie</button>
<p id="message"></p>
<script type="module" src="./main.js"></script>
JS:
const button = document.querySelector("#helloButton");
const message = document.querySelector("#message");
button.addEventListener("click", () => {
message.textContent = "Działa!";
});
Co się stało:
- znajdujemy przycisk,
- znajdujemy paragraf,
- nasłuchujemy kliknięcia,
- po kliknięciu zmieniamy tekst.
To jest esencja interaktywnego front-endu.
5. Zmienne
Współczesny JavaScript używa głównie:
const
let
const
const name = "Anna";
Nie można przypisać do tej zmiennej nowej wartości:
name = "Adam"; // błąd
let
let counter = 0;
counter = counter + 1;
var
Istnieje ze względów historycznych.
var oldStyle = true;
W nowym kodzie najczęściej go unikamy.
Praktyczna zasada:
Najpierw używaj const.
Jeśli wartość musi się zmieniać - użyj let.
6. Typy danych
String
const name = "Anna";
Number
const age = 46;
const price = 19.99;
JavaScript nie ma osobnego typu integer i float.
Boolean
const loggedIn = true;
const admin = false;
null
Celowy brak wartości:
const selectedUser = null;
undefined
Wartość nie została ustawiona:
let result;
console.log(result);
Object
const user = {
name: "Anna",
age: 46
};
Array
const technologies = ["HTML", "CSS", "JavaScript"];
BigInt
const hugeNumber = 12345678901234567890n;
Symbol
Rzadziej używany:
const id = Symbol("id");
7. Sprawdzanie typu
typeof "abc"; // "string"
typeof 123; // "number"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof {}; // "object"
typeof []; // "object"
Tablicę sprawdzamy:
Array.isArray([]);
8. Operatory
Arytmetyczne:
2 + 2
10 - 3
4 * 5
10 / 2
10 % 3
2 ** 8
Porównania:
5 > 3
5 >= 5
2 < 4
2 <= 2
Równość:
5 === 5
5 !== 4
Unikaj, jeśli nie masz powodu:
==
!=
ponieważ wykonują konwersję typów.
Przykład:
5 == "5"; // true
5 === "5"; // false
Standardowo używaj:
===
!==
9. Operatory logiczne
&&
||
!
Przykład:
if (loggedIn && admin) {
console.log("Panel administratora");
}
10. Nullish coalescing ??
const displayName = user.name ?? "Anonim";
Wartość po prawej zostanie użyta tylko dla:
null
undefined
To różni się od ||.
const value = 0 || 100;
// 100
const value2 = 0 ?? 100;
// 0
11. Optional chaining ?.
Zamiast:
if (user && user.address && user.address.city) {
console.log(user.address.city);
}
możesz:
console.log(user?.address?.city);
Jeśli któregoś elementu nie ma, otrzymasz undefined, zamiast wyjątku.
12. Template strings
Zamiast:
const message = "Witaj " + name + "!";
używamy:
const message = `Witaj ${name}!`;
Wielolinijkowo:
const html = `
<article>
<h2>${title}</h2>
<p>${description}</p>
</article>
`;
13. Warunki
if (age >= 18) {
console.log("Dorosły");
} else {
console.log("Niepełnoletni");
}
Kilka warunków:
if (score >= 90) {
grade = 5;
} else if (score >= 75) {
grade = 4;
} else {
grade = 3;
}
14. Operator trójargumentowy
const label = loggedIn ? "Wyloguj" : "Zaloguj";
Dobrze nadaje się do prostych warunków.
Nie buduj z niego wielopiętrowej logiki.
15. switch
switch (status) {
case "loading":
console.log("Ładowanie");
break;
case "success":
console.log("Gotowe");
break;
case "error":
console.log("Błąd");
break;
default:
console.log("Nieznany status");
}
16. Pętle
for
for (let i = 0; i < 5; i++) {
console.log(i);
}
for...of
Najlepszy do iterowania po elementach:
const names = ["Ala", "Ola", "Jan"];
for (const name of names) {
console.log(name);
}
forEach
names.forEach((name) => {
console.log(name);
});
while
let i = 0;
while (i < 5) {
console.log(i);
i++;
}
17. Funkcje
Klasyczna funkcja
function add(a, b) {
return a + b;
}
Wywołanie:
const result = add(2, 3);
18. Funkcja strzałkowa
const add = (a, b) => {
return a + b;
};
Skrót:
const add = (a, b) => a + b;
Jedna wartość:
const double = x => x * 2;
Funkcje strzałkowe są bardzo częste w:
- event listenerach,
map,filter,- Promise,
- React,
- Vue,
- callbackach.
19. Parametry domyślne
function greet(name = "Gość") {
return `Cześć ${name}`;
}
20. Obiekty
const user = {
name: "Anna",
age: 46,
active: true
};
Dostęp:
user.name
user.age
lub:
user["name"]
Zmiana:
user.active = false;
Dodanie:
user.city = "Example City";
21. Metody obiektu
const user = {
name: "Anna",
greet() {
console.log(`Cześć, jestem ${this.name}`);
}
};
user.greet();
22. Tablice
const items = ["monitor", "laptop", "mysz"];
Dostęp:
items[0];
Liczba elementów:
items.length;
Dodawanie:
items.push("klawiatura");
Usuwanie ostatniego:
items.pop();
Początek tablicy:
items.unshift("telefon");
items.shift();
23. Destrukturyzacja
Obiekt:
const user = {
name: "Anna",
age: 46
};
const { name, age } = user;
Tablica:
const coordinates = [51.1, 17.03];
const [lat, lon] = coordinates;
24. Spread ...
Tablice:
const oldItems = ["a", "b"];
const newItems = [...oldItems, "c"];
Obiekty:
const user = {
name: "Anna",
active: true
};
const updatedUser = {
...user,
active: false
};
Bardzo ważne w React i przy niemutowalnym aktualizowaniu danych.
25. Rest ...
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
sum(1, 2, 3, 4);
26. DOM
DOM to obiektowa reprezentacja dokumentu HTML.
HTML:
<h1 id="title">Stary tytuł</h1>
JS:
const title = document.querySelector("#title");
title.textContent = "Nowy tytuł";
27. Wyszukiwanie elementów
Najczęściej:
document.querySelector()
document.querySelectorAll()
ID:
document.querySelector("#menu");
Klasa:
document.querySelector(".card");
Tag:
document.querySelector("button");
Atrybut:
document.querySelector("[data-action='save']");
Wszystkie:
const cards = document.querySelectorAll(".card");
28. querySelectorAll i iteracja
const buttons = document.querySelectorAll(".button");
buttons.forEach((button) => {
console.log(button.textContent);
});
29. Zmiana treści
element.textContent = "Bezpieczny tekst";
Można też:
element.innerHTML = "<strong>Hello</strong>";
Ale innerHTML wymaga ostrożności.
Nie wkładaj tam bezpośrednio danych pochodzących od użytkownika lub niezaufanego API.
To może prowadzić do XSS.
30. Atrybuty
HTML:
<img id="photo" src="old.jpg" alt="">
JS:
const photo = document.querySelector("#photo");
photo.src = "new.jpg";
photo.alt = "Nowe zdjęcie";
Ogólnie:
element.getAttribute("data-id");
element.setAttribute("aria-expanded", "true");
element.removeAttribute("hidden");
31. dataset
HTML:
<button data-product-id="123">Kup</button>
JS:
const button = document.querySelector("button");
console.log(button.dataset.productId);
wynik:
123
32. Zdarzenia
Podstawowy mechanizm interakcji:
button.addEventListener("click", () => {
console.log("Klik");
});
Popularne wydarzenia:
click
dblclick
input
change
submit
keydown
keyup
focus
blur
mouseenter
mouseleave
pointerdown
pointerup
scroll
resize
DOMContentLoaded
33. Obiekt event
button.addEventListener("click", (event) => {
console.log(event);
console.log(event.target);
});
Dla klawiatury:
document.addEventListener("keydown", (event) => {
console.log(event.key);
});
34. Formularze
HTML:
<form id="loginForm">
<input id="email" type="email">
<button type="submit">Wyślij</button>
</form>
JS:
const form = document.querySelector("#loginForm");
const emailInput = document.querySelector("#email");
form.addEventListener("submit", (event) => {
event.preventDefault();
console.log(emailInput.value);
});
event.preventDefault() blokuje standardową akcję przeglądarki, np. przeładowanie formularza.
35. FormData
Dla większych formularzy:
<form id="userForm">
<input name="name">
<input name="email">
<button>Zapisz</button>
</form>
const form = document.querySelector("#userForm");
form.addEventListener("submit", (event) => {
event.preventDefault();
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
console.log(data);
});
36. Tworzenie elementów
const li = document.createElement("li");
li.textContent = "Nowy element";
document.querySelector("ul").append(li);
37. Usuwanie elementów
element.remove();
38. Klonowanie
const copy = element.cloneNode(true);
true oznacza kopiowanie również dzieci elementu.
39. Klasy CSS
Dodanie:
element.classList.add("active");
Usunięcie:
element.classList.remove("active");
Przełączenie:
element.classList.toggle("active");
Sprawdzenie:
element.classList.contains("active");
To jest zwykle lepsze niż ustawianie stylów bezpośrednio.
40. Style bezpośrednio
Możliwe:
element.style.display = "none";
element.style.opacity = "0.5";
Ale zazwyczaj lepiej:
element.classList.add("hidden");
i w CSS:
.hidden {
display: none;
}
Logika jest w JS, wygląd w CSS.
41. Event delegation
Załóżmy listę:
<ul id="list">
<li><button data-id="1">Usuń</button></li>
<li><button data-id="2">Usuń</button></li>
</ul>
Zamiast dodawać listener do każdego przycisku:
const list = document.querySelector("#list");
list.addEventListener("click", (event) => {
const button = event.target.closest("button[data-id]");
if (!button) {
return;
}
console.log(button.dataset.id);
});
To jest bardzo użyteczny wzorzec przy dynamicznych listach.
42. Timery
setTimeout
setTimeout(() => {
console.log("Minęła sekunda");
}, 1000);
setInterval
const timer = setInterval(() => {
console.log("Tick");
}, 1000);
Zatrzymanie:
clearInterval(timer);
43. JSON
JSON:
{
"name": "Anna",
"active": true
}
JavaScript -> JSON:
const json = JSON.stringify(user);
JSON -> JavaScript:
const user = JSON.parse(json);
44. Fetch API
Najważniejsze narzędzie do komunikacji HTTP w przeglądarce.
fetch("/api/products");
zwraca Promise.
Praktycznie używamy zwykle async/await.
45. Pobieranie danych z API
async function loadUsers() {
const response = await fetch("https://example.com/api/users");
const users = await response.json();
console.log(users);
}
Ale trzeba sprawdzić status odpowiedzi.
async function loadUsers() {
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
46. POST
async function createUser(user) {
const response = await fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(user)
});
if (!response.ok) {
throw new Error("Nie udało się zapisać użytkownika");
}
return response.json();
}
Wywołanie:
createUser({
name: "Anna",
active: true
});
47. Promise
Promise reprezentuje operację, która zakończy się później.
Może mieć stan:
pending
fulfilled
rejected
Przykład:
fetch("/api/users")
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
Ten sam kod w async/await jest zwykle czytelniejszy.
48. async/await
async function loadData() {
const response = await fetch("/api/data");
const data = await response.json();
console.log(data);
}
await można stosować wewnątrz funkcji async.
49. Obsługa błędów
async function loadData() {
try {
const response = await fetch("/api/data");
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Błąd:", error);
throw error;
}
}
50. Stan interfejsu podczas pobierania
Typowy schemat:
async function loadProducts() {
status.textContent = "Ładowanie...";
try {
const response = await fetch("/api/products");
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const products = await response.json();
renderProducts(products);
status.textContent = "";
} catch (error) {
status.textContent = "Nie udało się pobrać danych.";
}
}
W prawdziwym UI zawsze myśl o trzech stanach:
loading
success
error
51. localStorage
Dane przechowywane w przeglądarce.
Zapis:
localStorage.setItem("theme", "dark");
Odczyt:
const theme = localStorage.getItem("theme");
Usuwanie:
localStorage.removeItem("theme");
Czyszczenie:
localStorage.clear();
52. Zapisywanie obiektu
const settings = {
theme: "dark",
compact: true
};
localStorage.setItem(
"settings",
JSON.stringify(settings)
);
Odczyt:
const settings = JSON.parse(
localStorage.getItem("settings") ?? "{}"
);
Nie zapisuj w localStorage:
- haseł,
- kluczy API,
- sekretów backendowych,
- danych, których kradzież byłaby poważnym problemem.
53. sessionStorage
API podobne:
sessionStorage.setItem("tab", "products");
Dane istnieją tylko dla danej sesji karty/przeglądarki.
54. Moduły
math.js:
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
main.js:
import { add, subtract } from "./math.js";
console.log(add(2, 3));
55. Default export
export default function render() {
console.log("Render");
}
Import:
import render from "./render.js";
56. Sensowna organizacja modułów
src/
├── main.js
├── api/
│ └── products.js
├── components/
│ ├── modal.js
│ └── product-card.js
├── utils/
│ ├── format-price.js
│ └── debounce.js
└── state/
└── store.js
Nie rób od razu architektury korporacyjnej.
Dziel kod wtedy, gdy:
- plik zaczyna być nieczytelny,
- dana funkcja ma osobną odpowiedzialność,
- coś chcesz użyć w kilku miejscach.
57. Klasy
JavaScript obsługuje klasy:
class User {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Cześć ${this.name}`);
}
}
const user = new User("Anna");
user.greet();
Dziedziczenie:
class Admin extends User {
deleteUser() {
console.log("Usuwam użytkownika");
}
}
W codziennym froncie często pracuje się jednak równie dobrze lub lepiej z:
- funkcjami,
- modułami,
- prostymi obiektami,
- kompozycją.
Nie musisz budować wszystkiego jako klasy.
58. Najważniejsze metody tablic
Załóżmy:
const products = [
{ id: 1, name: "Laptop", price: 5000 },
{ id: 2, name: "Monitor", price: 1500 },
{ id: 3, name: "Mysz", price: 200 }
];
map
Tworzy nową tablicę:
const names = products.map(product => product.name);
filter
const cheap = products.filter(product => product.price < 2000);
find
const monitor = products.find(product => product.id === 2);
some
const hasExpensive = products.some(product => product.price > 4000);
every
const allPositive = products.every(product => product.price > 0);
reduce
const total = products.reduce(
(sum, product) => sum + product.price,
0
);
sort
Uwaga: sort() mutuje tablicę.
products.sort((a, b) => a.price - b.price);
Jeśli nie chcesz mutować:
const sorted = [...products].sort(
(a, b) => a.price - b.price
);
59. Mutacja i niemutowalność
Mutacja:
user.name = "Adam";
Niemutowalne utworzenie nowego obiektu:
const updatedUser = {
...user,
name: "Adam"
};
W zwykłym JavaScript obie techniki są legalne.
W React niemutowalne aktualizacje stanu są bardzo ważne.
60. Event loop - podstawy
JavaScript w przeglądarce wykonuje kod zasadniczo na jednym głównym wątku.
Przykład:
console.log("A");
setTimeout(() => {
console.log("B");
}, 0);
console.log("C");
Wynik:
A
C
B
Dlaczego?
setTimeout nie wykonuje callbacku natychmiast.
Callback trafia do kolejki i zostaje wykonany dopiero, gdy bieżący stos wywołań jest pusty.
61. Promise a timer
console.log("A");
Promise.resolve().then(() => {
console.log("Promise");
});
setTimeout(() => {
console.log("Timer");
}, 0);
console.log("B");
Typowy wynik:
A
B
Promise
Timer
Callbacki Promise trafiają do kolejki mikro-zadań, która ma wyższy priorytet niż timer.
Nie musisz znać całej specyfikacji event loop, ale warto rozumieć, że:
async !== osobny magiczny wątek
62. Node.js
Node.js pozwala wykonywać JavaScript poza przeglądarką.
W nowoczesnym froncie jest potrzebny głównie do:
- uruchamiania npm,
- Vite,
- bundlerów,
- frameworków,
- narzędzi developerskich,
- testów,
- buildów.
Nie oznacza to automatycznie, że backend musi być napisany w Node.
Możesz mieć:
frontend: JavaScript / React / Vue
backend: Go
i jest to absolutnie normalne.
63. Środowisko - stan na 2026
Na moment przygotowania tego kompendium bezpiecznym wyborem do pracy developerskiej jest:
Node.js 24 LTS
npm
Vite
Sprawdzenie:
node --version
npm --version
Node 24 jest obecnie linią LTS.
Nie ma potrzeby używania najnowszego Node „Current”, jeśli nie potrzebujesz nowych funkcji.
64. npm
npm to menedżer pakietów.
Inicjalizacja projektu:
npm init
Szybciej:
npm init -y
Instalacja biblioteki:
npm install axios
Zależność developerska:
npm install --save-dev eslint
Usunięcie:
npm uninstall axios
Aktualizacja:
npm update
65. Vite
Dla zwykłego projektu Vanilla JS:
npm create vite@latest
W kreatorze wybierz:
Vanilla
JavaScript
Potem:
cd projekt
npm install
npm run dev
Vite uruchomi lokalny serwer developerski.
Build produkcyjny:
npm run build
Zwykle wynik trafi do:
dist/
Podgląd buildu:
npm run preview
66. Vite bez kreatora
Możesz utworzyć projekt bez pytań:
npm create vite@latest my-app -- --template vanilla
React:
npm create vite@latest my-react-app -- --template react
Vue:
npm create vite@latest my-vue-app -- --template vue
67. Typowa struktura Vite
my-app/
├── index.html
├── package.json
├── package-lock.json
├── node_modules/
├── public/
└── src/
├── main.js
└── style.css
node_modules:
- może być duży,
- nie wrzucamy go do Git.
.gitignore:
node_modules/
dist/
.env
.env.*
68. package.json
Przykład:
{
"name": "my-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^7.0.0"
}
}
Najważniejsze sekcje:
scripts
dependencies
devDependencies
Uruchomienie skryptu:
npm run dev
npm run build
69. dependencies vs devDependencies
dependencies
Biblioteki potrzebne aplikacji.
Przykład:
react
vue
pixi.js
devDependencies
Narzędzia potrzebne głównie podczas developmentu.
Przykład:
vite
eslint
prettier
vitest
W nowoczesnych buildach granica nie zawsze oznacza „czy kod trafi do przeglądarki”, ale semantycznie taki podział nadal jest użyteczny.
70. Import biblioteki z npm
Instalacja:
npm install lodash-es
Kod:
import { debounce } from "lodash-es";
To właśnie bundler/dev server rozwiązuje import po nazwie pakietu.
Bez bundlera przeglądarka nie wie automatycznie, gdzie znajduje się:
"lodash-es"
71. DevTools
W Chrome/Edge/Firefox otwórz narzędzia developerskie.
Najważniejsze zakładki:
Elements
Console
Sources
Network
Application
Performance
72. Console
console.log(value);
console.warn(value);
console.error(value);
console.table(array);
console.table jest bardzo wygodne dla tablic obiektów:
console.table(products);
73. Breakpoint
Zamiast miliona console.log możesz zatrzymać program.
W DevTools -> Sources kliknij numer linii.
Albo wpisz:
debugger;
Przeglądarka zatrzyma wykonanie, jeśli DevTools są otwarte.
74. Network
Zakładka Network pokazuje:
- requesty HTTP,
- odpowiedzi,
- statusy,
- nagłówki,
- payload,
- czas,
- CORS,
- błędy ładowania.
Jeśli fetch() „nie działa”, Network jest jednym z pierwszych miejsc do sprawdzenia.
75. Application
Przydatna do:
- localStorage,
- sessionStorage,
- cookies,
- cache,
- service workers.
76. Struktura małego projektu Vanilla JS
Przykład:
promo-auditor/
├── index.html
├── package.json
├── public/
└── src/
├── main.js
├── style.css
├── api.js
├── render.js
└── utils.js
main.js:
import { loadPromotions } from "./api.js";
import { renderPromotions } from "./render.js";
async function init() {
const promotions = await loadPromotions();
renderPromotions(promotions);
}
init();
api.js:
export async function loadPromotions() {
const response = await fetch("/api/promotions");
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
render.js:
export function renderPromotions(promotions) {
const list = document.querySelector("#promotions");
list.replaceChildren();
for (const promo of promotions) {
const item = document.createElement("li");
item.textContent = promo.title;
list.append(item);
}
}
To już jest pełnoprawna mała aplikacja.
77. Kompletny przykład Vanilla JS - lista zadań
HTML
<!doctype html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
>
<title>Todo</title>
<link rel="stylesheet" href="/src/style.css">
</head>
<body>
<main>
<h1>Todo</h1>
<form id="todoForm">
<input
id="todoInput"
name="title"
placeholder="Nowe zadanie"
required
>
<button>Dodaj</button>
</form>
<ul id="todoList"></ul>
</main>
<script type="module" src="/src/main.js"></script>
</body>
</html>
JavaScript
const form = document.querySelector("#todoForm");
const input = document.querySelector("#todoInput");
const list = document.querySelector("#todoList");
let todos = loadTodos();
function loadTodos() {
return JSON.parse(
localStorage.getItem("todos") ?? "[]"
);
}
function saveTodos() {
localStorage.setItem(
"todos",
JSON.stringify(todos)
);
}
function addTodo(title) {
todos.push({
id: crypto.randomUUID(),
title,
done: false
});
saveTodos();
render();
}
function toggleTodo(id) {
todos = todos.map(todo => {
if (todo.id !== id) {
return todo;
}
return {
...todo,
done: !todo.done
};
});
saveTodos();
render();
}
function removeTodo(id) {
todos = todos.filter(
todo => todo.id !== id
);
saveTodos();
render();
}
function render() {
list.replaceChildren();
for (const todo of todos) {
const li = document.createElement("li");
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = todo.done;
checkbox.addEventListener("change", () => {
toggleTodo(todo.id);
});
const text = document.createElement("span");
text.textContent = todo.title;
if (todo.done) {
text.classList.add("done");
}
const removeButton =
document.createElement("button");
removeButton.textContent = "Usuń";
removeButton.addEventListener("click", () => {
removeTodo(todo.id);
});
li.append(
checkbox,
text,
removeButton
);
list.append(li);
}
}
form.addEventListener("submit", event => {
event.preventDefault();
const title = input.value.trim();
if (!title) {
return;
}
addTodo(title);
form.reset();
input.focus();
});
render();
To ćwiczenie wykorzystuje:
- DOM,
- eventy,
- formularz,
- tablice,
- obiekty,
map,filter,- localStorage,
- renderowanie UI,
- stan aplikacji.
Jeżeli rozumiesz ten przykład, masz już praktyczne podstawy front-endowego JavaScriptu.
78. Kiedy Vanilla JS wystarcza
Vanilla JS jest bardzo dobry dla:
- prostych stron firmowych,
- landing pages,
- kalkulatorów,
- formularzy,
- małych paneli,
- widgetów,
- modalów,
- galerii,
- wyszukiwarek,
- filtrów,
- integracji z backendem Go,
- wewnętrznych narzędzi,
- prostych dashboardów.
Nie zaczynaj automatycznie od Reacta.
Jeżeli aplikacja ma:
3 przyciski
formularz
modal
fetch
listę wyników
to Vanilla JS może być wszystkim, czego potrzebujesz.
79. Po co framework
Problem pojawia się, gdy UI składa się z wielu zależnych elementów.
Przykład:
filtry
sortowanie
paginated list
modal
koszyk
liczniki
routing
formularze
komponenty
wiele ekranów
stan użytkownika
Wtedy ręczne:
querySelector(...)
element.textContent = ...
element.classList...
zaczyna być trudniejsze do utrzymania.
Framework pozwala opisywać:
jak UI ma wyglądać dla danego stanu
zamiast ręcznie sterować każdą zmianą DOM.
80. React - czym jest
React jest biblioteką do budowania interfejsów z komponentów.
Komponent:
function Hello() {
return <h1>Cześć</h1>;
}
React wykorzystuje JSX.
JSX wygląda jak HTML, ale jest składnią JavaScriptu.
81. Utworzenie projektu React + Vite
Do nauki klientowego Reacta bardzo wygodny jest Vite:
npm create vite@latest my-react-app -- --template react
Potem:
cd my-react-app
npm install
npm run dev
Create React App jest rozwiązaniem historycznym i nie powinien być bazą nowego kursu.
82. Podstawowa struktura React
src/
├── App.jsx
├── main.jsx
└── index.css
main.jsx:
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";
createRoot(
document.getElementById("root")
).render(
<StrictMode>
<App />
</StrictMode>
);
83. Komponent React
function ProductCard() {
return (
<article>
<h2>Laptop</h2>
<p>5000 zł</p>
</article>
);
}
export default ProductCard;
84. Props
function ProductCard({ name, price }) {
return (
<article>
<h2>{name}</h2>
<p>{price} zł</p>
</article>
);
}
Użycie:
<ProductCard
name="Monitor"
price={1500}
/>
Props to dane przekazane z komponentu rodzica.
85. State - useState
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<button
onClick={() => setCount(count + 1)}
>
Kliknięcia: {count}
</button>
);
}
Nie robisz:
count++;
Stan aktualizujesz przez setter:
setCount(...)
86. Renderowanie warunkowe
function Account({ loggedIn }) {
if (!loggedIn) {
return <p>Zaloguj się</p>;
}
return <p>Witaj!</p>;
}
Lub:
{loggedIn ? <Dashboard /> : <Login />}
87. Listy w React
const products = [
{ id: 1, name: "Laptop" },
{ id: 2, name: "Monitor" }
];
function ProductList() {
return (
<ul>
{products.map(product => (
<li key={product.id}>
{product.name}
</li>
))}
</ul>
);
}
key powinien być stabilnym identyfikatorem.
88. Formularz React
import { useState } from "react";
function Search() {
const [query, setQuery] = useState("");
function submit(event) {
event.preventDefault();
console.log(query);
}
return (
<form onSubmit={submit}>
<input
value={query}
onChange={event =>
setQuery(event.target.value)
}
/>
<button>Szukaj</button>
</form>
);
}
89. useEffect
Przykład:
import { useEffect, useState } from "react";
function Products() {
const [products, setProducts] = useState([]);
useEffect(() => {
async function load() {
const response =
await fetch("/api/products");
const data = await response.json();
setProducts(data);
}
load();
}, []);
return (
<ul>
{products.map(product => (
<li key={product.id}>
{product.name}
</li>
))}
</ul>
);
}
Nie traktuj useEffect jako miejsca na dowolny kod.
Używamy go głównie do synchronizacji komponentu ze światem zewnętrznym:
- request,
- timer,
- event listener,
- API przeglądarki,
- biblioteka zewnętrzna.
90. React - kiedy
Dobry wybór, jeśli:
- aplikacja jest mocno komponentowa,
- UI ma sporo stanu,
- chcesz duży ekosystem,
- zależy Ci na znajomości bardzo popularnej technologii,
- aplikacja może się rozrosnąć.
Dla zwykłej strony firmowej React często nie jest konieczny.
91. Vue - czym jest
Vue jest frameworkiem do budowy interfejsów.
Jest często bardziej zbliżony składniowo do klasycznego HTML niż React.
Typowy komponent .vue:
<script setup>
import { ref } from "vue";
const count = ref(0);
</script>
<template>
<button @click="count++">
Kliknięcia: {{ count }}
</button>
</template>
<style scoped>
button {
font-weight: bold;
}
</style>
92. Utworzenie Vue
Oficjalny generator:
npm create vue@latest
Potem:
cd nazwa-projektu
npm install
npm run dev
Vue wykorzystuje obecnie bardzo naturalnie:
Composition API
<script setup>
Single File Components
Vite
93. ref
<script setup>
import { ref } from "vue";
const name = ref("Anna");
function changeName() {
name.value = "Adam";
}
</script>
<template>
<p>{{ name }}</p>
<button @click="changeName">
Zmień
</button>
</template>
W <script>:
name.value
W template:
{{ name }}
Vue automatycznie rozpakowuje ref.
94. computed
<script setup>
import { computed, ref } from "vue";
const firstName = ref("Anna");
const lastName = ref("Kowalski");
const fullName = computed(() => {
return `${firstName.value} ${lastName.value}`;
});
</script>
<template>
<p>{{ fullName }}</p>
</template>
95. Warunki Vue
<p v-if="loggedIn">
Witaj
</p>
<p v-else>
Zaloguj się
</p>
96. Pętle Vue
<ul>
<li
v-for="product in products"
:key="product.id"
>
{{ product.name }}
</li>
</ul>
97. Eventy Vue
<button @click="save">
Zapisz
</button>
To skrót od:
<button v-on:click="save">
98. Binding Vue
<img :src="imageUrl" :alt="title">
To skrót od:
v-bind:src
99. v-model
<script setup>
import { ref } from "vue";
const query = ref("");
</script>
<template>
<input v-model="query">
<p>Szukasz: {{ query }}</p>
</template>
Bardzo wygodne dla formularzy.
100. Vue - kiedy
Dobry wybór, jeśli:
- chcesz framework komponentowy,
- lubisz HTML-ową składnię template,
- chcesz prosty start,
- budujesz małe lub średnie SPA,
- nie potrzebujesz ciężkiej struktury Angulara.
Dla człowieka dobrze znającego HTML i CSS Vue często wchodzi bardzo naturalnie.
101. Angular - czym jest
Angular jest pełnym frameworkiem aplikacyjnym.
Daje m.in.:
- komponenty,
- routing,
- dependency injection,
- formularze,
- narzędzia CLI,
- testy,
- TypeScript,
- strukturę aplikacji.
Jest bardziej opiniotwórczy niż React lub Vue.
102. Utworzenie Angulara
Instalacja CLI:
npm install -g @angular/cli
Nowy projekt:
ng new my-app
Uruchomienie:
cd my-app
npm start
albo:
ng serve --open
Domyślny adres developerski:
http://localhost:4200
103. Współczesny Angular i standalone components
Nowoczesny Angular używa domyślnie standalone APIs.
Przykład:
import { Component } from "@angular/core";
@Component({
selector: "app-root",
standalone: true,
template: `
<h1>Hello Angular</h1>
`
})
export class App {}
Nie musisz na starcie uczyć się starego modelu opartego wszędzie na NgModule.
W starych projektach nadal go spotkasz.
104. Angular i sygnały
Przykład:
import {
Component,
signal
} from "@angular/core";
@Component({
selector: "app-counter",
standalone: true,
template: `
<button (click)="increment()">
{{ count() }}
</button>
`
})
export class Counter {
count = signal(0);
increment() {
this.count.update(
value => value + 1
);
}
}
105. Angular template
Warunek:
@if (loggedIn()) {
<p>Witaj</p>
} @else {
<p>Zaloguj się</p>
}
Pętla:
@for (product of products(); track product.id) {
<p>{{ product.name }}</p>
}
106. Generowanie komponentu
ng generate component product-card
Skrót:
ng g c product-card
CLI jest istotną częścią pracy z Angularem.
107. Angular - kiedy
Angular ma sens, gdy:
- aplikacja jest większa,
- zespół chce narzuconej struktury,
- projekt ma dużo formularzy, routingu i usług,
- chcesz gotową architekturę,
- TypeScript jest standardem od początku.
Do:
landing page + modal + formularz
Angular byłby najczęściej przerostem formy nad treścią.
108. React vs Vue vs Angular
Vanilla JS
Najmniej warstw.
Dobre do:
- stron,
- widgetów,
- małych aplikacji,
- integracji z backendem.
React
Najbardziej „JavaScriptowe” podejście.
Duży ekosystem.
JSX.
Dobre dla komponentowych aplikacji.
Vue
Bardzo przyjazne połączenie:
HTML + JS + CSS
Dobry próg wejścia.
Angular
Pełny framework.
Najwięcej struktury.
Najwięcej rzeczy dostajesz w jednym ekosystemie.
109. Czy trzeba znać wszystkie trzy?
Nie.
Trzeba rozumieć:
- Vanilla JS,
- DOM,
- eventy,
- moduły,
- async,
- API,
- npm,
- Vite.
Następnie dobrze znać jeden framework komponentowy.
Pozostałe wystarczy początkowo rozumieć na poziomie:
co robią
jak wygląda komponent
jak uruchomić projekt
jak działa stan
110. PixiJS
PixiJS jest biblioteką/rendering engine do grafiki 2D.
Nadaje się do:
- animacji,
- gier 2D,
- interaktywnych wizualizacji,
- efektów graficznych,
- aplikacji działających na canvas,
- bardzo dynamicznych scen.
Nie służy jako zamiennik zwykłego HTML/CSS dla strony firmowej.
111. Instalacja PixiJS
Nowy projekt:
npm create pixi.js@latest
Dokumentacja PixiJS rekomenduje m.in. wariant oparty na Vite.
Można też dodać PixiJS do projektu:
npm install pixi.js
112. Minimalny PixiJS 8
import { Application } from "pixi.js";
async function main() {
const app = new Application();
await app.init({
width: 800,
height: 600,
backgroundColor: 0x202020
});
document.body.appendChild(app.canvas);
}
main();
W PixiJS 8 inicjalizacja aplikacji jest asynchroniczna.
113. Grafika w PixiJS
Przykład:
import {
Application,
Graphics
} from "pixi.js";
async function main() {
const app = new Application();
await app.init({
resizeTo: window
});
document.body.appendChild(app.canvas);
const square = new Graphics()
.rect(0, 0, 100, 100)
.fill(0xff0000);
square.x = 100;
square.y = 100;
app.stage.addChild(square);
}
main();
114. Animacja PixiJS
app.ticker.add(ticker => {
square.rotation +=
0.01 * ticker.deltaTime;
});
Ticker wykonuje funkcję dla kolejnych klatek renderowania.
115. Interakcja PixiJS
Ogólny schemat:
sprite.eventMode = "static";
sprite.on("pointerdown", () => {
console.log("Klik");
});
Dzięki pointer events jedna logika może obsługiwać mysz i dotyk.
116. HTML czy PixiJS?
Używaj HTML/CSS dla:
- tekstu,
- formularzy,
- menu,
- artykułów,
- SEO,
- standardowej nawigacji,
- dostępności.
PixiJS dla:
- sceny,
- animacji,
- sprite'ów,
- dużej liczby obiektów graficznych,
- grafiki działającej jak gra.
Można połączyć:
HTML UI
+
PixiJS canvas
To bardzo normalny układ.
117. TypeScript
TypeScript to JavaScript z systemem typów.
JavaScript:
function add(a, b) {
return a + b;
}
TypeScript:
function add(
a: number,
b: number
): number {
return a + b;
}
118. Obiekt TypeScript
interface Product {
id: number;
name: string;
price: number;
}
function renderProduct(
product: Product
) {
console.log(product.name);
}
119. Czy uczyć się TypeScript od razu?
Najpierw musisz rozumieć JavaScript.
Potem TypeScript jest bardzo dobrym krokiem.
Proponowana kolejność:
HTML
CSS
JavaScript
DOM
async/fetch
moduły
npm/Vite
framework
TypeScript
Jeśli zaczniesz TS przed zrozumieniem JS, będziesz rozwiązywał błędy typów bez zrozumienia działania języka.
120. Testy jednostkowe
Dla projektu Vite popularnym wyborem jest Vitest.
Instalacja:
npm install -D vitest
Przykład funkcji:
export function add(a, b) {
return a + b;
}
Test:
import {
describe,
expect,
it
} from "vitest";
import { add } from "./math.js";
describe("add", () => {
it("dodaje liczby", () => {
expect(add(2, 3)).toBe(5);
});
});
121. Testy E2E
Do automatycznego sterowania przeglądarką można używać np. Playwright.
Test E2E sprawdza aplikację podobnie jak użytkownik:
otwórz stronę
kliknij
wpisz tekst
sprawdź wynik
Dla małych prywatnych projektów nie musisz od razu tworzyć ogromnej infrastruktury testowej.
Ale krytyczna logika powinna być możliwie testowalna.
122. ESLint
ESLint analizuje kod i wykrywa problemy.
Instalacja zależy od konfiguracji projektu.
Ogólnie jego rola to:
linting
wykrywanie błędów
pilnowanie reguł kodu
123. Prettier
Prettier formatuje kod.
Przykład:
const foo={a:1,b:2}
może zamienić na:
const foo = {
a: 1,
b: 2,
};
ESLint i Prettier rozwiązują inne problemy:
ESLint -> jakość i reguły kodu
Prettier -> formatowanie
124. Bezpieczeństwo - najważniejsze zasady
Nie ufaj inputowi
Nigdy nie zakładaj, że dane użytkownika są poprawne.
Frontendowa walidacja poprawia UX.
Backend musi walidować dane ponownie.
125. XSS
Nie rób:
result.innerHTML = userInput;
Bezpieczniej:
result.textContent = userInput;
Jeśli naprawdę musisz renderować HTML z niezaufanego źródła, trzeba go poprawnie sanityzować.
126. Klucze API
Kod front-endowy jest dostępny użytkownikowi.
Jeżeli wpiszesz:
const SECRET_KEY = "abc123";
to klucz nie jest sekretem.
.env w projekcie frontendowym również nie robi z wartości sekretu, jeżeli finalnie jest wstrzykiwana do kodu przeglądarkowego.
Sekretne klucze trzymaj po stronie backendu.
Schemat:
Browser
|
v
Twój backend
|
v
zewnętrzne API
127. CORS
CORS to mechanizm przeglądarki kontrolujący requesty między originami.
Jeżeli frontend:
https://app.example.com
odpytuje:
https://api.other.com
serwer API musi pozwolić na taki request.
CORS nie naprawia się po stronie frontendu magicznym nagłówkiem.
128. Dostępność
Interaktywny element powinien być semantyczny.
Dobrze:
<button id="save">
Zapisz
</button>
Gorzej:
<div id="save">
Zapisz
</div>
z listenerem kliknięcia.
button dostaje automatycznie:
- fokus,
- obsługę klawiatury,
- semantykę,
- zachowanie oczekiwane przez użytkownika.
129. ARIA
Używaj wtedy, gdy HTML nie wystarcza.
Np. przy przycisku otwierającym panel:
<button
aria-expanded="false"
aria-controls="menu"
>
Menu
</button>
JS:
button.setAttribute(
"aria-expanded",
String(open)
);
Najpierw semantyczny HTML, potem ARIA.
130. Wydajność
Dla zwykłej strony największe zyski często daje nie „super algorytm”, lecz:
- mniej JS,
- mniejsze obrazy,
- lazy loading,
- nieładowanie niepotrzebnych bibliotek,
- dzielenie kodu,
- rozsądny DOM,
- unikanie setek niepotrzebnych listenerów,
- unikanie niepotrzebnego renderowania.
131. Debounce
Przydatny np. w wyszukiwaniu podczas wpisywania.
Bez debounce:
k
ka
kar
karo
user
może wykonać 5 requestów.
Debounce czeka chwilę od ostatniego inputu.
Przykład:
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn(...args);
}, delay);
};
}
const search = debounce(query => {
console.log("Szukam:", query);
}, 300);
132. Dynamiczny import
Możesz załadować moduł dopiero, gdy jest potrzebny.
button.addEventListener(
"click",
async () => {
const module =
await import("./heavy-module.js");
module.openEditor();
}
);
To może pomóc zmniejszyć początkowy bundle.
133. Nie używaj frameworka tylko dlatego, że istnieje
Zła motywacja:
To jest strona, więc zrobię React.
Lepsza:
Czy stan i liczba komponentów są na tyle złożone,
że framework uprości projekt?
134. Nie buduj SPA, jeśli jej nie potrzebujesz
Jeśli strona to:
Home
O nas
Kontakt
3 artykuły
nie musisz budować skomplikowanego klientowego routera.
Klasyczny HTML generowany przez backend + trochę JS może być:
- prostszy,
- szybszy,
- łatwiejszy w SEO,
- łatwiejszy w utrzymaniu.
135. JavaScript z backendem Go
Przykładowa architektura:
Browser
|
| GET /
v
Go server
|
| HTML/CSS/JS
v
Browser
Browser
|
| fetch("/api/promotions")
v
Go API
|
| JSON
v
Browser
Frontend:
const response =
await fetch("/api/promotions");
const promotions =
await response.json();
Go może służyć:
- HTML,
- statyczne assety,
- API JSON.
Nie musisz przerabiać backendu na Node tylko dlatego, że używasz nowoczesnego front-endu.
136. Mój praktyczny podział technologii
Poziom 1 - zwykła interaktywna strona
HTML
CSS
Vanilla JS
ES modules
fetch
Poziom 2 - nowoczesne środowisko
Node LTS
npm
Vite
ESLint
Poziom 3 - aplikacja komponentowa
Wybierz jeden:
React
Vue
Angular
Poziom 4 - typowanie
TypeScript
Poziom 5 - grafika specjalna
PixiJS
Canvas
WebGL/WebGPU
137. Co wybrałabym do typowych małych projektów
Prosty widget / formularz / narzędzie wewnętrzne
Vanilla JS + Vite
Mała aplikacja z wieloma komponentami
Vue lub React
Projekt, w którym chcesz mocno rozwijać kompetencję rynkową
React + TypeScript
Duży panel biznesowy ze ścisłą strukturą
Angular + TypeScript
Wizualizacja / gra / animowany canvas
PixiJS
138. Jak naprawdę uczyć się JavaScriptu
Nie ucz się przez czytanie samej składni.
Po każdej grupie tematów napisz coś działającego.
Przykład:
Po zmiennych, warunkach i funkcjach
Kalkulator.
Po DOM
Menu i modal.
Po formularzach
Walidator formularza.
Po tablicach
Filtr produktów.
Po localStorage
Todo list.
Po fetch
Wyszukiwarka danych z API.
Po modułach
Rozbij projekt na kilka plików.
Po Vite
Zbuduj i wypuść produkcyjny dist/.
Po frameworku
Przepisz jeden wcześniejszy projekt.
To daje znacznie więcej niż 50 godzin oglądania tutoriali.
139. Proponowana ścieżka - etap 1
Opanuj bardzo dobrze:
const / let
string / number / boolean
array
object
if
for
function
arrow function
map
filter
find
destructuring
spread
Cel:
umiesz przekształcać dane bez patrzenia co chwilę do dokumentacji.
140. Etap 2 - przeglądarka
Opanuj:
querySelector
querySelectorAll
textContent
classList
dataset
createElement
append
remove
addEventListener
preventDefault
FormData
Cel:
potrafisz stworzyć stronę reagującą na użytkownika.
141. Etap 3 - asynchroniczność
Opanuj:
Promise
async
await
fetch
try/catch
response.ok
JSON
Cel:
potrafisz pobrać dane z backendu i pokazać loading/error/success.
142. Etap 4 - organizacja kodu
Opanuj:
import
export
moduły
foldery
separację odpowiedzialności
Cel:
projekt nie jest jednym script.js mającym 2500 linii.
143. Etap 5 - tooling
Opanuj:
Node
npm
package.json
Vite
npm run dev
npm run build
.gitignore
DevTools
Cel:
potrafisz samodzielnie postawić środowisko.
144. Etap 6 - framework
Najpierw wybierz jeden.
Moja praktyczna kolejność nauki:
1. Vanilla JS
2. React albo Vue
3. TypeScript
4. drugi framework tylko jeśli jest potrzebny
5. Angular, jeśli projekt/praca go wymaga
6. PixiJS jako osobna specjalizacja
Nie próbuj „opanować Reacta, Vue i Angulara naraz”.
To są trzy sposoby rozwiązania podobnego problemu.
145. Projekt ćwiczeniowy 1 - FAQ
Funkcje:
- lista pytań,
- kliknięcie rozwija odpowiedź,
- tylko jedna odpowiedź otwarta,
aria-expanded,- animacja CSS.
Ćwiczysz:
DOM
eventy
classList
dataset
dostępność
146. Projekt 2 - kalkulator ceny
Funkcje:
- input liczby,
- select,
- checkboxy,
- dynamiczne podsumowanie,
- formatowanie PLN.
Ćwiczysz:
formularze
Number
warunki
funkcje
Intl.NumberFormat
147. Projekt 3 - Todo
Funkcje:
- dodawanie,
- usuwanie,
- oznaczanie jako wykonane,
- filtry,
- localStorage.
Ćwiczysz:
state
render
array
map
filter
localStorage
148. Projekt 4 - wyszukiwarka produktów
Funkcje:
- pobranie JSON,
- input search,
- debounce,
- sortowanie,
- filtrowanie,
- loading,
- error.
Ćwiczysz:
fetch
async
DOM
array methods
debounce
149. Projekt 5 - dashboard
Funkcje:
- kilka endpointów,
- karty statystyk,
- tabela,
- filtry,
- modal,
- odświeżanie.
Zrób najpierw w Vanilla JS.
Potem przepisz na:
React
albo:
Vue
Dopiero wtedy zobaczysz realną różnicę.
150. Projekt 6 - PixiJS
Zrób:
- canvas full screen,
- 100 sprite'ów,
- animację,
- hover,
- kliknięcie,
- prosty HUD w HTML.
Ćwiczysz połączenie:
HTML
CSS
DOM
PixiJS
animation loop
151. Projekt 7 - frontend do backendu Go
Backend:
GET /api/items
POST /api/items
DELETE /api/items/:id
Frontend:
- pobiera listę,
- dodaje element,
- usuwa element,
- pokazuje błędy.
To jest bardzo praktyczne ćwiczenie pod prawdziwe projekty.
152. Przydatne API przeglądarki
Warto wiedzieć, że istnieją:
fetch
localStorage
sessionStorage
URL
URLSearchParams
FormData
File
Blob
Clipboard API
IntersectionObserver
ResizeObserver
MutationObserver
WebSocket
EventSource
Web Workers
Geolocation
History API
Canvas
Web Audio
WebRTC
Nie ucz się wszystkich na pamięć.
Wiedz, że istnieją i wracaj do dokumentacji, gdy ich potrzebujesz.
153. URLSearchParams
Adres:
/products?q=laptop&page=2
Kod:
const params =
new URLSearchParams(location.search);
console.log(params.get("q"));
console.log(params.get("page"));
Ustawienie:
const params =
new URLSearchParams();
params.set("q", "laptop");
history.replaceState(
null,
"",
`?${params.toString()}`
);
154. Clipboard
await navigator.clipboard.writeText(
"Tekst do schowka"
);
155. IntersectionObserver
Przydatny do wykrywania, czy element pojawił się na ekranie.
const observer =
new IntersectionObserver(entries => {
for (const entry of entries) {
if (entry.isIntersecting) {
console.log("Widoczny");
}
}
});
observer.observe(
document.querySelector("#section")
);
Zastosowania:
- lazy loading,
- animacje,
- infinite scroll.
156. WebSocket
Dla połączenia dwukierunkowego w czasie rzeczywistym:
const socket =
new WebSocket("wss://example.com/ws");
socket.addEventListener(
"message",
event => {
console.log(event.data);
}
);
Nie potrzebujesz WebSocket do zwykłego request/response.
Do tego jest HTTP + fetch.
157. Custom events
Możesz tworzyć własne eventy:
const event =
new CustomEvent("cart:updated", {
detail: {
count: 3
}
});
document.dispatchEvent(event);
Nasłuch:
document.addEventListener(
"cart:updated",
event => {
console.log(event.detail.count);
}
);
Przydaje się czasem do komunikacji między niezależnymi fragmentami Vanilla JS.
158. Intl
Formatowanie waluty:
const formatPrice =
new Intl.NumberFormat("pl-PL", {
style: "currency",
currency: "PLN"
});
formatPrice.format(1234.56);
Daty:
const formatDate =
new Intl.DateTimeFormat(
"pl-PL",
{
dateStyle: "long"
}
);
formatDate.format(new Date());
Nie pisz własnego formatowania dat/walut bez potrzeby.
159. Daty
const now = new Date();
ISO:
const iso = now.toISOString();
Parsowanie:
const date =
new Date("2026-09-19T10:00:00Z");
Daty i strefy czasowe potrafią być skomplikowane.
W poważnej logice zawsze jasno ustal:
czy dana data jest lokalna
czy UTC
czy zawiera offset
160. crypto.randomUUID
Do prostych lokalnych identyfikatorów:
const id = crypto.randomUUID();
Nie zastępuje to logiki ID po stronie bazy danych, ale jest bardzo wygodne w UI.
161. Modułowa aplikacja - przykład
src/
├── main.js
├── api.js
├── storage.js
├── state.js
├── ui.js
└── utils.js
state.js:
export const state = {
products: [],
query: ""
};
api.js:
export async function fetchProducts() {
const response =
await fetch("/api/products");
if (!response.ok) {
throw new Error("API error");
}
return response.json();
}
ui.js:
export function renderProducts(
products
) {
const list =
document.querySelector("#list");
list.replaceChildren();
for (const product of products) {
const li =
document.createElement("li");
li.textContent =
product.name;
list.append(li);
}
}
main.js:
import {
fetchProducts
} from "./api.js";
import {
renderProducts
} from "./ui.js";
import {
state
} from "./state.js";
async function init() {
state.products =
await fetchProducts();
renderProducts(
state.products
);
}
init();
To jest już architektura wystarczająca dla wielu małych narzędzi.
162. Framework nie zastępuje JavaScriptu
React:
products
.filter(...)
.map(...)
Vue:
computed(() =>
products.value.filter(...)
);
Angular:
products().filter(...)
W każdym przypadku nadal używasz:
JavaScript
arrays
objects
functions
async
HTTP
modules
Dlatego najważniejszą inwestycją jest sam język.
163. Co trzeba znać „na pamięć”
Warto mieć w głowie:
const
let
if
for
function
=>
array
object
map
filter
find
querySelector
addEventListener
textContent
classList
fetch
async
await
try/catch
import/export
164. Czego nie trzeba pamiętać
Nie musisz pamiętać:
- wszystkich opcji
fetch, - wszystkich metod
Date, - całego DOM API,
- wszystkich hooków frameworka,
- pełnej składni konfiguracji Vite,
- każdego CLI switcha.
Od tego jest dokumentacja.
Dobry developer nie jest kompilatorem dokumentacji.
Dobry developer:
rozumie model
wie czego szukać
potrafi złożyć rozwiązanie
potrafi zdebugować problem
165. Minimalna codzienna ściąga
DOM
const el =
document.querySelector("#id");
const all =
document.querySelectorAll(".item");
el.textContent = "Hello";
el.classList.add("active");
el.addEventListener(
"click",
handler
);
API
const response =
await fetch("/api/data");
if (!response.ok) {
throw new Error(
`HTTP ${response.status}`
);
}
const data =
await response.json();
Tablice
items.map(...)
items.filter(...)
items.find(...)
items.some(...)
items.every(...)
Moduły
export function foo() {}
import {
foo
} from "./foo.js";
npm
npm install
npm run dev
npm run build
166. Szybka decyzja technologiczna
Zadaj pytania.
Czy strona potrzebuje tylko trochę interakcji?
Tak:
Vanilla JS
Czy UI ma wiele zależnych komponentów i dużo stanu?
Tak:
React lub Vue
Czy projekt wymaga dużej, mocno narzuconej architektury?
Tak:
Angular
Czy głównym problemem jest wydajna grafika 2D?
Tak:
PixiJS
167. Finalny cel
Po przerobieniu tego materiału powinieneś potrafić samodzielnie:
- stworzyć HTML,
- podłączyć JS,
- znaleźć element DOM,
- obsłużyć kliknięcie,
- odczytać formularz,
- zmienić UI,
- pracować z tablicą danych,
- pobrać dane przez API,
- obsłużyć błąd,
- zapisać stan lokalnie,
- podzielić kod na moduły,
- stworzyć projekt npm,
- odpalić Vite,
- zbudować
dist, - zdebugować kod w DevTools,
- stworzyć podstawowy komponent React/Vue/Angular,
- zrozumieć, po co framework istnieje,
- uruchomić prostą scenę PixiJS,
- podłączyć frontend pod backend Go,
- świadomie zdecydować, czy framework jest w ogóle potrzebny.
Jeżeli umiesz te rzeczy, JavaScript przestaje być „czymś doczepionym do HTML”, a staje się normalnym narzędziem pracy.
168. Oficjalne źródła
JavaScript i Web APIs
-
MDN JavaScript: https://developer.mozilla.org/docs/Web/JavaScript
-
MDN DOM: https://developer.mozilla.org/docs/Web/API/Document_Object_Model
-
MDN Fetch: https://developer.mozilla.org/docs/Web/API/Fetch_API
-
MDN
<script>: https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/script -
MDN JavaScript Modules: https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules
Node.js
- https://nodejs.org/
Vite
- https://vite.dev/guide/
React
-
https://react.dev/
-
React - installation: https://react.dev/learn/installation
-
React - build from scratch: https://react.dev/learn/build-a-react-app-from-scratch
Vue
-
https://vuejs.org/
-
Vue quick start: https://vuejs.org/guide/quick-start
Angular
-
https://angular.dev/
-
Angular installation: https://angular.dev/installation
PixiJS
-
https://pixijs.com/
-
PixiJS quick start: https://pixijs.com/8.x/guides/getting-started/quick-start
-
PixiJS Application: https://pixijs.com/8.x/guides/components/application
169. Najkrótsze podsumowanie całego kursu
JavaScript na stronie działa według bardzo prostego modelu:
1. Pobierz dane
2. Trzymaj stan
3. Reaguj na zdarzenia
4. Zmieniaj UI
W Vanilla JS robisz to ręcznie:
state.count++;
element.textContent =
state.count;
Framework robi część synchronizacji za Ciebie:
stan się zmienił
↓
framework aktualizuje UI
Dlatego kolejność nauki ma ogromne znaczenie:
JavaScript
↓
DOM
↓
events
↓
async / fetch
↓
modules
↓
npm / Vite
↓
React / Vue / Angular
↓
TypeScript
A PixiJS traktuj jako osobną warstwę do grafiki i animacji, nie jako zamiennik całego webowego stacku.
To wystarczy, żeby przejść od:
<script>
alert("hej");
</script>
do normalnej, modularnej, interaktywnej aplikacji webowej.
Oficjalne źródła
- ECMAScript specification: https://tc39.es/ecma262/
- MDN JavaScript Guide: https://developer.mozilla.org/docs/Web/JavaScript/Guide
- Vite documentation: https://vite.dev/guide/
- React: https://react.dev/
- Vue: https://vuejs.org/
- Angular: https://angular.dev/
- PixiJS: https://pixijs.com/