Mit dem Quelltext an den Schminktisch

Bei Puzzle empfehlen wir in Frontend Projekten Prettier einzusetzen. Lerne warum und wie wir unseren Entwicklern empfehlen den eigenwilligen Quelltext-Formatierer zu verwenden. (English version)

Weshalb Prettier?

Prettier ist ein MIT-lizenziertes Werkzeug um automatisiert Quelltext zu formatieren. Im Frontend-Ökosystem hat es das Tool zu einer beachtlichen Popularität gebracht. Weshalb nicht das Formatierungs-Feature deiner Lieblings-IDE verwenden, hör‘ ich dich fragen? Nun, es gibt ein paar Gründe:

  • Prettier gibt einen bestimmten Stil vor (opinionated), mit nur wenigen Konfigurationsmöglichkeiten. Die Community ist ziemlich erpicht darauf, keine weiteren Optionen hinzuzufügen. Dies erübrigt Debatten über Code Stil und spart Zeit und Energie, welche zur Umsetzung von Kundenfeatures verwendet werden kann. Im Rationale Kapitel der offiziellen Dokumentation kannst du die Begründung der einzelnen Entscheide nachlesen.
  • Prettier ist ein CLI Tool. Dies ermöglicht die Verwendung losgelöst von der IDE, z.B. um es in die SCM/CI Prozesse zu integrieren.
  • Prettier ist Editorunabhängig, mit Unterstützung für die meisten Editoren/IDEs.
  • Prettier kann viele Sprachen formatieren, mit eingebauter Unterstützung für JavaScript, TypeScript, JSON, CSS, SCSS, HTML, Angular Templates, JSX, Markdown und noch viele mehr über das Plugin-Ökosystem.
  • Prettier produziert einen konsistenten Output.

Über JavaScript hinaus

Was als «JavaScript pretty printer» seinen Anfang nahm, entwickelte sich in den letzten Monaten zum vielseitigen Quelltext-Formatierer für unterschiedlichste Sprachen. Dank dem wachsenden Plugin-Ökosystem, gibt es nun auch Unterstützung für Java, Ruby, Python, PHP, ELM, Swift und weitere.

Interessanterweise, wie der Autor des Ruby-Plugins bemerkte, scheint die Plugin API von Prettier ziemlich ausgereift zu sein:

https://twitter.com/kddeisz/status/1095780274384879616

Die Ruby-Plugin Entwickler arbeiten zudem an einem Gem, welches ein eigenständiges Binary für Prettier (mit Hilfe von zeit/pkg) zur Verfügung stellt. Dies erübrigt Ruby Entwicklern die Installation von Node, um Prettier in ihren Projekten einzusetzen.

Aspekte wie diese ebnen möglicherweise den Weg, damit sich Prettier als das Werkzeug der Wahl zur Quelltext-Formatierung für alle möglichen Sprache etablieren kann.

Best practices

Wir empfehlen Prettier dreistufig einzusetzen:

  1. Integration in den Editor durch Formatierung beim Speichern.
  2. Integration ins SCM durch Formatierung beim Comitten (Git Pre-Commit Hook).
  3. Integration ins CI mit einem Linting-Step, welcher fehlschlägt, wenn eine Datei nicht Prettier-formatiert ist.

Weiter sollten folgende Aspekte beachtet werden:

  • Prettier soll immer im Projekt lokal installiert werden, nicht global. Es ist wichtig, dass alle Entickler/Systeme die gleiche Prettier-Version verwenden, da sich der produzierte Stil von Version zu Version unterscheiden kann.
  • Aus demselben Grund soll Prettier im package.json auf eine konkrete Version festgelegt werden (d.h. "prettier": "1.16.4", nicht "prettier": "^1.16.4"). Die Aktualisierung von Prettier kann dann regelmässig manuell erfolgen, inkl. nachträglichem Neuformatieren der gesamten Codebasis (siehe Abschnitt Migration).
  • Zum Schluss sollen beim Linting (z.B. mit ESLint/TSLint) alle Regeln welche den Code Stil betreffen deaktiviert werden, da diese sich durch die automatische Formatierung erübrigen und mit Prettier kollidieren können.

Einrichten

In den folgenden Abschnitten zeige ich detailliert auf, wie Prettier gemäss den oben genannten Best Practices eingerichtet werden kann.

Installation & Konfiguration

Als erstes kann Prettier im Projekt installiert werden, festgelegt auf eine konkrete Version:

yarn add prettier --dev --exact
# oder
npm install --save-dev --save-exact prettier

Hinweis: damit das Projekt-lokale CLI Tool verwenden werden kann muss ./node_modules/.bin im PATHenthalten sein.

Wenn du die Konfiguration anpassen möchtest, kannst du eine .prettierrc Datei erstellen. Wir verwenden einfache Anführungszeichen für JavaScript/TypeScript Dateien und Angular Templates:

{
  "overrides": [
    {
      "files": "*.{js,ts,component.html}",
      "options": {
        "singleQuote": true
      }
    }
  ]
}

Standardmässig ignoriert Prettier das node_modules Verzeichnis. Um weitere Verzeichnisse und Dateien zu ignorieren, kannst du diese in einer .prettierignore Datei definieren, z.B.:

coverage-html-report/
dist/
vendor/

Migration

Wir bereits erwähnt, sollte Prettier immer auf eine konkrete Version festgelegt sein und die Aktualisierung manuell erfolgen. Um Prettier zu aktualisieren, kann folgender Befehl ausgeführt werden:

