Schwierigkeiten bei der Veröffentlichung von Modulen in npm und Bower

Avatar of Kaloyan Kosev
Kaloyan Kosev am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Bower und npm sind de facto die Paketmanager des Webs. Ich bezweifle, dass es viele Front-End-Entwickler gibt, die noch nie davon gehört haben oder sie zur Verwaltung von Abhängigkeiten verwendet haben.

Während viele von uns sie als Konsumenten nutzen, entscheiden Sie sich vielleicht eines Tages, ein eigenes Projekt zu teilen und ein Mitwirkender zu werden! Das ist mir kürzlich passiert. Ich hatte die Erfahrung, meine Open-Source-Bibliothek auf npm und Bower zu veröffentlichen.

Obwohl ihre offiziellen Dokumentationen ziemlich gut waren, hatte ich immer noch mit drei wenig bekannten Tücken zu kämpfen. Ich werde mich in diesem Beitrag nicht auf die Grundlagen konzentrieren. Sie können diese jederzeit finden und lesen. Ich werde mich stattdessen auf die Tücken konzentrieren.

Heutzutage scheint es, dass selbst Bower den Leuten rät, Bower nicht mehr zu verwenden. Im Jahr 2018 gibt es jedoch immer noch viele Projekte, die davon abhängig sind. Die Umfrage State of JavaScript in 2017 zeigt, dass etwa 24% der befragten Entwickler Bower immer noch als Paketmanager verwenden. Daher denke ich, dass es noch eine Weile dauern wird, bis wir das Ende von Bower sehen, was bedeutet, dass es sich wahrscheinlich immer noch lohnt, es zu unterstützen, um Projekte abzudecken, die mit Legacy-Paketen verwaltet werden. Ich fühle den Schmerz derer unter Ihnen, die an einem Legacy-Projekt arbeiten – deshalb habe ich mich entschieden, mein Open-Source-Modul auch dort zu veröffentlichen.

Meine Hoffnung ist, dass Sie danach einen Schritt voraus sind, wenn Sie sich entscheiden, Ihren Code mit der Welt zu teilen. Ohne weitere Umschweife sind hier einige Tücken, auf die ich beim Verwalten von Paketen gestoßen bin.

Ein Paket von npm entfernen

Warum sich die Mühe machen, stundenlang einen Namen auszuwählen, wenn Sie sich stattdessen auf die Bereitstellung von Funktionen konzentrieren können? Bei meiner ersten Erfahrung mit npm war ich unglücklich, den Namen meines Projekts „test-something“ zu belassen.

Rate mal? Ein paar Tage später fand ich heraus, dass die Deinstallationsoption in der npm-Public-Registry nur für Versionen erlaubt ist, die in den letzten 24 Stunden veröffentlicht wurden. Wenn Sie versuchen, eine vor mehr als einem Tag veröffentlichte Version zu deinstallieren, müssen Sie den Support kontaktieren.

Sie geben an, dass es generell als schlechte Praxis gilt, eine Bibliothek zu löschen, von der andere Personen abhängig sind. Das verstehe ich, aber ich bin mir zu 100 % sicher, dass kein Projekt von einem Paket namens „test something“ abhängig ist.

Ich wollte die Sache ruhen lassen, aber mein Testpaket wäre für immer in meinem glänzendennpm-Benutzerprofil. Igitt!

Ich habe den Support kontaktiert und sie haben meine Anfrage noch am selben Tag bearbeitet. Sie wollten es immer noch nicht vollständig deinstallieren, aber sie haben es auf das @npm-Benutzerkonto übertragen und es mit einer Deprecations-Notiz versehen. Dies hat es von meinem Profil (woohoo!) und aus den Suchergebnissen entfernt. Wenn jemand jedoch die genaue URL (oder den Namen) kennt, kann er es immer noch installieren. Das ist zwar nicht ganz ideal, aber die Deprecations-Notiz wird trotzdem eine Warnung sein, dass das Paket nicht mehr unterstützt wird.

Ich glaube, das könnte mit den 11 Zeilen Code zusammenhängen, die Azer Koçulu von npm gelöscht hat und die das Internet für einen Moment kaputt gemacht haben. Sicherheit geht vor.

Die Moral von der Geschichte: Wählen Sie Ihren Paketnamen weise!

Module exportieren

Eine weitere Tücke, auf die ich gestoßen bin, war wie ich mein Modul exportieren kann. Ich wollte es universell tun, damit jeder es im Browser in einer der drei gängigsten Ansätze importieren kann. Zum Beispiel…

…mit ES6

