Skip to main content

Was ist package-lock.json und wie funktionieren Lockfiles für Yarn- und npm-Pakete?

Artikel von
Package Lock Files blog

14. März 2019

0 Min. Lesezeit

Was ist package-lock.json?

In diesem Artikel geht es sowohl um die Paket-Lockdatei von npm, `package-lock.json`, als auch um Yarns `_yarn.lock`. Paket-Lockdateien enthalten ein detailliertes Verzeichnis der Abhängigkeiten eines Projekts. Sie geben die genauen Versionen der zu installierenden Abhängigkeiten sowie deren Abhängigkeiten und so weiter an – bis hin zum vollständigen Abhängigkeitsbaum.

Eine Paket-Lockdatei wird erstmals zu einem Projekt hinzugefügt, wenn darin die Abhängigkeiten frisch installiert werden. Bei der Installation wird der gesamte Abhängigkeitsbaum berechnet und zusammen mit Metadaten zu jeder Abhängigkeit in der Lockdatei gespeichert, zum Beispiel:

  • Die zu installierende Paketversion

  • Ein Integritäts-Hash, mit dem sichergestellt wird, dass das Paket nicht manipuliert wurde

  • Der aufgelöste Speicherort im Registry-Repository, der angibt, von wo dieses Paket abgerufen wurde und bei künftigen Installationen abgerufen werden soll

Code-Editor mit einem package-lock-Eintrag für die Abhängigkeit acorn, einschließlich Version 5.7.3, Registry-URL, Integritäts-Hash und dev-Kennzeichnung.

Warum brauchen wir Lockdateien?

Lockdateien sollen alle Versionen im gesamten Abhängigkeitsbaum zum Zeitpunkt ihrer Erstellung festlegen beziehungsweise fixieren. Warum ist es wichtig, eine Paket-Lockdatei zu verwenden und Paketversionen zu fixieren?

Ohne Paket-Lockdatei löst ein Paketmanager wie Yarn oder npm während der Installation der Abhängigkeiten eines Pakets in Echtzeit die jeweils aktuellste Paketversion auf – statt der Version, die ursprünglich für das konkrete Paket vorgesehen war.

Diagramm zur semantischen Versionierung mit den Bestandteilen Haupt-, Neben- und Patch-Version.

Wenn ein Projekt beispielsweise von dummy-pkg: ^1.0.0 abhängt, können zwei separate Installationen zu unterschiedlichen Zeitpunkten verschiedene Versionen von dummy-pkg abrufen. Das kann passieren, wenn ein Nutzer `dummy-pkg` installiert und dabei Version 1.0.0 abruft, das Paket aber wenige Minuten später eine neue Version 1.0.1 veröffentlicht. Bei einer späteren Installation im Projekt würde ein zweiter Nutzer dann Version 1.0.1 von `dummy-pkg` statt Version 1.0.0 abrufen.

Lockdateien sorgen dafür, dass Installationen über den gesamten Abhängigkeitsbaum hinweg identisch und reproduzierbar bleiben – bei verschiedenen Nutzern, etwa Teammitgliedern, die zusammenarbeiten, und auf unterschiedlichen Systemen, zum Beispiel bei einem CI-Build.

Wie funktionieren Lockdateien?

Im Großteil des npm-Ökosystems gibt es zwei Paket-Lockdateien:

  • Yarns yarn.lock

  • npms package-lock.json

Ein gutes Flussdiagramm erklärt am besten, wie diese beiden Dateien verwendet werden:

Diagramm dazu, wie npm- und Yarn-Lockfiles die Paketinstallation, Veröffentlichung, Versionsverwaltung und reproduzierbare Builds steuern.

Diese Abbildung verwendet npms package-lock.json, die überall durch yarn.lock ersetzt werden kann. Die einzige Ausnahme: Der npm-Client ignoriert beim Veröffentlichen nicht automatisch eine yarn.lock-Datei. Sie wird daher in das gepackte Tarball aufgenommen, sofern sie nicht ausdrücklich in der Datei .npmignore ausgeschlossen wird. Wie auf der linken Seite der Abbildung zu sehen ist, wird diese Paket-Lockdatei jedoch selbst dann nicht von den Endnutzern verwendet, die die Bibliothek nutzen, wenn sie Teil des Pakets ist.

Weder Yarn noch npm berücksichtigen Lockdateien für transitive Abhängigkeiten; Paketmanager ignorieren diese vollständig. Nur beim Top-Level-Projekt, in dem eine Installation ausgeführt wird, wird der gesamte Abhängigkeitsbaum mithilfe einer Lockdatei ermittelt, auf die sich der Paketmanager als Abhängigkeitsmanifest bezieht.

Shrinkwrap-Lockdateien

Sag niemals nie. In einem Fall wird eine spezielle Lockdatei sogar bei transitiven Abhängigkeiten berücksichtigt. Die Datei npm-shrinkwrap.json fixiert wie andere Lockdateien den Abhängigkeitsbaum. Bei einer Veröffentlichung mit npm wird diese Datei jedoch auch in die Registry übernommen. Noch wichtiger: Wenn Endnutzer die Bibliothek in einer typischen Anwendung verwenden und npm install ausführen, bestimmt die Shrinkwrap-Datei der Bibliothek, welche Versionen abgerufen werden – statt der Semver-Auflösung, die während der Installation stattfindet.

