Wie der grüne Junior seinen Hot-Reloader schrieb

Hintergrund


Ein paar Zeilen über mich, um ein allgemeines Verständnis des Niveaus des Autors und des zu lösenden Problems zu erhalten.
Mein Name ist Eugene und ich bin ein Webentwickler Green Junior Frontend Entwickler.
Vor einem anderen Jahr arbeitete ich in einem ganz anderen Bereich und dachte nur theoretisch darüber nach, meinen Beruf zu wechseln, aber um Dezember 2018 fand ich meinen Weg und begann zu schauspielern.
Nach ungefähr sechs Monaten totaler Ausbildung bekomme ich einen Job als Frontend-Programmierer. Ich habe grundlegende Dinge gelernt (ich möchte es glauben), js, Interaktion mit dem DOM, reagieren + reduzieren. Mindestens HTML und CSS + ein allgemeines Verständnis von Bootstrap und Assembly, Arbeiten mit Git, der Befehlszeile.
Zusätzlich zur Theorie wurden einige Schulungsprojekte durchgeführt, darunter ein Chat zu React + Redux sowie einige Versuche, einige ihrer Ideen umzusetzen.
Im Allgemeinen ist ein solches Standard-Gentleman-Set für Anfänger geeignet.
In den ersten anderthalb Wochen habe ich eine virtuelle Maschine eingerichtet, es gibt viel von allem und alles ist mir unbekannt und unverständlich.
Dabei lerne ich neue Tools und Technologien kennen: Datenbanken (und setze mir ein weiteres Lesezeichen in die Lernliste), Kitt, Wincsp usw.
Überquere diesen Hindernisparcours erfolgreich und gehe nach vorne.

Vorwort


Nachdem ich meinen Reloader und diesen Artikel bereits geschrieben hatte, fand ich Analoga, einschließlich solcher auf Habré . Er beschloss jedoch, sein Fahrrad zu veröffentlichen.

Starten Sie


Wir haben ein ziemlich großes Projekt geerbt, geschrieben in eckigem JS mit all seinen Reizen. Nach React schien er mir wie ein Dinosaurier, aber nichts, ich kaufe eckige Kurse, fahre schnell hinein und fange an zu profitieren.

Ein positiver Eindruck ist, dass das Projekt von Menschen mit deutlich geraden Armen gut geschrieben wurde. Variablen mit ausgezeichneter klarer Benennung, die Struktur ist überall gleich und im Allgemeinen ist die gesamte Logik sehr zugänglich und einfach ausgedrückt.

Aber es gibt genug Minuspunkte.

Das erste Problem: Das Projekt wird von einem alten Minimierer erstellt, und es ist unmöglich, die moderne js-Syntax zu verwenden. None () => {}, const res = [... data, subRes], async / await ...

Das zweite Problem: Es gibt weder ein Webpack noch zumindest einen Schluck, und dementsprechend gibt es auch keinen Webpack-Dev-Server, der mir mit seinem hervorragenden Hot-Reload vertraut ist.

Schrieb. Gespeichert. F5. Unbequem. Schmerz? Kein direkter Schmerz, aber sehr unangenehm.

Das dritte Problem: Erstellen der .bat-Datei des Projekts, in der ein Teil des Projekts einfach kopiert wird, ein Teil der Bibliotheken ohne Minimierung gesammelt wird, ein Teil in eine Datei minimiert wird, der Rest der Projektdateien in eine andere. Liste der Bibliotheken in der dritten Datei. Liste der Dateien, die im vierten erstellt werden sollen. Usw.

Das vierte Problem: Alle Bibliotheken befinden sich ordentlich im Ordner libs und sind durch ein Skript in index.html verbunden. Alles in allem, außer Express und Proxy dafür (sie sind nicht an der Versammlung beteiligt, sondern nur für die Entwicklung).
Und weit weg von überall gibt es Versionen oder Hinweise auf eine bestimmte Bibliothek.

Ich habe in einer wunderschönen Welt der funktionalen Programmierung trainiert, voll von es6 +, Webpack-Dev-Server, tdd, eslint, automatischem Build und so weiter.

Und hier in der Erwachsenenwelt ist alles ganz anders ...

Krawatte


Aber ich arbeite gerne, ich betrachte Hindernisse als Möglichkeiten zur Selbstentwicklung, das Unternehmen ist gut, die Atmosphäre ist ausgezeichnet, meine Augen brennen!

In der Arbeitszeit erledige ich Arbeitsaufgaben, in meiner Freizeit versuche ich etwas zu verbessern.

Mitte Juni beginne ich mit dem Versuch, das Webpack zu befestigen, aber der erste Ansatz erwartet einen vollständigen Fehler. Ich bin seit einer Woche gequält, ich bin es sehr leid, vorübergehend aufgeschoben.

Ich beschließe, klein anzufangen - ich verbinde die neue Syntax über babel. Ich füge Babels anfängliche Verarbeitung zu unserer magischen build.bat hinzu, aber etwas bricht die Idylle und unser alter Minificator stolpert. Ich suche ein Problem.

