
Hallo an alle. Kürzlich bin ich auf die Aufgabe gestoßen, private npm-Pakete einzurichten. Alles klang sehr interessant und vielversprechend, bis sich herausstellte, dass dort nicht viel zu tun war. Hier wäre alles zu Ende gegangen, aber die zweite Aufgabe bestand darin, ein Demo-Repository für das npm-Paket zu schreiben, das genommen, geklont und darauf basierend schnell etwas Nützliches und im gleichen Stil erstellt werden konnte.
Das Ergebnis war ein Projekt mit angepasster Formatierung, Codestil, Tests für jeden Pool, Grenzwerten für die Codeabdeckung, Bericht zur Codeabdeckung und automatischer Dokumentation. Plus bequemes Veröffentlichen in npm. Details zur Einstellung - unter dem Schnitt.
Anforderungen
Zuerst habe ich herausgefunden, was wir bereits haben:
- Neue Projekte werden in TypeScript geschrieben
- Neben neuen Projekten gibt es eine Reihe von Projekten in reinem JavaScript
- Es gibt Anforderungen zum Schreiben von Tests und die Ergebnisse müssen zur Analyse gesendet werden
Dann schätzte er seine Wunschliste - da es Zeit und Begierde gibt, warum nicht ruhig angehen? Was ich mehr will:
- Ich möchte einen einheitlichen Formatierungsstil
- Ich möchte einen einheitlichen TypeScript-Stil
- Ich möchte Dokumentation, aber ich möchte sie nicht schreiben
- Im Allgemeinen möchte ich alles maximal automatisieren. Was würde Fyr-Fyr-Fyr und in der Produktion
Infolgedessen nahmen die Anforderungen wie folgt Gestalt an:
- Das Modul muss TypeScript sein und mit TsLint getestet werden
- Das Modul muss unter TypeScript und unter JavaScript verwendet werden
- Tests sollten am Git-Hook konfiguriert werden, die minimale Codeabdeckung sollte ebenfalls konfiguriert werden, Statistiken sollten es sein
- Die Formatierung muss konfiguriert sein
- Die Dokumentation muss aus Code erstellt werden.
- Die Veröffentlichung sollte bequem und konsistent sein.
- All das kann automatisiert werden
Es scheint schön zu sein, du musst es versuchen.
Vorläufige Gesten
Wir erstellen (klonen) das Repository, initialisieren package.json und setzen TypeScript lokal. Im Allgemeinen setzen wir alle Abhängigkeiten lokal, weil Alles wird zum Server gehen. Vergessen Sie nicht, die Versionsabhängigkeiten zu beheben .
git init npm init npm i -D typescript ./node_modules/.bin/tsc --init
Sofort vor Ort müssen Sie tsconfig.json für sich selbst optimieren - legen Sie target, libs, include / exclude, outDir und andere Optionen fest.
Um eine einheitliche Formatierung beizubehalten, habe ich zwei Werkzeuge verwendet. Die erste ist die .editorconfig-Datei. Es wird von allen wichtigen IDEs (WebStorm, VSCode, Visual Studio usw.) verstanden, erfordert keine Installation von überflüssigem Material und funktioniert mit einer großen Anzahl von Dateitypen - js, ts, md usw.
#root = true [*] indent_style = space end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true max_line_length = 100 indent_size = 4 [*.md] trim_trailing_whitespace = false
Jetzt verhält sich die automatische Formatierung bei meinen Kollegen mehr oder weniger gleich.
Das zweite Werkzeug ist schöner . Dies ist ein npm-Paket, das Ihre Textformatierung überprüft und wenn möglich automatisch korrigiert. Installieren Sie es lokal und fügen Sie den ersten Befehl zu package.json hinzu
npm i -D prettier
package.json
"prettier": "prettier --config .prettierrc.json --write src*.ts"
Prettier hat keinen init-Befehl, daher müssen Sie ihn manuell konfigurieren . Erstellen Sie .prettierrc.json im Stammverzeichnis des Projekts mit so etwas wie diesem kontroversen Inhalt (wenn überhaupt, geht es in dem Beitrag überhaupt nicht darum, welche Zitate besser sind, aber Sie können es versuchen)
.prettierrc.json
{ "tabWidth": 4, "useTabs": false, "semi": true, "singleQuote": true, "trailingComma": "es5", "arrowParens": "always" }
Erstellen Sie nun den Ordner src, erstellen Sie index.ts mit bedingtem Inhalt und versuchen Sie, hübscher auszuführen. Wenn ihm Ihre Formatierung nicht gefällt, wird er sie automatisch korrigieren. Sehr bequem. Wenn Sie sich dies nicht nur während eines Commits / Pushs merken möchten, können Sie es so konfigurieren, dass es automatisch ausgeführt oder eine Erweiterung für das Studio installiert wird.
Codestil
Mit dem Codestil ist auch nicht alles kompliziert. Für JavaScript gibt es eslint , für TypeScript gibt es tslint . Wir setzen tslint und erstellen tsconfig.js, um die Einstellungen zu speichern
npm i -D tslint ./node_modules/.bin/tslint --init
package.json
"lint": "tslint -c tslint.json 'src/**/*.ts' 'tests/**/*.spec.ts'"
Sie können Ihre eigenen Regeln schreiben oder vorhandene Regeln mithilfe des Extend-Parameters verwenden. Hier zum Beispiel eine Konfiguration von Airbnb.
Tslint-Entwickler scherzen module.exports = { extends: "./tslint-base.json", rules: { "no-excessive-commenting": [true, {maxComments: Math.random() * 10}] } };
Ist das nicht hübsch?
Es gibt einen wichtigen Punkt - tslint und hübscher überschneiden sich in der Funktionalität (z. B. in der Länge einer Zeichenfolge oder in „hängenden“ Kommas). Wenn Sie also beide verwenden, müssen Sie die Einhaltung überwachen oder etwas aufgeben.
Und doch gibt es für diejenigen, die nicht alle Dateien überprüfen möchten, sondern nur inszenierte - ein Paket mit Flusen
Tests
Was brauchen wir vor allem von den Tests? Erstens, damit sie automatisch starten, zweitens die Abdeckungskontrolle, drittens einige Berichte, vorzugsweise im lcov-Format (wenn überhaupt, wird lcov von verschiedenen Analysatoren gut verstanden - von SonarQube bis CodeCov). Wir werden uns etwas später mit der Automatisierung befassen, während wir die Tests selbst einrichten.
Wir setzen Karma , Jasmin und das entsprechende Bodykit ein
npm i -D karma karma-jasmine jasmine karma-typescript karma-chrome-launcher @types/jasmine ./node_modules/.bin/karma init
Wir modifizieren karma.conf.js ein wenig und konfigurieren die Arbeit sofort mit Abdeckung
karma.conf.js karmaTypescriptConfig : { include: ["./src/**/*.ts", "./tests/**/*.spec.ts"], tsconfig: "./tsconfig.json", reports: { "html": "coverage", "lcovonly": { directory: './coverage', filename: '../lcov.dat' } }, coverageOptions: { threshold: { global: { statements: 60, branches: 60, functions: 60, lines: 60, excludes: [] }, file: { statements: 60, branches: 60, functions: 60, lines: 60, excludes: [], overrides: {} } } }, }
Und vergessen Sie natürlich nicht, package.json einen neuen Befehl hinzuzufügen
package.json
"test": "karma start"
Wenn Sie CI verwenden oder planen, CI zu verwenden, ist es besser, HeadlessChrome zu verwenden :
npm i -D puppeteer
Und konfigurieren Sie Karma (Chrome Fix auf ChromeHeadless) und etwas anderes vor. Änderungen können im Demo-Repository angezeigt werden.
Führen Sie die Tests aus und überprüfen Sie, ob alles funktioniert. Überprüfen Sie gleichzeitig den Abdeckungsbericht (er befindet sich im Abdeckungsordner) und entfernen Sie ihn aus der Versionskontrolle. Er wird im Repository nicht benötigt.
Bericht:

Commit-Stil
Commits können auch vereinheitlicht werden (und gleichzeitig jemanden auf Hochtouren bringen, wenn Sie es übertreiben, also ist es besser ohne Fanatismus). Dafür habe ich Commitizen genommen . Es funktioniert in Form eines Dialogs, unterstützt das konventionelle Changelog-Format (Sie können ein Changelog aus seinen Commits erstellen) und es gibt ein VsCode- Plugin dafür
npm i -D commitizen npm i -D cz-conventional-changelog
cz-konventionelles-Changelog ist ein Adapter, der für Fragen und damit für das Format Ihrer Commits verantwortlich ist
Fügen Sie dem Skriptabschnitt einen neuen Befehl hinzu
"commit":"git-cz"
Und ein neuer package.json-Abschnitt - config for commitizen
"config": { "commitizen": { "path": "./node_modules/cz-conventional-changelog" } }
Der Dialog mit dem Commitizen sieht folgendermaßen aus:

Die Dokumentation
Nun zur Dokumentation. Wir werden zwei Arten von Dokumentation haben - aus Code und aus Commits. Für die Dokumentation aus dem Code habe ich typedoc genommen (analog zu esdoc, aber für TypeScript). Es ist sehr einfach einzurichten und zu arbeiten. Die Hauptsache ist, nicht zu vergessen, die Ergebnisse seiner Arbeit aus der Versionskontrolle zu entfernen.
npm i typedoc -D
und aktualisieren Sie package.json
package.json
"doc": "typedoc --out docs/src/ --readme ./README.md"
Das Flag --readme erzwingt, dass Readme in die Hauptdokumentationsseite aufgenommen wird, was praktisch ist.
Die zweite Art der Dokumentation ist Changelog, und das konventionelle Changelog-Cli- Paket hilft uns dabei.
npm i -D conventional-changelog-cli
package.json
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
Aus Winkel gibt es nur Formatierung und nichts mehr. Um das Changelog zu aktualisieren, führen Sie jetzt npm run changelog aus. Die Hauptsache ist, Commits sorgfältig zu schreiben. Nun, wir schreiben immer perfekte Commits, daher sollte dies kein Problem sein.
Bauen
Da unser Paket auch für JavaScript funktionieren sollte, müssen wir TypeScript in JavaScript umwandeln. Außerdem wäre es für alle Fälle schön, ein minimiertes Bündel zu erstellen. Dafür brauchen wir uglifyjs und ein kleines Tweak package.json
npm i -D uglifyjs
package.json
"clean":"rmdir dist /S /Q", "build": "tsc --p ./ --sourceMap false", "bundle": "uglifyjs ./dist/*.js --compress --mangle --output ./dist/index.min.js"
Wenn Sie die Größe Ihres Projekts steuern möchten, gibt es übrigens zwei weitere interessante Pakete
Sie können auch in den Commit / Push / Publish-Prozess integriert werden, um die akzeptable Bundle-Größe beizubehalten. Sehr sehr hilfreich.
Automatisierung
Nun, wir haben bereits die grundlegenden Schritte unternommen, jetzt muss alles automatisiert werden, sonst ist es offen gesagt unpraktisch zu arbeiten.
Dafür brauchen wir noch ein Paket - Husky . Es schreibt Git-Hooks neu und ruft die zugehörigen Befehle von package.json auf. Wenn Sie beispielsweise ein Commit durchführen, funktioniert das Precommit, das Push-Prepush usw. Wenn das Skript einen Fehler zurückgibt, schlägt das Festschreiben fehl.
npm i -D husky
package.json
"precommit":"npm run prettier", "prepush": "call npm run lint && call npm run test"
Hier gibt es eine wichtige Nuance: Die Verwendung der Aufrufsyntax ist nicht plattformübergreifend und wird auf Unix-Systemen nicht gestartet. Wenn Sie also alles ehrlich machen möchten, müssen Sie auch das npm-run-all- Paket installieren. Es funktioniert genauso, jedoch plattformübergreifend.
Posting
Nun, hier kommen wir zur Veröffentlichung unseres (wenn auch leeren) Pakets. Überlegen wir mal, was wir von der Veröffentlichung wollen.
- Testen Sie alles noch einmal
- Sammle Build-Artefakte
- Dokumentation sammeln
- Version anheben
- Tags auslösen
- Senden Sie an npm
Hände machen alles - traurig. Oder Sie vergessen etwas oder müssen eine Checkliste schreiben. Es ist auch notwendig zu automatisieren. Sie können ein anderes Paket setzen - entfesseln . Und Sie können die nativen Hooks von npm selbst verwenden - Preversion, Version, Postversion, zum Beispiel wie folgt:
"preversion": "npm run test", "version": "call npm run clean && call npm run build && npm run bundle && call npm run doc && call npm run changelog && git add . && git commit -m 'changelogupdate'
Für package.json muss noch angegeben werden, was in das Paket aufgenommen werden soll, der Einstiegspunkt und der Pfad zu unseren Typen (vergessen Sie nicht, das Flag --declaration in tsconfig.json anzugeben, um d.ts-Dateien abzurufen).
package.json
"main": "./dist/index.min.js", "types": "./dist/index.d.ts", "files": [ "dist/", "src/", "tests/" ]
Nun, das scheint alles zu sein. Jetzt reicht es zu tun
npm version ... npm publish
Und alles andere wird automatisch erledigt.
Bonus
Als Bonus gibt es ein Demo-Repository , das all dies + CI mit travis-ci unterstützt. Ich möchte Sie daran erinnern, dass HeadlessChrome dort konfiguriert ist. Wenn dies für Sie wichtig ist, empfehle ich Ihnen, dort nachzuschauen.
Danksagung
Vielen Dank an Alexei Volkov für seinen Bericht über das JsFest, der die Grundlage dieses Artikels wurde.
Dank max7z , unzerstörbar , justboris, um zu verdeutlichen, dass Pfade zu lokalen Abhängigkeiten weggelassen werden können.
Und einige Statistiken
- Node_modules Größe: 444 MB (NTFS)
- Anzahl der Abhängigkeiten der ersten Ebene: 17
- Insgesamt verwendete Pakete: 643
Nützliche Links