Strona główna / Artykuły / Co naprawdę robi npm install: rejestr, package.json i pliki Lockfile

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.

1605 słó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.
  • Pakiety: same wielokrotnie używalne jednostki kodu.
  • 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:

    1. npm szuka pakietu w rejestrze i wybiera wersję odpowiadającą podanemu zakresowi (najnowszą, jeśli żaden nie został określony).
    2. Rozwiązuje zależności samego pakietu oraz jego zależności, tworząc pełne drzewo struktury.
    3. Ładuje wszystko, co jeszcze nie jest zapisane w pamięci podręcznej, i umieszcza to w katalogu node_modules.
  • Zapisuje zależności w pliku 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.json określa, czego potrzebuje projekt, zazwyczaj w postaci zakresów.
    • package-lock.json rejestruje 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.json określa intencję; package-lock.json rejestruje 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 update działa wewnątrz tych przedziałów.
    • W automatyzacji używaj npm ci do 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