Stolpert über eine der Bibliotheken aus den ordentlichen Papa-Bibliotheken. Ich sehe mir Bibliotheksdateien an: Sie sind bereits in der alten Syntax minimiert.

Ich sage babel - "du gehst nicht hierher ... der Kopf wird den Code bekommen, es wird wirklich schlimm sein." Ich überprüfe: alles funktioniert! Hurra! Jetzt habe ich Zugang zu all diesen schönen neuen, stilvollen, trendigen Jugend-Dingen! Erster Sieg. Schön Ich denke bei dieser Gelegenheit, das Skript in e.bat (e-Evgen) umzubenennen, kann mich aber nicht entscheiden.

Die neue Syntax ist so vertraut und unterhaltsam, aber der Gedanke an einen krummen Build lässt mich nicht los.

Ende Juni und Anfang Juli. Ich mache den zweiten Ansatz, gründlicher, aber wieder stoße ich auf Fehler zwischen Webpack und AngularJS. Wieder eine Woche Forschung.

Nachdem ich einige Tage und teilweise Nächte damit verbracht habe, nach einer Lösung zu suchen, stoße ich auf äußerst interessante Reden von der HolyJS-Konferenz, bei der die Jungs bereits ziemlich tief in das Webpack eintauchen. Ich mache Fortschritte in seinem Verständnis, aber ich verstehe das Material immer noch nicht bis zum Ende.

Das Interesse steigt.

Ein Kollege sagt - vergessen Sie es, um das Projekt in ein paar Monaten zu übergeben, müssen Sie dies nicht mehr tun.
Ich hämmere nicht, aber ich schiebe es auf - viel Arbeit, es drückt mich alles zusammen, es bleibt keine Zeit mehr für außerschulische Aktivitäten.

Mitte Juli bekomme ich ähnlich wie bei unserem Projekt einen maßgeschneiderten Build in die Hände. Ich gehe mit ihm zum dritten Ansatz und richte praktisch ein Webpack mit uns ein, aber am Ende stelle ich neue Fehler fest, für deren Lösung ich nicht genug Zeit habe. Die Arbeit rollt mit neuer Intensität. Es zerstört mich mental. Ich habe dieses Geschäft wieder aufgeschoben.

Hauptteil


Mitte August. Infolgedessen spricht ein Freund über das Lernen von node.js und seinen Wunsch, seinen eigenen Hot-Reloader zu schreiben. Gedanken über unsere Versammlung flammen mit neuer Kraft auf.

Aufgabe: Laden Sie die aktuelle Seite neu, wenn Sie Dateien im Projekt aktualisieren.
Features: Alle Bibliotheken sind in index.html verbunden, Sie können nicht benötigen, ganz zu schweigen vom Import. Die Baugruppe vor dem erneuten Laden wird noch nicht benötigt, nur neu laden. Auf einem Entwicklungsserver, der Anfragen für unser Backing als Proxy sendet, kann ich Pakete verwenden und auch benötigen!

All dies geschieht am Freitag und ich entscheide, dass ich in einer vereinfachten Version für unser Projekt durchaus in der Lage bin, eine Technologie zu implementieren, die mich und meine Kollegen vor F5 bewahrt.

Der Denkprozess geht weiter und eine Vision der Lösung wird im Kopf gebildet.
Auf dem einfachsten Server (wie unserem) werde ich den gesamten Ordner und die Unterordner durchsuchen und einen Baum mit den Änderungsdaten jeder Datei bilden.

Dann werde ich alle n Millisekunden immer wieder umgehen und die Werte der Änderungszeit vergleichen. Geändert - neu laden. Ein Freund sagt dir: "Erfinde das Rad nicht neu, es gibt eine Uhr in node.js". Großartig, ich werde es benutzen. In server.js konfiguriere ich watch hinter dem Projektordner und rufe location.reload () auf, um etwas darin zu ändern.

Erste Iteration:

server.js
var express = require('express'); var app = express(); var server = require('http').Server(app); const port = 9080; server.listen(port); app.use(express.static(__dirname + '/src')); location.reload(). 


Das erste Problem ist location - dies ist keine node.js-Variable (in diesem Moment verstehe ich, warum meine Versuche, auf process.env an der Vorderseite zuzugreifen, ebenfalls erfolglos waren)).

Das zweite Problem ist, wie die Front verstehen kann, was beim Nachladen zu tun ist.

Exit - Websocket! Die Idee ist verlockend + Ich habe mit ihnen "Halbkegel" gearbeitet, als ich einen Chat schrieb, ich habe eine allgemeine Idee. Gleichzeitig führe ich pro Sitzung einen Neustartzähler durch, füge eine Variable hinzu und verarbeite die Anforderung, die sie gibt.

Ich versuche:

server.js
 var express = require('express'); //  express var app = express(); var server = require('http').Server(app); //  http  app var io = require('socket.io')(server); //  socket.io     var fs = require('fs'); const port = 9080; server.listen(port); app.use(express.static(__dirname + '/src')); let count = 0; app.get('/data', (req, res) => { res.data = count; res.send(`${count}`); }) const dir = './src'; fs.watch(dir, () => { io.emit('change', {data: count}); count += 1; }) 