// If a transpiler is configured (like webpack, Babel, Traceur Compiler or Rollup):
import MyModule from 'my-module';

…mit CommonJS

// If a module loader is configured (like RequireJS, Browserify or Neuter):
const MyModule = require('my-module');

…oder durch Referenzierung der Skriptdatei in HTML

<script ="/node_modules/my-module/index.js"></script>

Was ich eigentlich gesucht habe, ist das Muster der Universal Module Definition. Es ist ein Muster, das eine saubere Möglichkeit bietet, Ihr Modul an verschiedene Umgebungen zu exponieren, die Module auf verschiedene Weise konsumieren.

Dieses Muster hat ein paar Variationen, je nachdem, was Sie wirklich brauchen. Module, die auf diese Weise geschrieben sind, können jedoch überall funktionieren, sei es im Client, auf dem Server oder anderswo.

Das Standardmuster ist

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['dependency'], factory);
	} else if (typeof module === 'object' && module.exports) {
		  // Node. Does not work with strict CommonJS, but
		  // only CommonJS-like environments that support module.exports,
		  // like Node.
		  module.exports = factory(require('dependency'));
	} else {
    // Browser globals (root is window)
    root.returnExports = factory(root.dependency);
	}
}(this, function (dependency) {
  // Use dependency in some fashion.
  return {
    // Your module goes here
  };
}));

Wenn Sie Grunt, Gulp oder webpack verwenden, werden Sie feststellen, dass es ein Plugin gibt, das Ihre Module auf diese Weise für Sie wrappen kann. Außerdem ist es bereits im Kern von webpack integriert!

Verwaltung von Distributionsdateien

Diese war wirklich knifflig.

Ich baue ein Paket für npm und Bower. Ich folgte dem Muster, die Arbeitsdateien (ES6) im Verzeichnis src/ des Pakets zu behalten und meine Distributionsdateien (ES5, kompiliert mit Babel) im Verzeichnis dist/ zu bauen.

Ich ignoriere den gesamten Ordner dist/ in der Datei .gitignore. Sie kennen das Spiel: Quellcodeverwaltung sollte nur Quellcode enthalten. Wenn es aus der Quelle generiert wird, gehört es nicht dorthin – es sollte stattdessen von Ihrem Build-Prozess generiert werden.

Einerseits (npm) habe ich eine .npmignore, die genau das Gegenteil tut und src/ anstelle von dist/ ignoriert. Auf npm möchte ich nur meine Distributionsdateien. Das funktioniert perfekt.

Andererseits (Bower) fehlt der dist/-Ordner im Repository und daher enthält das Bower-Paket ihn nicht. Sie sehen, Bower verfolgt nur Ihren öffentlich verfügbaren Git-Endpunkt. Durch das Pushen von Git-Tags veröffentlichen Sie eine neue Version im Bower-Registry. Ja, es kann Dateien ignorieren, aber sie beziehen sich nur auf die Dateien in Ihrem Repository.

Also, wie kann ich den von Git ignorierten dist/-Ordnerinhalt auf Bower veröffentlichen?

Ich bin mir nicht sicher, ob das möglich ist. Der einzige Workaround, den ich gefunden habe, ist, die Distributionsdateien in das Repository zu committen. Wenn Sie diese Distributionsdateien wirklich aus dem Repository heraushalten möchten, besteht der Trick darin, sie kurz vor der Veröffentlichung eines Tags zu committen. Veröffentlichen Sie einen Tag. Entfernen Sie sie.

Es gibt noch einen weiteren Anwendungsfall, der mir etwas Frieden gibt. Stellen Sie sich vor, jemand lädt ein ZIP Ihres Repositorys herunter und fügt es in sein Projekt ein. Er benötigt Ihren ausgefallenen Build-Schritt nicht. Die Produktionsquelle ist bereits vorhanden. Nun, vielleicht ist das doch nicht so schlimm.

Zusammenfassend

Sowohl npm als auch Bower bleiben weit verbreitete und hilfreiche Möglichkeiten zur Verwaltung von Projektabhängigkeiten, auch wenn Bower sich verabschiedet. Obwohl sie gut in dem sind, was sie tun, birgt die Rolle als Eigentümer und Mitwirkender an einem Paket, das in einem der Paketverzeichnisse aufgeführt ist, einige Herausforderungen für uns, und ich hoffe, dass die hier dargelegten Ihnen helfen, anderen Zeit und möglichen Kopfschmerzen zu ersparen.

Kennen Sie andere Wege, die hier behandelten Tücken zu bewältigen? Oder sind Sie auf eigene Tücken gestoßen? Lassen Sie es mich in den Kommentaren wissen!