npm: Mehrere Versionen des selben Pakets in node_modules (Am Beispiel Bootstrap)
Aufgabenstellung: Ich soll mit npm in ein Repository, anders: einen lokalen Ordner, nicht nur eine Version von Bootstrap im Verzeichnis node_modules/
bereit stellen, sondern diverse herunter laden. So kann ich die scss/
-Ordner der unterschiedlichen Versionen leichter abgleichen, anschauen, kopieren, nutzen und jederzeit bequem updaten bzw. erneuern; ohne, dass ich auf GitHub rumsuchen muss.
Das geht natürlich mit anderen npm-Paketen ebenso.
Meine Arbeitsumgebung
Auch, wenn diese nicht maßgeblich ist und jedwede Konsole-Variante möglich ist, auf der mit npm gearbeitet werden kann. Das geht ja auch mit Windows-Hausmitteln. Mag ich aber nicht.
Ich verwende WSL1 mit Debian-Linux auf Windows 10. Das Windows-Subsystem für Linux (WSL) ermöglicht es, ein "echtes" Linux mit Konsole an seinem Windows-Rechner zu betreiben. Version 1 verwende ich, da ich vornehmlich mit Windows-Laufwerken arbeiten will, was angeblich schneller mit dieser Version läuft als mit WSL-Version 2.
Meine unter Linux installierte npm-Version ist momentan halbwegs aktuell. Ich weiß nur, dass mit Uraltversionen das unten beschriebene Vorgehen nicht funktioniert. Die Version kann man in der Konsole prüfen mit:
npm -v
---ergibt bei mir gerade---
8.1.4
Ordner vorbereiten
Meine Repositories befinden sich in Windows im Hauptordner Z:\git-kram
in diversen Unterordnern. Über die Linuxkonsole komme ich an dieses Verzeichnis via absoluten Pfad /mnt/z/git-kram
heran.
Zuerst lege ich mir ein neues Verzeichnis an. Der Name soll sein bootstrapscssghsvs
. Folgendes ist komplett unabhängig davon wie man den nun nennt.
Das ist zugleich mein Repository-Name, weil ich den Ordner später auch auf GitHub hochladen möchte. Das ist aber gar nicht unbedingt nötig und dient mir in diesem Fall nur als doppelte Sicherung.
Und wechsele in der Konsole auch gleich in dieses neue Verzeichnis:
cd /mnt/z/git-kram/
mkdir bootstrapscssghsvs
cd bootstrapscssghsvs
---Danach sehe ich---
volli@DELL-M6800:/mnt/z/git-kram/bootstrapscssghsvs$
Auch unter Stinknormal-Windows finde ich den neuen, leeren Ordner Z:\git-kram\bootstrapscssghsvs
.
Die package.json
für's npm
Als nächstes benötigen wir in unserem neuen Ordner eine Datei package.json
. Diese enthält Informationen und Anweisungen für npm, Node etc.
Wer nun unbedingt möchte, feuert an der Konsole ein npm init
ab und beantwortet die Fragen, die gestellt werden, um abschließend die neue Datei anzulegen und folgend "umzubiegen". Mich verwirrt dieses Prozedere eher und ich kopiere sie lieber aus einem anderen meiner Repositories und passe sie an ;-) Viele abgefragte Angaben sind für mein Vorhaben sowieso nicht relevant. Außerdem legt es immer auch irgendwas mit index.js
an, was ich gar nicht benötige. Ich tue also so, als hätte ich das init
gar nicht erwähnt.
So sieht meine Grundversion der package.json
aus.
{
"name": "bootstrapscssghsvs",
"version": "1.0.0",
"description": "A collection of SCSS files of different Bootstrap versions. Not any more.",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"updateCheck": "npm outdated",
"update": "npm update --save-dev"
},
"author": {
"name": "G@HService Berlin Neukölln, Volkmar Volli Schlothauer",
"url": "https://ghsvs.de"
},
"license": "ISC",
"repository": {
"type": "git",
"url": "https://github.com/GHSVS-de/bootstrapscssghsvs.git"
},
"dependencies": {}
}
repository
, license
, author
kann sich der geneigte Leser eigentlich sparen.
Ein erster Test
Oben in Zeile 6 sieht man ja, dass ich ein Test-Script "test"
angelegt habe, neben weiteren, die unten noch zum Einsatz kommen.
In der Konsole schicke ich den Test mit einem npm run test
ab:
npm run test
---Und das gibt aus und zeigt mir, dass die package.json funktioniert:
> bootstrapscssghsvs@1.0.0 test
> echo "Error: no test specified" && exit 1
Error: no test specified
Die zu ladenden Pakete (dependencies
) definieren
In Zeile 19 obiger package.json
sehen wir ein noch leeres "dependencies": {}
. Hier kommen nun kommagetrennt die Anweisungen hinein, was npm uns in den Ordner node_modules
herunterladen wird. Wenn der noch nicht existiert, wird er automatisch neu angelegt.
Hinweis: Der npm semver calculator kann hilfreich sein, wie man die jeweiligen Versionsangaben zu formulieren hat, um spezifisch diese oder jene "abzugreifen".
Vorspiele
Zuerst möchte ich immer die aktuellste Version von Bootstrap haben und befülle mein dependencies
-Objekt erst mal nur mit "bootstrap": "*"
.
"dependencies": {
"bootstrap": "*"
}
In die Konsole gebe ich ein: npm install
. Nach etwas mehr oder weniger Wartezeit (WSL kann gelegentlich langsam sein, weil unter anderem der Virenscanner reichlich bremsen kann), finde ich im Ordner node_modules/
den Ordner bootstrap/
. Schaue ich in die Datei node_modules/bootstrap/package.json
, sehe ich, dass es zum Zeitpunkt des Schreibens die aktuelle Version 5.2.0
ist.
Hinweis: Weitere Ordner, die sich in node_modules/
befinden sind normal und interessieren mich für mein eigentliches Vorhaben nicht. Hintergrund ist, dass auch die heruntergeladenen Bootstrap-Pakete mehr oder weniger eigene Abhängigkeiten (= Dependencies) haben, die halt auch in diesem Verzeichnis landen.
Weiter geht's: Jetzt würde es mir aber besser gefallen, die aktuellste Bootstrap-Version im Ordner node_modules/bs-current
zu finden.
Ich ändere die obige Dependency-Zeile nach "bs-current": "npm:bootstrap@*"
Der erste Teil ist mein Ziel-Wunschordner. Der zweite erzählt npm welches Paket online abgeholt werden soll und nach dem @
welche Version. Stern bedeutet halt das aktuellste.
Erneut gebe ich in die Konsole npm install
ein. Danach findet sich tatsächlich ein neuer Ordner node_modules/bs-current
und der alte node_modules/bootstrap
ist verschwunden.
Etwas blödsinnig in meinem Szenario. Ich formuliere meine dependencies
so um. Also 2 Zeilen.
"dependencies": {
"bootstrap": "*",
"bs-current": "npm:bootstrap@*"
}
Wieder npm install
. Zwei Ordner mit identischem Inhalt (= aktuellste Version) wurden erzeugt:
node_modules/bs-current
node_modules/bootstrap
Jetzt aber richtig
Was ich in meinem finalen Bootstrap-Sammelsurium haben möchte sind fünf verschiedene Ordner mit jeweils spezifischer Version darin:
- Die immer aktuellste Version in Ordner
bs-current
. - Die jeweils aktuellste Version
5.2.x
in Ordnerbs-52
. - Die jeweils aktuellste Version
5.1.x
in Ordnerbs-51
. - Die jeweils aktuellste Version
4.x
in Ordnerbs-4
. - Nur für diese Anleitung die allererste Version
0.0.1
in Ordnerbs-first
.
Meine Dependencies
sehen folglich und mit Hilfe des oben erwähnten npm semver calculator, der mir beim Finden der richtigen Dacherlzeichen (^
) und Tildenzeichen (~
) geholfen hat, so aus:
"dependencies": {
"bs-current": "npm:bootstrap@*",
"bs-52": "npm:bootstrap@~5.2",
"bs-51": "npm:bootstrap@~5.1",
"bs-4": "npm:bootstrap@^4",
"bs-first": "npm:bootstrap@0.0.1"
}
Schieße ich nun ein npm install
ab und mache die Augen zu bezüglich irgendwelcher WARN
und severity vulnerability
(wer alte Pakete lädt, sieht so was schon mal und zumindest ich kann sie in meinem Szenario komplett weg ignorieren), habe ich anschließend tatsächlich meine fünf Wunschordner mit den verschiedenen Versionen.
node_modules/bs-current
node_modules/bs-52
node_modules/bs-51
node_modules/bs-4
node_modules/bs-first
Updaten statt installieren
Wenn man jedes mal neu installiert, kann das bei umfangreicheren dependencies unnötig lange dauern. Deshalb habe ich in allen meinen Repository-package.json
-Dateien im scripts-Block zwei Update-Zeilen dabei:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"updateCheck": "npm outdated",
"update": "npm update --save-dev"
}
Gebe ich in die Konsole npm run updateCheck
ein, zeigt sie mir, ob eventuell was zu aktualisieren ist.
Wenn ja, feuere ich ein npm run update
ab.
Sonstiges
Naürlich werde ich noch ein JavaScript schreiben, mit dem mir dann ausschließlich die scss
-Ordner aus diesen unübersichtlichen node_modules
-Unterordnern praktikabler für die tägliche Arbeit irgendwo hinkopiert werden.