Wichtig ist, dass Yarn und npm unterschiedlich mit Paketen umgehen, die eine Datei npm-shrinkwrap.json enthalten:

  • npm legt die in npm-shrinkwrap.json angegebenen Abhängigkeiten immer auf der eigenen Ebene des Pakets im Ordner node_modules/ ab und versucht nicht, sie im Verzeichnisbaum nach oben zu verschieben.

  • Yarn berücksichtigt npm-shrinkwrap.json nie und ignoriert die Datei vollständig.

Wozu dient eine Shrinkwrap-Datei? Sie ermöglicht es Bibliotheksbetreuern, die Abhängigkeiten ihrer Bibliothek festzulegen und zu pflegen, um bekannte Versionen auszuliefern. Dafür muss jedoch der gesamte Abhängigkeitsbaum sorgfältig gewartet werden. Wird eine Shrinkwrap-Datei verwendet, muss außerdem keine weitere Lockdatei im Quellcode-Repository vorhanden sein. Ein bekanntes Beispiel für eine Bibliothek, die diesen Ansatz verfolgt, ist das Projekt hapijs.

Abweichungen bei Lockdateien

Lockdateien werden angelegt, wenn Entwickler mit einem Projekt arbeiten – etwa indem sie eine Abhängigkeit hinzufügen oder die Abhängigkeiten eines frisch geklonten Projekts installieren. Entwickler fügen einem Projekt im Entwicklungszyklus häufig Abhängigkeiten hinzu oder entfernen sie. Doch was passiert, wenn sie Änderungen an package.json vornehmen und vergessen, die dazugehörige Lockdatei einzuchecken?

Wenn die package.json eines Projekts nicht mit der Lockdatei übereinstimmt, versuchen Paketmanager wie npm und Yarn, die Abweichung auszugleichen und ein neues Manifest zu erstellen. Das klingt zwar sinnvoll, kann aber zu Problemen führen, wenn es während der CI passiert.

Schlägt der Build-Schritt nicht fehl, wenn die Lockdatei von den in package.json deklarierten Abhängigkeiten abweicht, können die erstellten oder getesteten Artefakte eine beliebige zum Build-Zeitpunkt verfügbare Version verwenden. Damit werden alle Vorteile einer Lockdatei zunichtegemacht.

Daher empfiehlt es sich, Paketmanager anzuweisen, bei der Installation von Abhängigkeiten die Lockdatei zu verwenden, zum Beispiel:

$ yarn install --frozen-lock file
$ npm ci

Lockfiles für Anwendungen und Bibliotheken

Je nachdem, ob es sich bei einem Projekt um die Hauptanwendung oder um eine Bibliothek handelt, die von einer Anwendung oder einer anderen Bibliothek verwendet werden soll, gehen die Meinungen darüber auseinander, wie Lockdateien eingesetzt werden sollten.

Bei Anwendungsprojekten besteht Einigkeit darüber, eine Lockdatei zu verwenden. Bei Bibliotheken eher nicht. Warum?

Das Hauptargument gegen Lockdateien in Bibliotheken lautet, dass dadurch die Abhängigkeiten, die Nutzer tatsächlich zusammen mit der Bibliothek abrufen, voneinander abweichen. Infolgedessen erkennen Paketbetreuer nicht, wenn Builds fehlschlagen.

Ohne Lockdatei werden die Abhängigkeiten jedoch erst bei der Installation aufgelöst und unterscheiden sich wahrscheinlich ohnehin zwischen Betreuern und Nutzern.

Meiner Meinung nach unterscheiden sich Bibliotheksprojekte nicht von anderen Projekten und sollten für die Zusammenarbeit im Team und reproduzierbare Builds eine Lockdatei enthalten.

Ich möchte jedoch eine Verbesserung vorschlagen: Wenn Sie tatsächlich befürchten, dass Abhängigkeiten Ihrer Bibliothek bei Ihren Nutzern Probleme verursachen, können Sie zwei verschiedene CI-Builds einrichten, um solche Probleme aufzudecken:

  • Bei einem Build wird die Lockdatei des Projekts wie bei jeder üblichen Build-Konfiguration verwendet.

  • Beim anderen wird die Lockdatei des Projekts ignoriert und die Abhängigkeiten werden gemäß den jeweils neuesten Semver-Versionen aufgelöst.

Mit diesem Ansatz erhalten Sie reproduzierbare Builds und konsistente Abhängigkeiten für die Entwicklung. Gleichzeitig können Entwickler potenziell inkompatible Änderungen für Nutzer Ihrer Bibliothek erkennen – und das alles, während auch die Zufriedenheit Ihres gesamten Entwicklerteams gewährleistet bleibt.

Starten Sie mit Capture-the-Flag

Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Challenges lösen.

Gepostet in: