Es gibt eine wachsende Meinung (z. B. zum Beispiel), dass die direkte Verwendung von Node-Paketen mit den von ihnen bereitgestellten Kommandozeilenbefehlen ein guter Weg ist. Im Gegensatz zur Abstraktion der Funktionalität hinter einem Task-Runner. Teilweise: Man benutzt sowieso npm, npm bietet Skript-Funktionalität, warum nicht einfach diese nutzen? Aber es steckt mehr dahinter. Lassen Sie uns die Überlegungen durchgehen, aber auch genau, wie man viele der wichtigsten Aufgaben in einem Frontend-Entwicklungs-Build-Prozess erledigt.
Ich verwende jetzt seit etwa sechs Monaten npm-Skripte in meinen Projekten. Davor habe ich Gulp und davor Grunt verwendet. Sie haben mir gute Dienste geleistet und mir geholfen, meine Arbeit schneller und effizienter zu erledigen, indem sie viele Dinge automatisierten, die ich früher von Hand erledigte. Ich begann jedoch das Gefühl zu haben, dass ich gegen die Werkzeuge kämpfte, anstatt mich auf meinen eigenen Code zu konzentrieren.
Grunt, Gulp, Broccoli, Brunch und ähnliche Tools erfordern alle, dass man seine Aufgaben an ihre Paradigmen und Konfigurationen anpasst. Jedes hat seine eigenen Syntaxen, Eigenheiten und Tücken, die man lernen muss. Dies erhöht die Codekomplexität, die Build-Komplexität und zwingt einen, sich auf die Behebung von Werkzeugen zu konzentrieren, anstatt Code zu schreiben.
Diese Build-Tools sind auf Plugins angewiesen, die ein Kern-Kommandozeilen-Tool umschließen. Dies schafft eine weitere Abstraktionsebene vom Kern-Tool, was mehr Potenzial für Probleme bedeutet.
Hier sind drei Probleme, die ich mehrmals gesehen habe
- Wenn es kein Plugin für das Kommandozeilen-Tool gibt, das Sie verwenden möchten, haben Sie Pech (es sei denn, Sie schreiben es selbst).
- Ein Plugin, das Sie zu verwenden versuchen, umschließt eine ältere Version des Tools, das Sie verwenden möchten. Features und Dokumentation stimmen nicht immer zwischen dem von Ihnen verwendeten Plugin und der aktuellen Version des Kern-Tools überein.
- Fehler werden nicht immer gut behandelt. Wenn ein Plugin fehlschlägt, gibt es möglicherweise nicht die Fehlermeldung des Kern-Tools weiter, was zu Frustration führt und man weiß nicht wirklich, wie man das Problem debuggt.
Aber, bedenken Sie…
Lassen Sie mich das sagen: Wenn Sie mit Ihrem aktuellen Build-System zufrieden sind und es alles leistet, was Sie benötigen, können Sie es weiterhin verwenden! Nur weil npm-Skripte beliebter werden, heißt das nicht, dass Sie das Schiff wechseln sollten. Konzentrieren Sie sich weiterhin auf das Schreiben Ihres Codes, anstatt mehr Werkzeuge zu lernen. Wenn Sie das Gefühl bekommen, dass Sie mit Ihren Werkzeugen kämpfen, dann würde ich in Erwägung ziehen, npm-Skripte zu verwenden.
Wenn Sie sich entschieden haben, npm-Skripte zu untersuchen oder zu verwenden, lesen Sie weiter! Im Rest dieses Beitrags finden Sie viele Beispielaufgaben. Außerdem habe ich npm-build-boilerplate mit all diesen Aufgaben erstellt, das Sie als Ausgangspunkt verwenden können. Los geht's!
npm-Skripte schreiben
Den Großteil unserer Zeit werden wir in einer `package.json`-Datei verbringen. Hier leben alle unsere Abhängigkeiten und Skripte. Hier ist eine abgespeckte Version aus meinem Boilerplate-Projekt
{
"name": "npm-build-boilerplate",
"version": "1.0.0",
"scripts": {
...
},
"devDependencies": {
...
}
}
Wir werden unsere `package.json`-Datei im Laufe der Zeit aufbauen. Unsere Skripte kommen in das `scripts`-Objekt, und alle Werkzeuge, die wir verwenden möchten, werden installiert und in das `devDependencies`-Objekt aufgenommen.
Bevor wir beginnen, hier ist eine Beispielstruktur des Projekts, auf das ich im gesamten Beitrag Bezug nehmen werde

