Co naprawdę robi npm install: rejestr, package.json i pliki Lockfile
Praktyczny przewodnik po npm: rejestrze i interfejsie wiersza poleceń, sposobie rozwiązywania problemów z pakietami przez npm install, tym, co rejestruje plik package.json i package-lock.json, oraz sposobie publikowania pakietów.
Prawie każdy projekt w JavaScript, niezależnie od tego, czy działa na Node.js, React czy Next.js, rozpoczyna się od tej samej komendy, a wielu programistów używa jej codziennie, nie mając jasnego pojęcia o tym, co ona robi. Znajomość źródeł pakietów, sposobu, w jaki npm decyduje o tym, co zainstalować, oraz tego, do czego służą pliki package.json, package-lock.json i node_modules, ułatwia debugowanie problemów z instalacją. Ten przewodnik omawia każdy aspekt, od pierwszej instalacji po publikację własnego pakietu.
Komendy, które wszyscy wpisują
Najbardziej powszechną formą jest instalacja wszystkiego, co projekt już deklaruje:
npm install
Równie częste jest dodawanie biblioteki pod jej nazwą, np. frameworku webowego Express:
npm install express
lub klienta HTTP Axios:
npm install axios
Za tymi jednolinijkami kryje się kilka pytań. Skąd pobierany jest kod? Skąd npm wie, od czego zależy projekt? Do czego służy plik package.json? I dlaczego katalog node_modules staje się tak duży?
Czym jest npm
npm to domyślny menedżer pakietów dla Node.js, który jest dołączany razem z nim. Umożliwia dostęp do ogromnego katalogu pakietów wielokrotnego użycia opublikowanych przez innych programistów, dzięki czemu możesz wykorzystać sprawdzone rozwiązania w swoim projekcie zamiast pisać je od zera.
Pomyśl o nim jako o publicznej bibliotece kodu. Załóżmy, że backend w Node.js potrzebuje serwera HTTP. Zamiast budować mechanizmy routingu i obsługi pośredników od podstaw, dodajesz Express:
npm install express
Chcesz korzystać z innych API? Dodaj klienta HTTP:
npm install axios
Walidację przychodzących danych według schematu zajmuje się Zod:
npm install zod
A bcrypt zajmuje się haszowaniem haseł:
npm install bcrypt
To jest największą zaletą ekosystemu: gdy istnieje dobrze przetestowane rozwiązanie, rzadko ma się powód, by tworzyć własne. Z drugiej strony każdy zainstalowany pakiet to kod, któremu teraz ufasz, dlatego warto wybierać utrzymywane, powszechnie używane biblioteki i utrzymywać spis w skromnych rozmiarach. Przeczytaj jak działają ataki łańcucha dostaw w npm, aby zrozumieć, dlaczego to ma znaczenie.
Ekosystem, a nie tylko polecenie
Początkujący często postrzegają npm jako zwykłe słowo wpisywane w terminalu. W rzeczywistości nazwa ta obejmuje kilka współpracujących elementów:
- Rejestr npm: publiczna usługa, z której publikowane i pobierane są pakiety.
- CLI npm: narzędzie wiersza poleceń, które komunikuje się z rejestratem i zarządza zależnościami.
package.json: plik manifestu opisujący twój projekt oraz elementy, od których zależy.Pakiety publiczne są bezpłatne: możesz zainstalować dowolny pakiet publiczny bez konieczności posiadania konta. Ta niska bariera przyczyniła się do rozprzestrzenienia się otwartego oprogramowania JavaScript na całym świecie. Konto jest potrzebne tylko w celu publikacji.
Co się dzieje, gdy uruchamiasz npm install
Weźmy projekt, który dodaje Express:
npm install express
Na poziomie ogólnym:
- npm szuka pakietu w rejestrze i wybiera wersję odpowiadającą podanemu zakresowi (najnowszą, jeśli żaden nie został określony).
- Rozwiązuje zależności samego pakietu oraz jego zależności, tworząc pełne drzewo struktury.
- Ładuje wszystko, co jeszcze nie jest zapisane w pamięci podręcznej, i umieszcza to w katalogu
node_modules.
package.json oraz dokładną strukturę rozwiązanych zależności w pliku package-lock.json.Tak więc jeden krótki polecenie umożliwia korzystanie z całej struktury funkcjonalności.
package.json: manifest projektu
W centrum każdego projektu Node.js znajduje się jeden plik:
package.json
Jest on jednocześnie dowodem tożsamości i konfiguracją projektu, zawierając nazwę, wersję, opis, skrypty, zależności do działania i rozwoju oraz dane autora. Minimalny przykład definiuje plik wejściowy o nazwie main, jeden skrypt oraz jedną zależność:
{
"name": "my-project",
"version": "1.0.0",
"description": "My Node.js application",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^5.1.0"
}
}
name
name identyfikuje projekt lub pakiet. Jeśli go publikujesz, to właśnie tę nazwę ludzie wpisują, aby go zainstalować, dlatego musi być unikalna w rejestrze.
"name": "my-project"
version
version zawiera aktualną wersję pakietu.
"version": "1.0.0"
Najważniejsze jest to podczas publikowania. npm używa wersjonowania semantycznego (MAJOR.MINOR.PATCH): zmiany zakłócające funkcjonowanie podnoszą numer główny, funkcje kompatybilne – numer drugorzędny, a poprawki – numer trzeci.
description
description to jednowierszowy opis tego, czym zajmuje się projekt, który jest wyświetlany w wynikach wyszukiwania w rejestrze.
"description": "My Node.js application"
scripts
scripts definiuje nazwane skróty dla często używanych poleceń. Tutaj start uruchamia plik wejściowy:
"scripts": {
"start": "node index.js"
}
Bez niego trzeba byłoby wpisać pełne polecenie:
node index.js
Z nim robi się to samo:
npm start
Wartością jest spójność: każdy współpracownik i każda zadań CI uruchamia to samo nazwane polecenie. Nazwy dostosowane, takie jak build, są wykonywane za pomocą npm run build.
Zależności: od czego zależy twój projekt
Załóżmy platformę dostaw jedzenia. Jej backend może wykorzystywać:
- Express do API
- Zod do walidacji
- bcrypt do haszowania haseł
- bibliotekę JSON Web Token do autoryzacji
- Mongoose do obsługi MongoDB
Każda z tych bibliotek to zależność. Gdy ją instalujesz:
npm install express
npm dodaje wpis do package.json:
"dependencies": {
"express": "^5.1.0"
}
Znak kierunkowy w ^5.1.0 oznacza zakres: akceptowane są wszystkie późniejsze wersje 5.x, natomiast 6.0.0 nie. Ten wpis informuje osoby przeglądające projekt, że do jego uruchomienia potrzebny jest Express. Narzędzia wymagane tylko podczas rozwoju, takie jak narzędzia do testowania, trafiają do devDependencies za pomocą polecenia npm install --save-dev.
Dlaczego jedno polecenie może być używane przez cały zespół
Załóżmy, że dołączasz do zespołu i klonujesz jego repozytorium. Nikt nie oczekuje, że sam pobierzesz pięćdziesiąt bibliotek ręcznie. Wystarczy wykonać:
npm install
npm odczytuje deklarowane zależności i instaluje je wszystkie. To właśnie dzięki możliwości odbudowy środowiska programistycznego na podstawie jego opisu menedżery pakietów są niezbędne.
node_modules: miejsce, gdzie znajduje się zainstalowany kod
Po instalacji pojawia się nowa folder:
node_modules/
Zawiera on pakety, o które prosiłeś, oraz wszystko, od czego one zależą, dlatego też staje się duży. Typowa struktura:
my-project/
│
├── node_modules/
├── package.json
├── package-lock.json
└── index.js
Nie komituj pliku node_modules do Git. Jest on duży, może zawierać wersje specyficzne dla danej platformy i zawsze można go odtworzyć. Umieść go w pliku .gitignore i zamiast tego komituj te pliki:
package.json
package-lock.json
Każdy inny użytkownik może wtedy uruchomić:
npm install
i otrzymać te same zależności.
package-lock.json: dokładny zapis
Obok pliku manifestu znajduje się drugi plik:
package-lock.json
Dlaczego oba pliki? Krótka wersja:
package.jsonokreśla, czego potrzebuje projekt, zazwyczaj w postaci zakresów.package-lock.jsonrejestruje dokładnie to, co zostało zainstalowane: każdą wersję pakietu w całym drzewie, plus hashe integralności.
Ponieważ zakresy mogą z czasem odpowiadać nowszym wersjom, plik lockfile zapewnia, że laptopy, współpracownicy i systemy CI używają identycznych wersji. Zapisz go i w systemach CI preferuj npm ci, który instaluje pakiety ściśle na podstawie pliku lockfile.
Komendy npm, które warto znać
Dodanie pakietu:
npm install express
Zainstaluj wszystko, co deklaruje projekt:
npm install
Usuń pakiet z node_modules i package.json:
npm uninstall express
Zaktualizuj pakiety do najnowszych wersji, na które pozwalają zakresy (nie będzie to dotyczyć większych wersji):
npm update
Wyświetl wersję npm:
npm -v
Wyświetl wersję Node.js:
node -v
Pokaż konto npm, pod którym jesteś zalogowany:
npm whoami
Od użytkownika do wydawcy
Możesz również przyczyniać się do tworzenia pakietów. Opublikuj przydatną bibliotekę, a inni będą mogli ją zainstalować jak każdą inną:
npm install your-package
To pętlenie utrzymuje otwarty kod żywy: budujesz na pracach innych, tworzysz własne rozwiązania i dzielisz się nimi.
Kroki publikacji krok po kroku
Potrzebujesz konta npm. Zaloguj się z terminala:
npm login
Potwierdź, które konto jest aktywne:
npm whoami
Przejdź do projektu:
cd myproject
Upewnij się, że posiada on ważny plik manifestu z unikalną wartością name oraz version:
package.json
Następnie opublikuj:
npm publish
Pakiet jest teraz dostępny dla wszystkich. Dwa wskazówki: najpierw uruchom npm pack --dry-run, aby zobaczyć, które pliki zostaną dołączone, oraz zwiększaj version przy każdym wydaniu, ponieważ opublikowana wersja nie może być ponownie użyta. Sprawdź aktualne dokumentacje npm dotyczące wymagań bezpieczeństwa kont, takich jak dwufaktorowa autoryzacja.
Jak wszystko się łączy
Cały proces wygląda w ten sposób:
Developer
↓
npm install
↓
npm Registry
↓
Package + Dependencies
↓
node_modules
↓
package.json
↓
Your Application
Uruchamiasz polecenie, CLI pobiera pakiety z rejestru, kod trafia do katalogu node_modules, manifest i plik lockfile to rejestrują, a twoja aplikacja go importuje. To właśnie ta łańcuchowa struktura umożliwia programistom efektywne ponowne wykorzystywanie, zarządzanie, udostępnianie i publikowanie kodu.
Główne wnioski
Npm może wydawać się zbiorem poleceń w terminalu, ale gdy już poznasz to, co dzieje się za ich plecami:
npm install
System staje się łatwy do zrozumienia. JavaScript dostarcza języka, Node.js środowisko wykonawcze, a npm ekosystem do dzielenia się kodem. W praktyce:
package.jsonokreśla intencję;package-lock.jsonrejestruje fakty. Zapisz oba pliki.- Nigdy nie zapisuj folderu
node_modules. - Przedziały zznaków caret umożliwiają aktualizacje typu minor i patch, a polecenie
npm updatedziała wewnątrz tych przedziałów. - W automatyzacji używaj
npm cido dokładnych instalacji. - Dodawaj zależności celowo; każda z nich to kod, któremu ufasz.
Zatem następnym razem, gdy będziesz pisać:
npm install
pamiętaj, że łączysz swój projekt z ekosystemem stworzonym przez programistów z całego świata.
Literatura pokrewna
- Co JSON.stringify cicho usuwa, przekształca i odmawia serializacji — Dowiedz się, które wartości JavaScript są pomijane lub modyfikowane przez JSON.stringify, jak toJSON, zamienniki i funkcje odwracające to naprawiają oraz kiedy structuredClone jest lepszym narzędziem.
- Co async/await naprawdę gwarantuje i co zostawia dla ciebie — Zrozum, co tak naprawdę wstrzymuje działanie await, jak unikać zapytań seryalizowanych oraz dlaczego błędy, anulowanie, kolejność i ponawianie wymagają rozwiązań wykraczających poza async/await.