An der Front mache ich die einfachste App auf Angularjs

app.js.
 angular.module('App', []) .controller('myAppCtrl',['$scope', '$timeout','$http', ($scope, $timeout, $http) => { $scope.title = '       '; $scope.count = 0; $scope.todo = [ '  ,  ', '   node.js watch   ', '     ,         ', ' , codeclimate  travis   ' ] $scope.marks = [ 'watcher      ' ] // var socket = io(); // socket.on('change', (data) => { // console.log(data.data); // $scope.count = data.data; // console.log('scope.count: ', $scope.count); // $scope.$digest();// // location.reload();//agfr // }) $http({method: 'GET',url: 'data'}) .then(response => { $scope.count = response.data;// }); }]) 


Und ein separates Modul, das es neu lädt. Separat, damit das Projekt nicht zu viel bekommt.

watch.js
 var socket = io(); socket.on('change', () => { location.reload(); }) 


Es funktioniert! Er überwacht auch andere Dateien als js (man weiß es nie!): Checked .json, .css.
Ich überprüfe die Unterordner - es funktioniert nicht.

Ich denke, okay, jetzt werde ich es rekursiv reduzieren. Nur für den Fall, Google und - voila - ist bereit
die Entscheidung.

Fügen Sie dieses Paket hinzu.

server.js
 var express = require('express'); //  express var app = express(); var server = require('http').Server(app); //  http  app var io = require('socket.io')(server); //  socket.io     var fs = require('fs'); var watch = require('node-watch'); const port = 9080; server.listen(port); app.use(express.static(__dirname + '/src')); let count = 0; let changed = []; app.get('/data', (req, res) => { res.data = count; res.send({count, changed}); }) const translate = { remove: "", update: "" } watch('./', { recursive: true }, function(evt, name) { io.emit('change', {data: count}); count += 1; changed = [{name, evt}, ...changed]; }); 


Hurra, es funktioniert!

Ich erinnere mich an Eslint, Codeclimate und Travis.
Installieren Sie die erste, fügen Sie den Rest hinzu.
Ich bereinige den Code, alles ist var on const und so weiter.

Linter schwört, dass der Winkel nicht definiert ist, aber meine Funktionen zum Verbinden von Bibliotheken im Projekt bestimmen dieses Verhalten. Ich schalte es aus. Gleichzeitig schraube ich die Variablen ein wenig aus der Kommandozeile, führe sie aus, alles funktioniert!

Er kam am Montag zur Arbeit und befestigte die gesamte Farm an einem Arbeitsentwurf. Ich musste ein wenig ändern, gleichzeitig Änderungen vornehmen, damit es möglich war, einige Startparameter über die Befehlszeile und Ausnahmen zu ändern, so dass ich nicht alles las.

Infolgedessen stellte sich Folgendes heraus:

server.js
 const express = require('express'), http = require('http'), watch = require('node-watch'), proxy = require('http-proxy-middleware'), app = express(), server = http.createServer(app), io = require('socket.io').listen(server), exeptions = ['git', 'js_babeled', 'node_modules', 'build', 'hotreload'], // ,   ,    backPortObj = { /*  ,   back*/ }, address = process.argv[2] || /*    back*/, localHostPort = process.argv[3] || 9080, backMachinePort = backPortObj[address] || /*   back */, isHotReload = process.argv[4] || "y", // "n" || "y" target = `http://192.168.${address}:${backMachinePort}`, str = `Connected to machine: ${target}, hot reload: ${isHotReload === 'y' ? 'enabled' : 'disabled'}.`, link = `http://localhost:${localHostPort}/`; server.listen(localHostPort); app .use('/bg-portal', proxy({ target, changeOrigin: true, ws: true })) .use(express.static('.')); if (isHotReload === 'y') { watch('./', { recursive: true }, (evt, name) => { let include = false; exeptions.forEach(item => { if (`${name}`.includes(item)) include = true; }) if (!include) { console.log(name); io.emit('change', { evt, name, exeptions }); }; }); }; console.log(str); console.log(link); 


app.js.
 var socket = io.connect(); socket.on('change', ({ evt, name, exeptions }) => { location.reload(); }); 


Das laufende Skript in package.json ruft nur server.js unter dem Knoten auf und beginnt wie folgt:

 npm start 1.100 8080 

Schrieb. Gespeichert. F5

Abschließend möchte ich Vanya, meiner Freundin, an einigen Stellen dem Mastermind und dem Hauptkicker sowie Sasha - dem Mann, den ich als meinen Mentor betrachte - danken!

Anstelle eines Nachwortes


Und nach 2 Wochen, am letzten Tag meiner Testphase, schraubte ich Webpack und Webpack-Dev-Server in unser Projekt und schickte meinen heißen Reloader in den Staub im Geschichtsregal.

Diese 2 Wochen haben wir es jedoch jeden Tag benutzt und er hat regelmäßig seinen Job gemacht!

Source: https://habr.com/ru/post/de466237/


All Articles