Node.js Projekte, in denen es besser ist, keine Sperrdateien zu verwenden

Der Autor des Materials, dessen Übersetzung wir heute veröffentlichen, sagt, dass eines der Probleme, mit denen sich Programmierer befassen müssen, darin besteht, dass ihr Code für sie funktioniert und jemand anderem Fehler gibt. Dieses Problem, möglicherweise eines der häufigsten, entsteht aufgrund der Tatsache, dass verschiedene Abhängigkeiten, die das Programm verwendet, in den Systemen des Erstellers und Benutzers des Programms installiert sind. Um diesem Phänomen entgegenzuwirken, existieren in den Garn- und npm- Paketmanagern sogenannte Sperrdateien. Sie enthalten Informationen zu den genauen Versionen der Abhängigkeiten. Der Mechanismus ist nützlich, aber wenn jemand ein Paket entwickelt, das in npm veröffentlicht werden soll, sollte er keine Sperrdateien verwenden. Dieses Material widmet sich der Geschichte, warum dies so ist.



Das Wichtigste auf den Punkt gebracht


Sperrdateien sind äußerst nützlich, wenn Sie Node.js-Anwendungen wie Webserver entwickeln. Wenn Sie jedoch über das Erstellen einer Bibliothek oder eines Befehlszeilentools mit dem Ziel der Veröffentlichung in npm sprechen, müssen Sie wissen, dass Sperrdateien in npm nicht veröffentlicht werden. Wenn diese Dateien während der Entwicklung verwendet werden, verwenden der Ersteller des npm-Pakets und diejenigen, die dieses Paket verwenden, unterschiedliche Versionen der Abhängigkeiten.

Was ist eine Sperrdatei?


Die Sperrdatei beschreibt den vollständigen Abhängigkeitsbaum in der Form, die er während der Arbeit am Projekt erhalten hat. Diese Beschreibung enthält auch verschachtelte Abhängigkeiten. Die Datei enthält Informationen zu bestimmten Versionen der verwendeten Pakete. Im npm-Paketmanager werden solche Dateien in yarn - yarn.lock als package-lock.json yarn.lock . In beiden Managern befinden sich diese Dateien im selben Ordner wie package.json .

So könnte package-lock.json aussehen.

 { "name": "lockfile-demo", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": {  "ansi-styles": {    "version": "3.2.1",    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",    "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",    "requires": {      "color-convert": "^1.9.0"    }  },  "chalk": {    "version": "2.4.2",    "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",    "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",    "requires": {      "ansi-styles": "^3.2.1",      "escape-string-regexp": "^1.0.5",      "supports-color": "^5.3.0"    }  } } } 

Hier ist ein Beispiel für eine yarn.lock Datei. Es ist nicht wie package-lock.json , enthält jedoch ähnliche Daten.

 # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies:       color-convert "^1.9.0" chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies:       ansi-styles "^3.2.1"       escape-string-regexp "^1.0.5"       supports-color "^5.3.0" 

Beide Dateien enthalten einige wichtige Abhängigkeitsinformationen:

  • Die genaue Version jeder installierten Abhängigkeit.
  • Abhängigkeitsinformationen für jede Abhängigkeit.
  • Informationen zum heruntergeladenen Paket, einschließlich der Prüfsumme zur Überprüfung der Integrität des Pakets.

Wenn alle Abhängigkeiten in der Sperrdatei aufgeführt sind, warum fügen sie dann auch Informationen zu package.json ? Warum werden zwei Dateien benötigt?

Vergleich von package.json und Sperrdateien


Der Zweck des dependencies der Datei package.json besteht darin, die Projektabhängigkeiten package.json , die installiert werden müssen, damit sie ordnungsgemäß funktionieren. Dies beinhaltet jedoch keine Informationen über die Abhängigkeiten dieser Abhängigkeiten. Abhängigkeitsinformationen können genaue Paketversionen oder einen bestimmten Versionsbereich enthalten, der gemäß den Regeln der semantischen Versionierung angegeben wurde . Bei Verwendung des Npm- oder Garnbereichs wird die am besten geeignete Version des Pakets ausgewählt.

Angenommen, der Befehl npm install wurde ausgeführt, um die Abhängigkeiten eines bestimmten Projekts zu installieren. Während des Installationsprozesses nahm npm geeignete Pakete auf. Wenn Sie diesen Befehl nach einer Weile erneut ausführen und während dieser Zeit neue Versionen von Abhängigkeiten freigegeben werden, kann es durchaus vorkommen, dass beim zweiten Mal andere Versionen der im Projekt verwendeten Pakete geladen werden. Wenn Sie beispielsweise eine Abhängigkeit wie twilio mit dem npm install twilio der folgende Eintrag im Abschnitt " dependencies " der Datei package.json :

 { "dependencies": {    "twilio": "^3.30.3" } } 