yarn upgrade --exact prettier@latest
# oder
npm install --save-exact prettier@latest

Nach jedem Update, oder wenn Prettier in einem existierenden Projekt neu einerichtet wurde, musst du die gesamte Codebasis neu formatieren. Der Einfachheit halber empfehlen wir dazu einen Task im package.json einzurichten:

{
  "scripts": {
    "format": "prettier --write \"./**/*.{js,ts,json,css,scss,html,md,yaml}\""
  }
}

Mit diesem Script muss lediglich folgender Befehl ausgeführt werden um den Quelltext des Projekts neu zu formatieren:

yarn format
# oder
npm run format

git commit -a -m "Reformat sources after Prettier update"

Adieu Style-Linting

Mit dem Einsatz von Prettier erübrigt sich das Style-Linting mit ESLint oder TSLint und sollte deaktiviert werden. Glückerweise helfen uns dabei die offiziellen Pakete eslint-config-prettier und tslint-config-prettier. Diese können wiefolgt installiert werden (in diesem Beispiel für TSLint):

yarn add --dev tslint-config-prettier
# oder
npm install --save-dev tslint-config-prettier

Danach können in der TSLint Konfigurationsdatei (tslint.json) die Stilregeln überschrieben werden, indem das Prettier-Regelset ganz am Schluss (wichtig!) der erweiterten Regelsets eingebunden wird:

{
  "extends": [
    "tslint:recommended",
    "codelyzer",
    "tslint-config-prettier"
  ]
}

Alle Regeln, welche direkt in der TSLint Konfigurationsdatei unter "rules" definiert sind, müssen auch entfernt werden. Die Prettier-Pakete bieten ein nützliches Tool an, mit dem die betroffenen Regeln ausgegeben werden können:

tslint-config-prettier-check ./tslint.json
# oder
eslint --print-config . | eslint-config-prettier-check

Integration in den Editor

Prettier bietet für die meisten Editoren Integrationsmöglichkeiten zum Formatieren des Quelltexts beim Speichern oder über eine Tastenkombination an: Emacs, VIM, Visual Studio Code, Atom, Sublime Text, JetBrains IntelliJ und Studio.

Die Seite Editor Integration enthält spezifische Anleitungen für die einzelnen Editoren.

Pre-Commit Hook

Wir empfehlen einen Git Pre-Commit Hook mit Husky und lint-staged einzurichten. Dazu müssen die folgenden zwei Pakete installiert werden:

yarn add lint-staged husky --dev
# oder
npm install --save-dev lint-staged husky

Danach kann folgende Konfiguration im package.json hinzugefügt werden:

"husky": {
     "hooks": {
         "pre-commit": "lint-staged"
     }
},
"lint-staged": {
  "./**/*.{js,ts,json,css,scss,html,md,yaml}": [
    "prettier --write",
    "git add"
  ]
}

Von nun an wird der Quelltext beim Committen formatiert, selbst wenn die Editorintegration nicht konfiguriert oder nicht funktionieren sollte.

Um zusätzlich ESLint/TSLint vor dem Formatierungsprozess auszuführen, kann die Konfiguration entsprechend erweitert werden (in diesem Beispiel für TSLint):

"lint-staged": {
  "linters": {
    "./src/**/*.ts": [
      "tslint",
      "prettier --write",
      "git add"
    ],
    "./**/*.{js,json,css,scss,html,md,yaml}": [
      "prettier --write",
      "git add"
    ]
  }
}

Prettier Linting-Schritt im CI

Als letzte Stufe empfehlen wird einen Linting-Schritt im CI einzurichten, der greift, sollte der Pre-Commit Hook nicht zum Zug kommen. Auch hier können die offiziellen Pakete eslint-plugin-prettier und tslint-plugin-prettier genutzt werden (in diesem Beispiel für TSLint):

npm install --save-dev tslint-plugin-prettier
# oder
yarn add --dev tslint-plugin-prettier

Wir erstellen dann eine separate TSLint Konfigurationsdatei (tslint-prettier.json), mit welcher ausschliesslich die Formatierung überprüft wird:

{
  "extends": ["tslint-plugin-prettier"],
  "rules": {
    "prettier": true
  }
}

Der Vorteil von zwei getrennten Konfigurationen ist, dass lokal kein Style-Linting gemacht werden muss und im Pre-Commit Hook das Standard-Linting vor Prettier ausgeführt werden kann.

In der Annahme es gibt bereits einen lint Task im package.json, kann ein weiterer Task hinzugefügt werden, welche die obige Konfiguration nutzt:

{
  "scripts": {
    "lint": "tslint \"src/**/*.ts\" -e \"src/**/*.spec.ts\"",
    "lint:format": "tslint -c tslint-prettier.json \"src/**/*.ts\""
  }
}

Dieser Task kann dann in der CI Pipeline verwendet werden:

yarn lint:format
# oder
npm run lint:format

Hinweis: dieser Task überprüft nur die Formatierung von JavaScript/TypeScript Dateien.

Fazit

Ich hoffe ich konnte dich für den Einsatz von Prettier in deinen Projekten überzeugen und konnte unsere Best Practices veranschaulichen. Es gilt noch eine wichtige Warnung auszusprechen: einmal mit Prettier angefangen gibt es kein Zurück mehr! 🤩

HappyPretty hacking!

Bild: Creative Commons CC0 Public Domain, Quelle

Kommentare sind geschlossen.