SCSS zu CSS kompilieren
Ich bin ein starker Nutzer von SCSS, daher werde ich damit arbeiten. Um SCSS zu CSS zu kompilieren, wende ich mich an node-sass. Zuerst müssen wir `node-sass` installieren; tun Sie dies, indem Sie Folgendes in Ihrer Kommandozeile ausführen
npm install --save-dev node-sass
Dies installiert `node-sass` in Ihrem aktuellen Verzeichnis und fügt es dem `devDependencies`-Objekt in Ihrer `package.json` hinzu. Dies ist besonders nützlich, wenn jemand anderes Ihr Projekt ausführt, da er alles hat, was er braucht, um das Projekt zum Laufen zu bringen. Nach der Installation können wir es auf der Kommandozeile verwenden
node-sass --output-style compressed -o dist/css src/scss
Lassen Sie uns aufschlüsseln, was dieser Befehl tut. Beginnend am Ende sagt er: Schau im `src/scss`-Ordner nach allen SCSS-Dateien; gib die kompilierten CSS-Dateien im Ordner `dist/css` aus (Flag `-o`); komprimiere die Ausgabe (mit dem Flag `--output-style` mit "compressed" als Option).
Jetzt, da wir das auf der Kommandozeile zum Laufen gebracht haben, verschieben wir es in ein npm-Skript. Fügen Sie es in Ihrem `scripts`-Objekt von `package.json` wie folgt hinzu
"scripts": {
"scss": "node-sass --output-style compressed -o dist/css src/scss"
}
Gehen Sie nun zurück zur Kommandozeile und führen Sie
npm run scss
Sie sehen dieselbe Ausgabe wie bei der direkten Ausführung des `node-sass`-Befehls in der Kommandozeile.
Jedes Mal, wenn wir in diesem Beitrag ein npm-Skript erstellen, können Sie es mit einem Befehl wie dem obigen ausführen.
Ersetzen Sie einfach `scss` durch den Namen der Aufgabe, die Sie ausführen möchten.
Wie Sie sehen werden, haben viele der Kommandozeilen-Tools, die wir verwenden werden, zahlreiche Optionen, mit denen Sie sie genau nach Ihren Wünschen konfigurieren können. Zum Beispiel hier die Liste der (node-sass Optionen). Hier ist eine andere Konfiguration, die zeigt, wie mehrere Optionen übergeben werden können
"scripts": {
"scss": "node-sass --output-style nested --indent-type tab --indent-width 4 -o dist/css src/scss"
}
CSS mit PostCSS autoprefixen
Da wir jetzt SCSS zu CSS kompilieren, können wir mit Autoprefixer & PostCSS automatisch Vendor-Präfixe hinzufügen. Wir können mehrere Module gleichzeitig installieren, getrennt durch Leerzeichen
npm install --save-dev postcss-cli autoprefixer
Wir installieren zwei Module, da PostCSS standardmäßig nichts tut. Es stützt sich auf andere Plugins wie Autoprefixer, um das von Ihnen bereitgestellte CSS zu manipulieren.
Nachdem die notwendigen Werkzeuge installiert und in `devDependencies` gespeichert wurden, fügen Sie eine neue Aufgabe in Ihrem `scripts`-Objekt hinzu
"scripts": {
...
"autoprefixer": "postcss -u autoprefixer -r dist/css/*"
}
Diese Aufgabe besagt: Hey `postcss`, verwende (Flag `-u`) `autoprefixer`, um alle `.css`-Dateien in `dist/css` mit Vendor-Prefixed-Code zu ersetzen (Flag `-r`). Das war's! Müssen Sie die Standardbrowserunterstützung für Autoprefixer ändern? Es ist einfach, es zum Skript hinzuzufügen
"autoprefixer": "postcss -u autoprefixer --autoprefixer.browsers '> 5%, ie 9' -r dist/css/*"
Auch hier gibt es viele Optionen, die Sie zur Konfiguration Ihrer eigenen Builds verwenden können: postcss-cli und autoprefixer.
JavaScript-Linting
Die Einhaltung eines standardisierten Formats und Stils beim Schreiben von Code ist wichtig, um Fehler zu minimieren und die Entwicklereffizienz zu steigern. "Linting" hilft uns dabei automatisch, also fügen wir JavaScript-Linting hinzu, indem wir eslint verwenden.
Installieren Sie das Paket noch einmal; diesmal verwenden wir eine Abkürzung
npm i -D eslint
Dies ist dasselbe wie
npm install --save-dev eslint
Nach der Installation richten wir einige grundlegende Regeln ein, gegen die unser Code geprüft wird, mit `eslint`. Führen Sie Folgendes aus, um einen Assistenten zu starten
eslint --init
Ich schlage vor, "Fragen zu Ihrem Stil beantworten" zu wählen und die gestellten Fragen zu beantworten. Dies erstellt eine neue Datei im Stammverzeichnis Ihres Projekts, gegen die `eslint` Ihren Code prüft.
Nun fügen wir eine Lint-Aufgabe zu unserem `scripts`-Objekt in `package.json` hinzu
"scripts": {
...
"lint": "eslint src/js"
}
Unsere Lint-Aufgabe ist 13 Zeichen lang! Sie sucht nach allen JavaScript-Dateien im Ordner `src/js` und führt sie gegen die zuvor erstellte Konfiguration aus. Natürlich können Sie mit den Optionen verrückt werden.
JavaScript-Dateien verkleinern
Lassen Sie uns daran arbeiten, unsere JavaScript-Dateien zu kombinieren und zu minifizieren, wozu wir uglify-js verwenden können. Wir müssen zunächst `uglify-js` installieren
npm i -D uglify-js
Dann können wir unsere Uglify-Aufgabe in `package.json` einrichten
"scripts": {
...
"uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.js"
}
Eines der großartigen Dinge an npm-Skripten ist, dass sie im Wesentlichen ein Alias für eine Kommandozeilenaufgabe sind, die Sie immer wieder ausführen möchten. Das bedeutet, dass Sie Standard-Kommandozeilen-Code direkt in Ihrem Skript verwenden können! Diese Aufgabe verwendet zwei Standard-Kommandozeilenfunktionen: `mkdir` und `&&`.
Der erste Teil dieser Aufgabe, `mkdir -p dist/js`, besagt: Erstelle eine Ordnerstruktur (`mkdir`), aber nur, wenn sie noch nicht existiert (`-p`-Flag). Sobald das erfolgreich abgeschlossen ist, führe den `uglifyjs`-Befehl aus. Das `&&` ermöglicht es Ihnen, mehrere Befehle zu verketten und jeden nacheinander auszuführen, *wenn* der vorherige Befehl erfolgreich abgeschlossen wurde.
Der zweite Teil dieser Aufgabe weist `uglifyjs` an, mit allen JS-Dateien (`*.js`) in `src/js/` zu beginnen, den "mangle"-Befehl anzuwenden (Flag `-m`) und das Ergebnis nach `dist/js/app.js` auszugeben. Überprüfen Sie noch einmal die Dokumentation des betreffenden Tools für eine vollständige Liste von Optionen.
Aktualisieren wir unsere `uglify`-Aufgabe, um eine komprimierte Version von `dist/js/app.js` zu erstellen. Verkette einen weiteren `uglifyjs`-Befehl und übergib das Flag "compress" (`-c`)
"scripts": {
...
"uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.js && uglifyjs src/js/*.js -m -c -o dist/js/app.min.js"
}
Bilder komprimieren
Wenden wir uns nun der Komprimierung von Bildern zu. Laut httparchive.org beträgt das durchschnittliche Seiten-Gewicht der Top-1000-URLs im Internet 1,9 MB, wobei Bilder 1,1 MB dieses Gesamtbetrags ausmachen. Eines der besten Dinge, das Sie zur Steigerung der Seitengeschwindigkeit tun können, ist die Reduzierung der Größe Ihrer Bilder.
Installieren Sie imagemin-cli
npm i -D imagemin-cli
Imagemin ist großartig, da es die meisten Bildtypen, einschließlich GIF, JPG, PNG und SVG, komprimiert. Sie können ihm einen Ordner mit Bildern übergeben, und er wird sie alle bearbeiten, wie hier
"scripts": {
...
"imagemin": "imagemin src/images dist/images -p",
}
Diese Aufgabe weist `imagemin` an, alle Bilder in `src/images` zu finden und zu komprimieren und sie in `dist/images` abzulegen. Das Flag `-p` wird übergeben, um "progressive" Bilder zu erstellen, wo immer möglich. Überprüfen Sie die Dokumentation für alle verfügbaren Optionen.
SVG-Sprites
Die Begeisterung für SVG ist in den letzten Jahren gestiegen, und das aus gutem Grund. Sie sind gestochen scharf auf allen Geräten, mit CSS editierbar und bildschirmleserfreundlich. Allerdings hinterlassen SVG-Bearbeitungssoftware normalerweise überflüssige und unnötige Codes. Glücklicherweise kann svgo helfen, all das zu entfernen (wir werden es unten installieren).
Sie können auch den Prozess des Kombinierens und Spriting Ihrer SVGs automatisieren, um eine einzelne SVG-Datei zu erstellen (mehr über diese Technik hier). Um diesen Prozess zu automatisieren, können wir svg-sprite-generator installieren.
npm i -D svgo svg-sprite-generator
Das Muster ist Ihnen wahrscheinlich mittlerweile vertraut: Nach der Installation fügen Sie eine Aufgabe in Ihrem `scripts`-Objekt von `package.json` hinzu
"scripts": {
...
"icons": "svgo -f src/images/icons && mkdir -p dist/images && svg-sprite-generate -d src/images/icons -o dist/images/icons.svg"
}
Beachten Sie, dass die `icons`-Aufgabe drei Dinge tut, basierend auf der Anwesenheit von zwei `&&`-Direktiven. Erstens verwenden wir `svgo`, übergeben einen Ordner (Flag `-f`) von SVGs; dies komprimiert alle SVGs im Ordner. Zweitens erstellen wir den Ordner `dist/images`, falls er noch nicht existiert (mit dem Befehl `mkdir -p`). Drittens verwenden wir `svg-sprite-generator`, übergeben ihm einen Ordner von SVGs (Flag `-d`) und einen Pfad, wohin wir den SVG-Sprite ausgeben möchten (Flag `-o`).
Server starten und Änderungen automatisch mit BrowserSync injizieren
Eines der letzten Puzzleteile ist BrowserSync. Einige Dinge, die es tun kann: einen lokalen Server starten, aktualisierte Dateien automatisch in jeden verbundenen Browser injizieren und Klicks & Scrollen zwischen Browsern synchronisieren. Installieren Sie es und fügen Sie eine Aufgabe hinzu
npm i -D browser-sync
"scripts": {
...
"serve": "browser-sync start --server --files 'dist/css/*.css, dist/js/*.js'"
}
Unsere BrowserSync-Aufgabe startet einen Server (Flag `--server`), der den aktuellen Pfad standardmäßig als Root verwendet. Das Flag `--files` weist BrowserSync an, nach CSS- oder JS-Dateien im Ordner `dist` zu suchen. Immer wenn sich etwas darin ändert, werden die geänderten Dateien automatisch in die Seite injiziert.
Sie können mehrere Browser (sogar auf verschiedenen Geräten) öffnen, und alle erhalten in Echtzeit aktualisierte Dateianpassungen!
Aufgaben gruppieren
Mit all den Aufgaben von oben können wir
- SCSS zu CSS kompilieren und automatisch Vendor-Präfixe hinzufügen
- JavaScript linten und verkleinern
- Bilder komprimieren
- Einen Ordner mit SVGs in einen einzelnen SVG-Sprite konvertieren
- Einen lokalen Server starten und Änderungen automatisch in jeden mit dem Server verbundenen Browser injizieren
Hören wir nicht auf!
CSS-Aufgaben kombinieren
Fügen wir eine Aufgabe hinzu, die die beiden CSS-bezogenen Aufgaben (Sass-Preprocessing und Ausführung von Autoprefixer) kombiniert, damit wir sie nicht einzeln ausführen müssen
"scripts": {
...
"build:css": "npm run scss && npm run autoprefixer"
}
Wenn Sie `npm run build:css` ausführen, wird die Kommandozeile angewiesen, `npm run scss` auszuführen; wenn dies erfolgreich abgeschlossen ist, wird dann (`&&`) `npm run autoprefixer` ausgeführt.
Genau wie bei unserer `build:css`-Aufgabe können wir unsere JavaScript-Aufgaben verketten, um die Ausführung zu erleichtern
JavaScript-Aufgaben kombinieren
"scripts": {
...
"build:js": "npm run lint && npm run uglify"
}
Jetzt können wir `npm run build:js` aufrufen, um unser JavaScript in einem Schritt zu linten, zu verketten und zu verkleinern!
Verbleibende Aufgaben kombinieren
Das Gleiche können wir für unsere Bildaufgaben tun, sowie eine Aufgabe, die alle Build-Aufgaben in einer zusammenfasst
"scripts": {
...
"build:images": "npm run imagemin && npm run icons",
"build:all": "npm run build:css && npm run build:js && npm run build:images",
}
Auf Änderungen warten
Bis zu diesem Punkt erfordern unsere Aufgaben, dass wir Änderungen an einer Datei vornehmen, zurück zum Kommandozeilenfenster wechseln und die entsprechenden Aufgaben ausführen. Eines der nützlichsten Dinge, die wir tun können, ist das Hinzufügen von Aufgaben, die auf Änderungen warten und Aufgaben automatisch ausführen, wenn Dateien geändert werden. Um dies zu tun, empfehle ich die Verwendung von onchange. Installieren wie üblich
npm i -D onchange
Lassen Sie uns Watch-Aufgaben für CSS und JavaScript einrichten
"scripts": {
...
"watch:css": "onchange 'src/scss/*.scss' -- npm run build:css",
"watch:js": "onchange 'src/js/*.js' -- npm run build:js",
}
Hier ist die Aufschlüsselung dieser Aufgaben: `onchange` erwartet, dass Sie einen Pfad als Zeichenkette für die Dateien übergeben, die Sie überwachen möchten. Wir werden unsere Quell-SCSS- und JS-Dateien zum Überwachen übergeben. Der Befehl, den wir ausführen möchten, kommt nach den `--`, und er wird jedes Mal ausgeführt, wenn eine Datei im angegebenen Pfad hinzugefügt, geändert oder gelöscht wird.
Fügen wir noch einen Watch-Befehl hinzu, um unseren npm-Skripte-Build-Prozess abzuschließen.
Installieren Sie noch ein Paket, parallelshell
npm i -D parallelshell
Fügen Sie erneut eine neue Aufgabe zum `scripts`-Objekt hinzu
"scripts": {
...
"watch:all": "parallelshell 'npm run serve' 'npm run watch:css' 'npm run watch:js'"
}
`parallelshell` nimmt mehrere Zeichenketten entgegen, denen wir mehrere `npm run`-Aufgaben übergeben.
Warum `parallelshell` verwenden, um mehrere Aufgaben zu kombinieren, anstatt `&&` wie in früheren Aufgaben zu verwenden? Zuerst habe ich das versucht. Das Problem ist, dass `&&` Befehle verkettet und darauf wartet, dass jeder Befehl *erfolgreich abgeschlossen* wird, bevor der nächste gestartet wird. Da wir jedoch `watch`-Befehle ausführen, werden diese niemals beendet! Wir würden in einer Endlosschleife stecken bleiben.
Daher ermöglicht uns die Verwendung von `parallelshell`, mehrere `watch`-Befehle gleichzeitig auszuführen.
Diese Aufgabe startet einen Server mit BrowserSync über die Aufgabe `npm run serve`. Dann startet sie unsere Watch-Aufgaben für CSS- und JavaScript-Dateien. Jedes Mal, wenn eine CSS- oder JavaScript-Datei geändert wird, führt die Watch-Aufgabe eine entsprechende Build-Aufgabe aus; da BrowserSync so konfiguriert ist, dass es auf Änderungen im `dist`-Ordner achtet, injiziert es automatisch neue Dateien in jeden Browser, der mit seiner URL verbunden ist. Super!
Weitere nützliche Aufgaben
`npm` kommt mit vielen integrierten Aufgaben, in die Sie eingreifen können. Lassen Sie uns noch eine Aufgabe schreiben, die eine dieser integrierten Skripte nutzt.
"scripts": {
...
"postinstall": "npm run watch:all"
}
`postinstall` wird sofort ausgeführt, nachdem Sie `npm install` in Ihrer Kommandozeile ausgeführt haben. Dies ist ein Nice-to-have, besonders wenn Sie in Teams arbeiten. Wenn jemand Ihr Projekt klont und `npm install` ausführt, startet sofort unsere `watch:all`-Aufgabe. Sie haben automatisch einen Server gestartet, ein Browserfenster geöffnet und die Dateien werden auf Änderungen überwacht.
Zusammenfassung
Puh! Wir haben es geschafft! Ich hoffe, Sie konnten ein paar Dinge über die Verwendung von npm-Skripten als Build-Prozess und die Kommandozeile im Allgemeinen lernen.
Falls Sie es verpasst haben, habe ich ein npm-build-boilerplate-Projekt mit all diesen Aufgaben erstellt, das Sie als Ausgangspunkt verwenden können. Wenn Sie Fragen oder Kommentare haben, twittern Sie mich an oder hinterlassen Sie unten einen Kommentar. Ich helfe Ihnen gerne weiter!
Der Wechsel zu npm-Skripten ist großartig, aber wenn Sie ein Open-Source-Projekt pflegen und Beiträge maximieren möchten, stellen Sie bitte sicher, dass Ihre Skripte auch auf Nicht-Unix-Maschinen funktionieren. Die größte plattformübergreifende Schwierigkeit liegt bei der Einstellung von Umgebungsvariablen (z. B. NODE_ENV). Eine großartige Bibliothek dafür ist better-npm-run.
Ein weiteres Problem ist das Kommentieren Ihres Codes und generell das lesbare und wartbare Halten. Ich habe gulp-shelter entwickelt, um das Beste aus npm-Skripten und Gulpfiles zu kombinieren, ohne das Rad neu zu erfinden.
Anstelle von parallelshell habe ich festgestellt, dass npm-run-all recht nützlich ist. Es erlaubt Globbing von Aufgaben bei deren Ausführung, z. B.
Dasselbe gilt für den Build-Schritt
Gut! Von diesem Paket hatte ich noch nichts gehört. Danke, dass Sie es darauf hingewiesen haben!
Ich denke, es gibt sicherlich gültige Argumente gegen die (vielleicht) unnötige Abstraktion Ihres Codes in Task-Runnern.
Installieren Sie in all Ihren obigen Beispielen alle diese Dinge global? node-sass, postcss, onchange usw.? Oder sind sie immer noch nur lokal im Projektverzeichnis?
Sie installieren sie lokal, was das -D-Flag bewirkt (obwohl ich glaube, dass der Befehl `eslint --init` im Artikel zunächst eine global installierte Version verwendet). Aber NPM-Skripte haben `node_modules/.bin/` verfügbar, sodass alle von Ihnen installierten Module ihre ausführbaren Dateien dort ablegen und Sie in Ihren NPM-Skripten darauf verweisen können, als wären sie global installiert. Wenn sie also lokal installiert sind, können Sie `eslint ...` immer noch in Ihr Lint-Skript einfügen und es wird immer noch die lokale Version für Ihr Projekt verwendet, wenn es ausgeführt wird.
Das ist großartig, danke — ich benutze schon ewig Makefiles (schreckliche Syntax), und ich hatte immer das Gefühl, dass die "Task-Runner" unnötig waren.
Was mich ärgert, ist, dass ich nie daran gedacht habe, die "Skripte" von npm auf diese Weise als glorifizierte Makefiles zu verwenden, und ich gehe jetzt zur ernsthaften Selbstbefragung über, um herauszufinden, warum :-)
Wahrscheinlich haben Sie nie darüber nachgedacht, denn warum sollten Sie? Wenn Sie bereits Make verwenden und Unix-Anwendungen entwickeln, warum sollten Sie stattdessen npm-Skripte verwenden? Make kann bereits genau das tun, was das alles leistet.
Ich habe auch Make für Frontend-Builds verwendet (einschließlich bestimmter anwendungsspezifischer Deployment-Aufgaben).
Wie Sie sagen, Make ist für all das gut genug, aber da ich sowieso Node benutze, schadet es nicht, die bombastischen Task-Runner über Bord zu werfen (und Make, während ich schon dabei bin).
Aber das hätte ich selbst bedenken sollen, da meine Tendenz ohnehin zu einfacheren Build-Systemen geht.
Da Sie die Skripte bereits in die composer.json-Datei einfügen, gab es einen Grund, npm zu verwenden, um sie auszuführen, anstatt Composer?
https://getcomposer.org/doc/articles/scripts.md
Ich benutze Gulp mit Node seit etwa 8 Monaten und füge und verbessere meine Aufgaben, während ich arbeite. Ich habe jetzt einen sehr guten Boilerplate, den ich am Anfang jedes Projekts herunterlade. Alles ist an meine Standardaufgabe gebunden, also gebe ich einfach "gulp" in die Kommandozeile meines Atom-Texteditors ein und innerhalb von Sekunden wird alles für mich erstellt. Ich musste dies bisher nicht weiter vereinfachen. Es ist bereits dumm einfach und die einzigen "Schwierigkeiten", die ich hatte, wurden durch Ausführen von "npm update" gelöst. Trotzdem, Hut ab für das großartige Tutorial!
Ich versuche, npm-Skripte so oft wie möglich zu verwenden. Wenn eine Aufgabe zu aufwendig ist, schreibe ich sie als Gulp-Aufgabe. Wenn eine Abfolge von Aufgaben zu langsam ist und übersprungen werden kann, anstatt wiederholt zu werden, verwende ich Make, um die Abfolge zu orchestrieren.
Hier ist ein Beitrag über das Kompilieren von Sass mit Gulp, das viel schneller ist als das Kompilieren mit npm-Skripten
Ich habe in einigen Projekten mit Grunt, Gulp und npm-Skripten gearbeitet und derzeit ist Gulp mein Favorit wegen seiner Einfachheit, Geschwindigkeit und Stream-basierten Natur. Wir sind in einem unserer Projekte sogar von npm-Skripten zu Gulp umgestiegen, da die Skripte ziemlich unübersichtlich waren: Sie enthielten wiederholte Konfigurationen, die wir aufgrund fehlender Variablen nicht vereinfachen konnten, und das "scripts" JSON-Objekt sah einfach nur wie ein hässlicher Textblock aus, mit dem Risiko, nicht plattformübergreifend zu sein und keiner Möglichkeit, es zu dokumentieren.
Aber ja, npm-Skripte bleiben meine erste Wahl für kleine Projekte. Meiner Meinung nach ist der Schlüsseltrick zu wissen, wann man etwas Leistungsfähigeres und Verwaltbareres wählt. Ansonsten hat man eben das, was man von npm kostenlos bekommt.
Ich wähle
:P
postinstallwerde ich definitiv ausprobieren. Derzeit benutze ichnpm start, was eine schöne Abkürzung und ein Verweis auf das Hauptskript zum Ausführen ist.Cooler Artikel!
Kein Schritt in Ihrem Setup für Cachebusting?
Ich dachte nicht, dass es für die Zwecke dieses Beitrags zwingend erforderlich sei; aber wenn ich Cache Busting hinzufügen müsste, würde ich dieses Modul verwenden: https://www.npmjs.com/package/hashmark.
Ich werde sehen, ob ich diese Aufgabe zum Boilerplate hinzufüge, auf das im Beitrag verwiesen wird.
Ich bin definitiv an der Idee interessiert, npm für alles zu verwenden (ich habe kürzlich Bower aufgegeben, da alle Front-End-Pakete, die ich verwende, jetzt auf npm verfügbar sind, also warum zwei Paketmanager verwenden?). Allerdings bin ich auch kürzlich von Grunt zu Gulp gewechselt, hauptsächlich weil ich festgestellt habe, dass es mir erhebliche Geschwindigkeitsverbesserungen brachte, die vermutlich aus der Art und Weise stammen, wie Gulp Streams verwendet, um aufeinanderfolgende Aufgaben im Speicher und nicht auf der Festplatte auszuführen. (Auf meinem Rechner dauern Aufgaben, die zuvor bei Grunt über eine Sekunde dauerten, bei Gulp fast sofort.)
Ich vermute, dass dieser Vorteil von Gulp durch den Wechsel zum oben beschriebenen Ansatz verloren gehen würde...? Soweit ich sehen kann, scheint es, dass jede aufeinanderfolgende Aufgabe von der Festplatte lesen und dann auf die Festplatte schreiben würde. Ich frage mich, ob es eine Möglichkeit gibt, npm-Skripte zu verwenden, aber Pipes/Streams so zu verwenden, wie es Gulp tut?
Es ist großartig, vor ein paar Tagen habe ich mit Dockerizing mit Node.js gearbeitet, weil unter Windows keine Wildcards unterstützt werden (z. B. ./js/*.js). Hier ist mein Repo: https://github.com/andru255/learn-npm-buildtool und ich freue mich über Feedback :)
Zuerst möchte ich Ihnen für den Artikel danken. Sie haben beschrieben, wie einfach Sie
npm runverwenden können, um einige Dateioperationen anstelle von Gulp/Grunt durchzuführen. Leider kann diese Methode, die Aufgabe von Streaming-Build-Systemen zu erledigen, bei komplizierteren Anwendungsfällen nicht durchgeführt werden.Was ist mit Sourcemaps (extrem nützlich, wenn Sass/Less verwendet wurden) –
gulp-sourcemaps?Was ist mit Umgebungsbedingungen (generiere keine Sourcemaps in der Produktion oder minifiere JS/CSS in der Produktion, niemals in der Entwicklungsumgebung) –
gulpIf.Gleiches gilt für andere Fälle, in denen die Gulp/Grunt-Plugins durch eine verfeinerte Funktion angepasst werden müssen, die erweiterte Dinge beschreibt. Ich würde also sagen, dass der Ersatz eines z. B. Gulp Zeitverschwendung ist oder vielmehr genau die gleiche Arbeit erledigt, was Sie tun können, indem Sie nur drei oder mehr Module in einer Gulp-Aufgabe einrichten. Was ist der Sinn, sich zu wiederholen, wenn es bereits mit einem Task-Runner erledigt ist? Warum verwenden wir Code-Schnipsel oder erweiterte IDEs anstelle von
nano/pico/notepad? Es geht nur darum, produktiv zu sein, denke ich.Sourcemaps und Umgebungseinstellungen sind definitiv die Dinge, die mich von der Verwendung von npm-Skripten abhalten. Ich würde mich freuen, wenn jemand eine clevere Lösung hätte.
„min-sass“: „node-sass resources/sass/main.scss | cleancss -o public/stylesheets/main.min.css –source-map“
npm run min-sass
Dies ist eine weitere Möglichkeit, alle Build-Aufgaben zu erledigen, aber ich würde praktisch prüfen, ob dies einen Leistungsvorteil bringt oder erhebliche Zeit spart, bevor ich darauf umsteige.
Wenn jemand Statistiken über Leistung/Zeitaufwand/Reduzierung der Komplexität hat, bitte teilen.
Für kleine Projekte bin ich definitiv auf NPM-Skripte eingestellt, da ich manchmal nur CSS- und JS-Dateien zusammen mit Webpack für RiotJS, React und Angular-Bundles squash. Ich entwickle normalerweise aufbauend auf Laravel, Express oder Meteor, die bereits etwas Sass- oder JS-Magie haben. Ich liebe Meteor, weil manchmal viel Magie schön ist, um Dinge zu erledigen. Alles passiert einfach. Für einige Projekte ist die Meteor-Magie im Vergleich zu alkoholinduzierenden Gulp-Build-Alpträumen, nur um etwas live zu bringen, genau das Richtige.
Und noch etwas, wenn Sie einfach für ein Projekt mit Stylus (oder CSS) und Jade (oder HTML) loslegen möchten
Es ist die Bao-Methode für kleinere Dinge.
Ansonsten fange ich an, eine Neigung dazu zu entwickeln, die Dinge eher Vanilla Node zu halten. Mit
require('child_process').execoderrequire('child_process').execSynckönnen Sie jeden Befehl wie im Terminal laden. Ich habe ein kleines Skript erstellt, das Java (und meine Tests) für ein Schulprojekt kompiliert und ausführt. Wirklich einfach einzurichten und damit zu arbeiten. Ich habe Gulp zum Beobachten von Dateien und für die CLI verwendet, aber ich kann mir nicht vorstellen, dass es so schwierig ist, etwas dafür bei npm zu finden. (FYI: execSync zum Kompilieren und exec zum Ausführen des Programms/Tests. Wenn eine neue Ausführung durchgeführt wird, rufe ichrunningProgram.kill('SIGKILL')auf dem laufenden Programm auf)npm-Skripte gewinnen derzeit an Bedeutung, nicht weil npm-Skripte (also Shell-Befehle) von Natur aus so großartig sind, sondern weil sie eine gemeinsame Basis für alle Plugins(!) bieten, die Sie verwenden werden. Der gemeinsame Nenner ist nett, bauen wir darauf auf. Was npm wirklich Einzigartiges bietet, ist die gemeinsame (Shell-)Schnittstelle und die Möglichkeit, diese programmatisch wiederzuverwenden. Zusätzlich benötigen Sie nicht mehr jede einzelne Abhängigkeit, die Sie, Ihr Hund, Ihre Mutter und Ihr (technisch versierter, ungeborener) Enkelkind jemals in Ihrem großen, allmächtigen PATH hatten (Hinweis: Ich bin nicht derjenige, der hier Großbuchstaben liefert). Sie können Dinge lokal halten.
Also npm-Skripte: Juhu! Brillante Idee. Aber Node (oder Python oder Ruby) Skripte sind es, wo das Herzstück von allem liegt, wenn Sie echte Kontrolle wollen.
Wie auch immer... Mein Vorschlag: Laden Sie Dinge lokal in Ihr Projekt über npm herunter, erstellen Sie einen Ordner namens 'build-scripts', erstellen Sie npm-Skripte für Ihre Build-Aufgaben, die Node-Skripte aus 'build-scripts' verwenden, um beliebige Aufgaben auszuführen, und verwenden Sie exec/execSync, um tatsächliche Terminalbefehle auszuführen.
.. Ihnen überlassen. Verwenden Sie alles, was nicht zu viel Zeit für die Konfiguration verschwendet. Und im schlimmsten Fall landen Sie einfach mit einer Reihe von execSync-Befehlen, die auf Ihre npm-Skripte verweisen.
Ich hatte diese Diskussion kürzlich mit meinen Kollegen. Ich denke, das Hauptproblem, das man beim Umstieg auf reine npm-Skripte verliert, ist das Konzept einer gemeinsamen "Aufgabe". Ich stimme vollkommen zu, dass Gulp/Grunt/etc. restriktive Pluginsysteme haben, aber was beide bieten, ist eine wirklich einfache Möglichkeit, eine abstrakte Aufgabe zu erstellen und sie auf logische/reproduzierbare Weise zu verketten.
Für große Apps mit komplexen Build-Systemen ist eine einfache und konsistente Möglichkeit, Aufgaben zu wrappen und zu verketten, notwendig und meiner Meinung nach ziemlich leicht erreichbar.
„mkdir“ und „rm“ funktionieren unter Windows nicht, sodass der gesamte Prozess dort zusammenbricht. Außerdem ist es ehrlicher, den vollständigen Hash der Skripte anzuzeigen (er ist bereits ziemlich groß), anstatt irrelevante Teile wegzulassen.
rimraf und mkdirp
Das stimmt nicht ganz. Wenn Sie eine UNIX-ähnliche Shell verwenden (wie die Bash-Shell, die Sie erhalten, wenn Sie Git for Windows installieren und nicht die Standard-Eingabeaufforderung von Windows), wie es viele Entwickler tun, dann funktionieren mkdir und rm – und die Mehrheit der anderen gängigen UNIX-Befehle – unter Windows einwandfrei.
Ich liebe diesen Satz: „Lassen Sie mich das sagen: Wenn Sie mit Ihrem aktuellen Build-System zufrieden sind und alle Ihre Anforderungen erfüllt, können Sie es weiterhin verwenden!“
Heutzutage gibt es zu viel „Benutzen Sie es nicht, benutzen Sie das hier“…
„Wann wurde es als ‚richtig‘ angesehen, Build-Skripte in einem Paketmanifest zu schreiben?“ —Jon Schlinkert
Vielen Dank für diesen Beitrag! Er hat mir sehr geholfen, mich mit gleichzeitigen Aufgaben in einem komplexen Setup mit
webpackundnpmauseinanderzusetzen.Etwas, das ich immer noch nicht herausfinden kann. Beim Ausführen von
die npm-Aufgabe wird nach erfolgreichem Abschluss beendet. Ich möchte auch die Icons-Aufgabe *beobachten*. Gibt es eine Möglichkeit, dies zu tun?
Katja,
Es sieht so aus, als müssten Sie eine Watch-Aufgabe für Icons einrichten und dann
npm run iconsdurchnpm run watch:iconsersetzen.Ich rufe gerne die Binärdateien im Ordner
node_modulesauf, anstatt mich auf globale Befehle zu verlassen.anstelle von
Ich würde verwenden
Nachdem ich Stephens Sauceda's Kommentar oben gesehen habe, denke ich, dass dies mehr Sinn macht
Das ist eigentlich das, was npm im Hintergrund tut, daher überladen Sie unnötigerweise Ihre
package.json. Die npm-Dokumentation besagtEs geht sogar so weit zu sagen
npm docs source
Schön! Es wäre gut zu wissen, ob npm die PATH-Variable voranstellt oder anhängt. Ich habe die Antwort in den Dokumenten nicht gefunden. Das würde bestimmen, ob npm standardmäßig die lokale oder globale Installation verwendet, was einen Unterschied macht, wenn es einen Versionskonflikt gibt.
Hallo Damon, toller Artikel!
Für alle Windows-Benutzer, die die Standard-Eingabeaufforderung und nicht die UNIX-ähnliche verwenden, ist es möglich, den
mkdir -p-Teil wie folgt umzuschreibenif not exist dist\\js mkdir dist\\jsWindows-Schrägstriche müssen escaped werden.
Danke Paolo!
Wenn Sie unter Windows sind, würde ich vielleicht in Erwägung ziehen, mkdirp (https://github.com/substack/node-mkdirp) und rimraf (https://www.npmjs.com/package/rimraf) zu verwenden.
Fehlt mir etwas? Abgesehen von "watch" (und devDependencies) – wie handhabt diese Lösung die Abhängigkeitskette? Baut npm run-scripts "alles" ... "immer"?
Aus der Welt von "make-land" kommend, bin ich wohl so altmodisch, dass ich es einfach nicht verstehe – ich möchte nicht, dass ein Build-Schritt IRGENDETWAS ausführt, wenn es nicht notwendig ist :/
Gibt es einen Unterschied zwischen der Verwendung von parallelshell und einfach einer einfachen Pipe | ?
Dies wäre wahrscheinlich gleichwertig mit parrallelshell
"start": "npm run watch | npm run server"oder so etwas"deploy": "(npm run watch &) && npm run server"