piece of paper with two pencils and some handwritten lines of code
Webentwicklung |

Auch Scripts brauchen Liebe!

mo.jpg.png

Moritz

4. März 2020

tl;dr quick summary
Warum npm-Scripts die gleiche Aufmerksamkeit für Qualität und Wartbarkeit verdienen wie jeder andere Aspekt unseres Codes und die Vorstellung von scriptlint.

Hinweis: Dieser Artikel wurde unter Zuhilfenahme von KI aus dem Englischen übersetzt. Hier geht's zum Originaltext.

Einer der einzigartigsten und attraktivsten Aspekte der modernen JavaScript-Entwicklung ist das Tooling, das sich darum rankt. Erinnerst du dich an die Zeiten, als deine Teammitglieder starke Meinungen zu Einrückungen hatten und sich gegenseitig für das Einchecken von "schlechtem" oder "hässlichem" Code kritisierten? Heutzutage kümmern sich ESLint und Prettier um dieses Problem, indem sie diese Meinungen in Konfigurationen festlegen und dich automatisch überprüfen, bevor du den Code überhaupt kompilieren kannst. Testen ist ein weiteres Beispiel für solches Tooling: Wir verwenden Jest für Unit-Tests, Cypress für E2E-Tests und alle möglichen Pretests, Checks und andere Linter. Und wir führen all das sowohl lokal als auch in der CI-Umgebung aus. All dieses Tooling ist schwer einzurichten und hat eine steile Lernkurve, aber sobald es funktioniert, leistet es großartige Arbeit bei der Aufrechterhaltung der Codequalität und Wartbarkeit, selbst in größeren Teams.

Der typische Einstiegspunkt zu diesen Tools ist der "scripts"-Abschnitt in der package.json, auch bekannt als "npm scripts" (obwohl sie auch mit yarn und anderen npm-Alternativen ausgeführt werden können). Sie bieten einfachen CLI-Zugriff auf alle Tools in deinem Projekt. Aber wenn es um die Wartbarkeit dieser Scripts geht, werden sie irgendwie vernachlässigt. Wenn du jemals in einer großen und ausgereiften JS-Codebasis gearbeitet hast, hast du es gesehen: Dutzende und Aberdutzende von Build-, Lint- und Test-Scripts, die sich manchmal gegenseitig mit pre*- oder post*-Präfixen aufrufen, Dinge sequenziell mit && ausführen und fast immer in einer scheinbar zufälligen Reihenfolge, die es schwer macht zu finden, wonach du suchst. Ein Albtraum.

Noch schlimmer ist, dass jeder Scripts-Abschnitt unterschiedliche - wenn überhaupt - Namens- und Aufrufkonventionen verwendet. Vielleicht startet npm run start einen prestart-Hook, der rm -rf ./dist ausführt, bevor Babel alles transpiliert und poststart einen Server startet? Vielleicht startet npm run start den lokalen Dev-Server plus irgendeine Art von Watcher? Vielleicht musst du das über start:development starten (oder war es start-develop?) - ohne direkt in die package.json zu schauen - wer weiß? Du kannst keine Kommentare in package.json hinzufügen und es gibt kaum jemals einen README-Abschnitt für die Scripts... oh, und was ist, wenn du ein neues Teammitglied einarbeitest, das darauf besteht, Windows zu verwenden? rm -rf ./dist wird unter Windows fehlschlagen.

test:lint oder test-lint, welches war es nochmal?

Können wir BITTE einen Weg finden, das auf konsistente Weise zu organisieren!? Können wir uns nicht auf ein paar Best Practices einigen!? Ich höre dich schreien. Nun, deine Freunde bei Peerigon haben genau das Richtige, um deine Schmerzen zu lindern.

Stand der package.json 2020

Dies ist gewissermaßen ein eigenes Blogpost-Thema, aber wir haben uns eingehend angesehen, wie Leute Package-Scripts verwenden. Wir haben die package.jsons der 1000 am häufigsten abhängigen npm-Module gecrawlt (es gibt bessere Metriken da draußen, wenn du die Daten hast - dies war einfach leicht zu crawlen) und ihre "scripts" untersucht. Einige häufige Muster haben sich herauskristallisiert:

1. Leute organisieren ihre Scripts in Namespaces

Du siehst viele build:* oder test:* Namen, was zwei Vorteile bietet: Es gruppiert Scripts sowohl visuell als auch alphabetisch (manche Leute halten alphabetische Reihenfolge durch die Zeilensortierungsfunktion ihrer Editoren ein).

2. : ist ein sehr gebräuchlicher Namespace-Separator

Es ist unklar, wer damit angefangen hat, aber es scheint der Favorit zu sein. Eine andere beliebte Option ist -.

3. Leute teilen komplexe Aufgaben in kleinere Schritte auf

Um Prozesse einfacher zu warten, ist es sehr üblich, ein komplexes Script in kleinere Teile aufzuteilen und sie dann sequenziell auszuführen. Meistens geschieht dies durch Verwendung von && — was auf *nix- und Windows-Systemen funktioniert. Eine weitere Best Practice, die du siehst, ist die Verwendung von npm-run-all. Die Verwendung von benutzerdefinierten Hooks (pre*/post*) ist weniger üblich, aber auch ein gültiger (wenn auch diskutabel unintuitiverer) Ansatz.

4. Manche Leute interessiert es einfach nicht