Wenn Sie sich die Dokumentation zur semantischen Versionierung von npm ansehen, sehen Sie, dass das Symbol ^ angibt, dass eine beliebige Version des Pakets geeignet ist, deren Anzahl größer oder gleich 3.30.3 und kleiner als 4.0.0 ist. Wenn das Projekt keine Sperrdatei enthält und eine neue Version des Pakets freigegeben wird, yarn install npm install oder yarn install install diese neue Version des Pakets automatisch. Die Informationen in package.json werden nicht aktualisiert. Bei Verwendung von Sperrdateien sieht alles anders aus.

Wenn npm oder yarn die entsprechende Sperrdatei findet, werden Pakete basierend auf dieser Datei und nicht auf package.json . Dies ist beispielsweise besonders nützlich, wenn Sie CI-Systeme (Continuous Integration) auf Plattformen verwenden, auf denen Sie einen einheitlichen Betrieb von Code und Tests in einer Umgebung sicherstellen müssen, deren Eigenschaften im Voraus bekannt sind. In solchen Fällen können Sie beim Aufrufen der entsprechenden Paketmanager spezielle Befehle oder Flags verwenden:

 npm ci #   ,    package-lock.json yarn install --frozen-lock-file #  ,    yarn.lock,     

Dies ist äußerst nützlich, wenn Sie ein Projekt wie eine Webanwendung oder einen Server entwickeln, da Sie in einer CI-Umgebung das Benutzerverhalten simulieren müssen. Wenn wir eine Sperrdatei in das Projekt-Repository aufnehmen (z. B. mit Git-Tools erstellt), können wir daher sicher sein, dass jeder Entwickler, jeder Server, jedes Code-Building-System und jede CI-Umgebung dieselben Versionen verwendet Abhängigkeiten.

Warum nicht dasselbe tun, wenn Sie Bibliotheken oder andere Softwaretools in der npm-Registrierung veröffentlichen? Bevor wir diese Frage beantworten, müssen wir darüber sprechen, wie das Veröffentlichen von Paketen funktioniert.

Paketveröffentlichungsprozess


Einige Entwickler glauben, dass das, was in npm veröffentlicht wird, genau das ist, was im Git-Repository gespeichert ist oder was das Projekt nach Abschluss der Arbeit daran wird. Dies ist eigentlich nicht der Fall. Beim Veröffentlichen eines Pakets ermittelt npm package.json des .npmignore in der Datei package.json und der Datei .npmignore , welche Dateien veröffentlicht werden .npmignore . Wenn nichts davon erkannt werden kann, wird die .gitignore Datei verwendet. Außerdem werden einige Dateien immer veröffentlicht, andere nie. Was diese Dateien sind, finden Sie hier . Beispielsweise ignoriert npm immer den Ordner .git .

Danach nimmt npm alle entsprechenden Dateien und packt sie mit dem Befehl npm pack in eine tarball Datei. Wenn Sie sich ansehen möchten, was genau in eine solche Datei gepackt ist, können Sie den Befehl npm pack --dry-run im Projektordner npm pack --dry-run und die Liste der Materialien in der Konsole npm pack --dry-run .


Npm pack - Befehlsausgabe trocken ausführen

Die resultierende tarball Datei wird dann in die npm-Registrierung hochgeladen. Wenn Sie den npm pack --dry-run Sie darauf achten, dass eine Datei package-lock.json im Projekt nicht in der Tarball-Datei enthalten ist. Dies liegt daran, dass diese Datei gemäß den npm- Regeln immer ignoriert wird.

Das Ergebnis ist, dass die Datei package-lock.json nicht beteiligt ist, wenn jemand das Paket eines anderen installiert. Was sich in dieser Datei befindet, das der Paketentwickler hat, wird bei der Installation des Pakets durch eine andere Person nicht berücksichtigt.

Dies kann durch unglücklichen Zufall zu dem Problem führen, über das wir am Anfang gesprochen haben. Im Entwicklersystem funktioniert der Code einwandfrei und in anderen Systemen führt er zu Fehlern. Tatsache ist jedoch, dass der Projektentwickler und diejenigen, die das Projekt verwenden, unterschiedliche Versionen der Pakete verwenden. Wie kann ich das beheben?

Ablehnung von Sperrdateien und Verwendung von Technologie-Schrumpffolie


Zuerst müssen Sie verhindern, dass Sperrdateien in das Projekt-Repository aufgenommen werden. Wenn Sie git verwenden, müssen Sie Folgendes in Ihre .gitignore Projektdatei .gitignore :

 yarn.lock package-lock.json 