Es gibt alle möglichen Best Practices, die sich in diesen Erkenntnissen widerspiegeln, aber auch viele Projekte könnten etwas Hilfe mit ihren Scripts gebrauchen.

Nenn es keinen "Standard"

Screenshot eines Tweets von Tim Myers über Script-Standards

Bildunterschrift: Tim Myers auf Twitter

Als Technikfreaks neigen wir dazu, nach einem "Standard" zu greifen, wenn wir nicht sicher sind, wie man etwas "richtig" macht. Es gibt diesen berühmten xkcd-Comic über Standards, der ein Zeugnis für die Tendenz von Softwareentwicklern ist, neue Standards zu erfinden, wenn die alten nicht zu ihren Bedürfnissen passen.

In diesem Fall gab es keinen Standard. Die Benennung und Gestaltung von npm-Scripts ist unerforschtes Gebiet, und als Neuling bist du auf dich allein gestellt. Erfahrene JS-Entwickler haben durch Erfahrung eine Art, Dinge "richtig" zu machen, aber keine Möglichkeit zu erklären, warum oder wie.

Dennoch wollten wir davon absehen, ein kompliziertes und abstraktes technisches Standardpapier zu schreiben, das niemand lesen und verstehen kann. Wir möchten es so einfach wie möglich machen, die Scripts deines Projekts zu verbessern.

Deshalb haben wir...

scriptlint

Das scriptlint-Logo

... als CLI-Tool entwickelt - denke an einen Linter für deine Package-Scripts - mit konfigurierbaren Regeln und leicht konsumierbarer Dokumentation.

Hier ist ein Beispiel in einem webpack-basierten Frontend-Projekt, das scriptlint auf der Shell verwendet. Hier ist die Package-Datei:

Wenn du scriptlint in diesem Projekt ausführst, wirst du einige Warnungen sehen:

Dies sind die Warnungen aus den nicht-strikten/minimalen Regeln von scriptlint: Deine package.json muss Scripts namens dev, start und test enthalten, und letzteres kann nicht das Standard-Test-Script von npm init sein. So beheben wir diese Probleme:

  • Da "Starten" des Projekts wahrscheinlich bedeuten würde, den Dev-Server zu starten, benennen wir start-dev in start um und erstellen einen Alias dev dafür. Andersherum wäre auch in Ordnung.
  • Da wir noch keine Unit-Tests verwenden, definieren wir test als eine Kombination aus "der Code baut ohne Fehler" und "ESLint beschwert sich nicht" als nächstbeste Alternative. Wir können später Jest und/oder Cypress hinzufügen, wenn wir wollen, aber Bauen, Typ-Prüfung und Linting sollten Teil jeder test-Script-Kette sein.

So sieht das jetzt aus:

Führe scriptlint erneut aus, um zu prüfen:

Nachdem wir nun die minimalen Regeln hinter uns gebracht haben, verbessern wir das weiter, indem wir scriptlint --strict ausführen. Drei neue Warnungen tauchen auf:

Beginnen wir mit den ersten zwei Problemen, denn die sind am einfachsten zu beheben - durch Ausführen von scriptlint --strict --fix! Einige der Regeln können automatisch behoben werden, in diesem Fall wird scriptlint ...

  • dem Script namens eslint den Fallback-Namespace other: voranstellen
  • die Scripts alphabetisch sortieren

Da other:eslint kein großartiger Name ist, werden wir ihn manuell in test:lint umbenennen.

Das letzte verbleibende Problem ("Use of unix double ampersand (&&) in script 'test' is not allowed [...]") kann behoben werden, indem wir npm-run-all als devDependency installieren und test wie folgt umschreiben: run-s build test:lint. Eine schnelle Überprüfung durch Ausführen von scriptlint --strict --fix und schon ist es geschafft:

Ein perfekt "scriptlint-standard"-konformer Scripts-Abschnitt!

In diesem Beispiel haben wir etwa die Hälfte der verfügbaren Regeln in Aktion gesehen. Wenn du wissen möchtest, was scriptlint sonst noch für dich tun kann, schau auf unsere Github-Seite! Natürlich ist scriptlint Open Source (MIT-Lizenz), auf npm verfügbar, kommt mit JS-Modul-Unterstützung, TypeScript-Typdefinitionen, ist konfigurierbar und erweiterbar (benutzerdefinierte Regeln!). Es kann sowohl lokal in deinen Projekten als auch global in deiner Shell installiert werden. Hier ist unser Installationsleitfaden.

Wir hoffen, dass es deinem Team bei der Aufrechterhaltung der Script-Qualität hilft, und würden uns über dein Feedback freuen. Die Pflege des "Standards"/der scriptlint-Regeln sollte eine Community-Anstrengung sein!

Von Peerigon mit ❤️

Dank an Tanner Hoisington und Johannes Ewald.

npm scripts

Tooling

Linting

Code Quality Tools

Weitere Themen

Lea, 04.04.2025

Vue clever nutzen – Wiederverwendbarkeit für Einsteiger:innen

Vue

JavaScript

Reusability

DRY Principle

Components

Composables

Zum Blogartikel
Header-top-ten-mistakes-to-avoid.png

Francesca, Ricarda, 02.04.2025

Die 10 häufigsten Fehler bei der Entwicklung digitaler Produkte – und wie du sie vermeidest

MVP development

UX/UI design

product vision

agile process

user engagement

product development

Zum Blogartikel

Judith, 31.03.2025

Von der Hypothese zur echten Erkenntnis: MVPs richtig einsetzen

Zum Blogartikel