In der yarn.lock heißt es, dass yarn.lock zum Repository hinzugefügt werden muss, auch wenn es um die Entwicklung der Bibliothek geht, die Sie veröffentlichen yarn.lock . Wenn Sie jedoch möchten, dass Sie und Ihre Bibliotheksbenutzer mit demselben Code arbeiten, würde ich empfehlen, yarn.lock in die .gitignore Datei aufzunehmen.

Sie können die automatische Erstellung der Datei package-lock.json deaktivieren, .npmrc Datei .npmrc mit dem folgenden Inhalt zum Projektordner .npmrc :

 package-lock=false 

Wenn Sie mit Garn arbeiten, können Sie den yarn install --no-lockfile , mit dem Sie das Lesen der Datei yarn.lock deaktivieren können.

Die Tatsache, dass wir die Datei package-lock.json , bedeutet jedoch nicht, dass wir keine Informationen über Abhängigkeiten und verschachtelte Abhängigkeiten erfassen können. Es gibt eine andere Datei namens npm-shrinkwrap.json .

Im Allgemeinen ist dies dieselbe Datei wie package-lock.json . Sie wird mit dem npm shrinkwrap . Diese Datei wird in die npm-Registrierung aufgenommen, wenn das Paket veröffentlicht wird.

Um diesen Vorgang zu automatisieren, kann der npm shrinkwrap als Prepack-Skript zum package.json Datei package.json hinzugefügt werden. Sie können den gleichen Effekt mit dem Git-Commit-Hook erzielen. Auf diese Weise können Sie sicher sein, dass in Ihrer Entwicklungsumgebung, in Ihrem CI-System und den Benutzern Ihres Projekts dieselben Abhängigkeiten verwendet werden.

Es ist erwähnenswert, dass empfohlen wird, diese Technik verantwortungsbewusst anzuwenden. Durch das Erstellen von Shrinkwrap-Dateien schreiben Sie bestimmte Versionen der Abhängigkeiten fest. Dies ist einerseits nützlich, um den stabilen Betrieb des Projekts sicherzustellen, andererseits kann es Benutzer daran hindern, kritische Patches zu installieren, was andernfalls automatisch erfolgen würde. Tatsächlich empfiehlt npm dringend, bei der Entwicklung von Bibliotheken keine Shrinkwrap-Dateien zu verwenden, um deren Verwendung auf CI-Systeme zu beschränken.

Suchen von Paket- und Abhängigkeitsinformationen


Leider ist es bei all den zahlreichen Informationen zum Abhängigkeitsmanagement in der npm- Dokumentation manchmal schwierig, in diesen Informationen zu navigieren. Wenn Sie wissen möchten, was genau während der Installation von Abhängigkeiten installiert oder --dry-run wird, bevor Sie das Paket an npm senden, können Sie mit verschiedenen Befehlen das --dry-run verwenden. Die Verwendung dieses Flags führt dazu, dass das Team das System nicht beeinflusst. Beispielsweise npm install --dry-run Befehl npm install --dry-run die Abhängigkeiten nicht tatsächlich, und der Befehl npm publish --dry-run startet den Paketveröffentlichungsprozess nicht.

Hier sind einige ähnliche Befehle:

 npm ci --dry-run #  ,   package-lock.json   npm-shrinkwrap.json npm pack --dry-run #     ,       npm install <dep> --verbose --dry-run #            

Zusammenfassung


Vieles, worüber wir hier gesprochen haben, hängt von den Besonderheiten der Ausführung verschiedener Operationen mit npm ab. Wir sprechen über das Verpacken, Veröffentlichen, Installieren von Paketen und das Arbeiten mit Abhängigkeiten. Und angesichts der Tatsache, dass sich npm ständig weiterentwickelt, können wir sagen, dass sich dies alles in Zukunft ändern kann. Darüber hinaus hängt die Möglichkeit der praktischen Anwendung der hier gegebenen Empfehlungen davon ab, wie der Paketentwickler das Problem der Verwendung unterschiedlicher Versionen von Abhängigkeiten in unterschiedlichen Umgebungen wahrnimmt.

Hoffentlich hat Ihnen dieses Material geholfen, besser zu verstehen, wie das npm-Abhängigkeits-Ökosystem funktioniert. Wenn Sie sich noch eingehender mit dieser Frage befassen möchten, können Sie hier die Unterschiede zwischen den npm install npm ci und npm install nachlesen. Hier erfahren Sie, was genau in die npm-shrinkwrap.json package-lock.json und npm-shrinkwrap.json . Auf der npm-Dokumentationsseite können Sie herausfinden, welche Projektdateien in Paketen enthalten sind und welche nicht.

Liebe Leser! Verwenden Sie die Datei npm-shrinkwrap.json in Ihren Projekten?

Source: https://habr.com/ru/post/de453582/


All Articles