Node.js
für Webapplikationen
WER BIN ICH?
• Sebastian Springer	

• https://github.com/sspringer82	

• @basti_springer	

• Consultant,Trainer,Autor
var http = require(‘http');!
!
http.createServer(function (req, res) {!
res.writeHead(200, !
{'Content-Type': 'text/plain'});!
res.end('Hello Worldn');!
}).listen(1337, ‘127.0.0.1');!
!
console.log('Server running at localhost');
Heute machen wir kein plain Node.js
Wie baue ich mit Node.js eine stabile und performante
Webapplikation?
Für die ich mich später nicht schämen muss…
Struktur
Struktur bedeutet Organisation des Quellcodes in
Komponenten, Dateien und Verzeichnisse.
Ziel ist eine Verbesserung der
Wartbarkeit und Erweiterbarkeit.
…und ja, das geht mit Node.js
Node.js-Modulsystem zur Aufteilung in Dateien
Einbinden von Dateien kostet nichts, Node.js verfügt über
einen Modulcache.
$ node cache2.js
In Module
Module function
Module function
var foo = require('./myFile');
var bar = require('./myFile');
!
foo.myFunc();
bar.myFunc();
console.log('In Module');
!
module.exports = {
myFunc: function() {console.log('Module function');}
};
Frameworks
Frameworks liefern Strukturkomponenten, Hilfsfunktionen
und eine Reihe von Best Practices.
!
Frameworks lösen Probleme, von denen du noch nicht einmal
wusstest, dass du sie haben wirst.
TemplatingModular Routing Extensible
Jade
Handlebars
Middleware MiddlewareHTTP-Methods
Sehr weit verbreitetes Web Application Framework auf Basis
von Node.js-http und Connect.
var express = require('express');!
var app = express();!
!
app.get('/', function(req, res){!
res.send('hello world');!
});!
!
app.listen(3000);
TemplatingModular Routing Extensible
Jade
Handlebars
Middleware MiddlewareHTTP-Methods
Neues, noch experimentelles Framework, das auf ECMAScript
6-Features setzt (min. node-v0.11).
Bessere Unterstützung von Promises und potenzieller
Nachfolger von express.
var koa = require('koa');!
var app = koa();!
!
// logger!
app.use(function *(next){!
var start = new Date;!
yield next;!
var ms = new Date - start;!
console.log('%s %s - %s', this.method, this.url, ms);!
});!
!
// response!
app.use(function *(){!
this.body = 'Hello World';!
});!
!
app.listen(3000);
TemplatingModular Routing Extensible
PlatesMiddleware
Middleware
Plugins
Director
Ein wesentlich kleineres Framework als express. Unterstützt
die wichtigsten Funktionen, die für den Aufbau einer Web
Applikation benötigt werden.
var flatiron = require('flatiron'),!
app = flatiron.app;!
!
app.use(flatiron.plugins.http);!
!
app.router.get('/', function () {!
this.res.writeHead(200, { 'Content-Type': 'text/plain' });!
this.res.end('Hello world!n');!
});!
!
app.start(8080);
TemplatingModular Routing Extensible
own engineModules OverwritesHTTP-Methods
Im Vergleich zu express ein vergleichsweise kleines
Framework. Umfangreiche Abdeckung der Problemstellungen.
var framework = require('total.js');!
var http = require('http');!
!
var debug = true;!
!
framework.run(http, debug, 8005);
exports.install = function(framework) {!
framework.route('/', view_homepage);!
framework.route('/{link}/', view_detail);!
};!
!
function view_homepage() {!
var self = this;!
self.view('homepage');!
}
express.js
Verzeichnisstruktur
.!
!"" controllers!
#   $"" index.js!
!"" index.js!
!"" models!
#   $"" user.js!
!"" public!
!"" router.js!
$"" views!
$"" login.js
index.js
var express = require('express');!
var bodyParser = require('body-parser');!
var routes = require('./router');!
!
var app = express();!
!
app.use(bodyParser.json());!
!
app.use('/', express.static(__dirname + '/public'));!
!
routes(app);!
!
app.listen(8080);
router.js
var express = require('express');!
!
var todoController = require('./controllers/todo');!
!
module.exports = function(app) {!
var todoRouter = express.Router();!
!
todoRouter.get('/', todoController.getAllAction);!
todoRouter.get('/:id', todoController.getOneAction);!
todoRouter.post('/', todoController.createAction);!
todoRouter.put('/:id', todoController.updateAction);!
todoRouter.delete('/:id',
todoController.deleteAction);!
!
app.use('/todo', todoRouter);!
};
Datenbanken
1. Treiber installieren
!
npm install sqlite3
2. Verbindung aufbauen
!
var db = new sqlite3.Database(‘./db/myDb.db');
3. Abfragen
!
db.get(sql, id, function(err, row) {!
… !
});
ORM
○␣
␣
var express = require('express');!
var orm = require('orm');!
var app = express();!
!
app.use(orm.express("mysql://username:password@host/
database", {!
define: function (db, models, next) {!
models.person = db.define("person", { ... });!
next();!
}!
}));!
app.listen(80);!
!
app.get("/", function (req, res) {!
req.models.person.find(...);!
});
npm install orm
Paketverwaltung
Der Node Package Manager ist seit der Version 0.6.3 Teil von
Node.js.
Installation, Update und Removal von Paketen.
Das zentrale Repo liegt unter npmjs.org.
Jeder kann Pakete veröffentlichen.
!
Jedes Paket löst seine eigenen Abhängigkeiten auf.
Konfigurationsdatei für ein Projekt.
Wird mit npm init erstellt.
Enthält viele Meta-Informationen und die Abhängigkeiten.
package.json
• node_modules: Verzeichnis, in das die Abhängigkeiten
installiert werden (sollte im VCS ignoriert werden).
!
• npm install: Installiert sämtliche Abhängigkeiten aus der
package.json automatisch.
!
• npm install --save: Trägt die Abhängigkeiten in die
package.json ein.
Distribution
• Installation über npmjs.org
• Installation eines Pakets aus einem Verzeichnis
• Installation eines Pakets aus einer .tgz-Datei
Voraussetzung: package.json muss vorhanden sein
Skalierung
Node.js ist im Kern klein und leichtgewichtig.
Node.js ist Single-Threaded.
Node.js schlägt sich als Einzelkämpfer recht gut.
ABER: das alles hat auch seine Grenzen.
Multi-Threaded
Mit Boardmitteln
child_process cluster
child_process
Manuelles Forken von Kindprozessen.
Prozesse können über Nachrichten kommunizieren.
!
ACHTUNG: Kinder kosten… Ressourcen.
var cp = require('child_process');!
!
var sub = cp.fork(__dirname + '/sub.js');!
!
sub.on('message', function(m) {!
console.log('PARENT got message:', m);!
});!
!
sub.send({ hello: 'world' });
process.on('message', function(m) {!
console.log('CHILD got message:', m);!
});!
!
process.send({ foo: 'bar' });
Parent
Child
cluster
Skalierung für socket-basierte Module wie z.B. http.
Betriebssystem übernimmt das Loadbalancing.
Die Prozesse teilen sich einen Port.
var cluster = require('cluster');!
var http = require('http');!
var numCPUs = require('os').cpus().length;!
!
if (cluster.isMaster) {!
for (var i = 0; i < numCPUs; i++) {!
cluster.fork();!
}!
!
cluster.on('exit', function(worker, code, signal) {!
console.log('worker ' + worker.process.pid + ' died');!
});!
} else {!
http.createServer(function(req, res) {!
res.writeHead(200);!
res.end("hello worldn");!
}).listen(8000);!
}
In die Breite
Loadbalancer
Node Server 1 Node Server 2
Datenbank
cloud
Performance
Performance
• Kein synchroner Code
• Keine statischen Assets - z.B. Nginx einsetzen
• Den Client rendern lassen - JSON-Kommunikation
• gzip nutzen
• Binärmodule sind schneller - z.B. mySQL
Qualität
jslint/jshint
npm install -g jslint
!
Werkzeuge zur statischen Codeanalyse.
Finden Syntaxfehler und Antipatterns.
$ jslint index.js
!
index.js
#1 Unexpected dangling '_' in '__dirname'.
app.use('/', express.static(__dirname + '/public')); // Line 9, Pos 29
Copy-Paste-Detection
npm install -g jscpd
!
Findet duplizierten Quellcode im Projekt.
$ jscpd -f app.js
!
info: Found 7 exact clones with 70 duplicated lines in 1 files
- app.js:6626 -6635
app.js:6646 -6655
Plato
npm install -g plato
!
Visualisierung der Komplexität einer Applikation.
Metriken: Maintainability, Lines of Code, Estimated Errors in
Implementation, Lint Errors
Testing
assert
Mocha
nodeunit
jasmine-node
KONTAKT
Sebastian Springer
sebastian.springer@mayflower.de
!
Mayflower GmbH
Mannhardtstr. 6
80538 München
Deutschland
!
@basti_springer
!
https://github.com/sspringer82

Node.js für Webapplikationen

  • 1.
  • 2.
    WER BIN ICH? •Sebastian Springer • https://github.com/sspringer82 • @basti_springer • Consultant,Trainer,Autor
  • 3.
    var http =require(‘http');! ! http.createServer(function (req, res) {! res.writeHead(200, ! {'Content-Type': 'text/plain'});! res.end('Hello Worldn');! }).listen(1337, ‘127.0.0.1');! ! console.log('Server running at localhost'); Heute machen wir kein plain Node.js
  • 4.
    Wie baue ichmit Node.js eine stabile und performante Webapplikation? Für die ich mich später nicht schämen muss…
  • 5.
  • 6.
    Struktur bedeutet Organisationdes Quellcodes in Komponenten, Dateien und Verzeichnisse. Ziel ist eine Verbesserung der Wartbarkeit und Erweiterbarkeit. …und ja, das geht mit Node.js
  • 7.
    Node.js-Modulsystem zur Aufteilungin Dateien Einbinden von Dateien kostet nichts, Node.js verfügt über einen Modulcache.
  • 8.
    $ node cache2.js InModule Module function Module function var foo = require('./myFile'); var bar = require('./myFile'); ! foo.myFunc(); bar.myFunc(); console.log('In Module'); ! module.exports = { myFunc: function() {console.log('Module function');} };
  • 9.
  • 10.
    Frameworks liefern Strukturkomponenten,Hilfsfunktionen und eine Reihe von Best Practices. ! Frameworks lösen Probleme, von denen du noch nicht einmal wusstest, dass du sie haben wirst.
  • 11.
    TemplatingModular Routing Extensible Jade Handlebars MiddlewareMiddlewareHTTP-Methods Sehr weit verbreitetes Web Application Framework auf Basis von Node.js-http und Connect.
  • 12.
    var express =require('express');! var app = express();! ! app.get('/', function(req, res){! res.send('hello world');! });! ! app.listen(3000);
  • 13.
    TemplatingModular Routing Extensible Jade Handlebars MiddlewareMiddlewareHTTP-Methods Neues, noch experimentelles Framework, das auf ECMAScript 6-Features setzt (min. node-v0.11). Bessere Unterstützung von Promises und potenzieller Nachfolger von express.
  • 14.
    var koa =require('koa');! var app = koa();! ! // logger! app.use(function *(next){! var start = new Date;! yield next;! var ms = new Date - start;! console.log('%s %s - %s', this.method, this.url, ms);! });! ! // response! app.use(function *(){! this.body = 'Hello World';! });! ! app.listen(3000);
  • 15.
    TemplatingModular Routing Extensible PlatesMiddleware Middleware Plugins Director Einwesentlich kleineres Framework als express. Unterstützt die wichtigsten Funktionen, die für den Aufbau einer Web Applikation benötigt werden.
  • 16.
    var flatiron =require('flatiron'),! app = flatiron.app;! ! app.use(flatiron.plugins.http);! ! app.router.get('/', function () {! this.res.writeHead(200, { 'Content-Type': 'text/plain' });! this.res.end('Hello world!n');! });! ! app.start(8080);
  • 17.
    TemplatingModular Routing Extensible ownengineModules OverwritesHTTP-Methods Im Vergleich zu express ein vergleichsweise kleines Framework. Umfangreiche Abdeckung der Problemstellungen.
  • 18.
    var framework =require('total.js');! var http = require('http');! ! var debug = true;! ! framework.run(http, debug, 8005); exports.install = function(framework) {! framework.route('/', view_homepage);! framework.route('/{link}/', view_detail);! };! ! function view_homepage() {! var self = this;! self.view('homepage');! }
  • 19.
  • 20.
    Verzeichnisstruktur .! !"" controllers! #   $""index.js! !"" index.js! !"" models! #   $"" user.js! !"" public! !"" router.js! $"" views! $"" login.js
  • 21.
    index.js var express =require('express');! var bodyParser = require('body-parser');! var routes = require('./router');! ! var app = express();! ! app.use(bodyParser.json());! ! app.use('/', express.static(__dirname + '/public'));! ! routes(app);! ! app.listen(8080);
  • 22.
    router.js var express =require('express');! ! var todoController = require('./controllers/todo');! ! module.exports = function(app) {! var todoRouter = express.Router();! ! todoRouter.get('/', todoController.getAllAction);! todoRouter.get('/:id', todoController.getOneAction);! todoRouter.post('/', todoController.createAction);! todoRouter.put('/:id', todoController.updateAction);! todoRouter.delete('/:id', todoController.deleteAction);! ! app.use('/todo', todoRouter);! };
  • 23.
  • 24.
    1. Treiber installieren ! npminstall sqlite3 2. Verbindung aufbauen ! var db = new sqlite3.Database(‘./db/myDb.db'); 3. Abfragen ! db.get(sql, id, function(err, row) {! … ! });
  • 25.
  • 26.
    var express =require('express');! var orm = require('orm');! var app = express();! ! app.use(orm.express("mysql://username:password@host/ database", {! define: function (db, models, next) {! models.person = db.define("person", { ... });! next();! }! }));! app.listen(80);! ! app.get("/", function (req, res) {! req.models.person.find(...);! }); npm install orm
  • 27.
  • 28.
    Der Node PackageManager ist seit der Version 0.6.3 Teil von Node.js. Installation, Update und Removal von Paketen. Das zentrale Repo liegt unter npmjs.org. Jeder kann Pakete veröffentlichen. ! Jedes Paket löst seine eigenen Abhängigkeiten auf.
  • 29.
    Konfigurationsdatei für einProjekt. Wird mit npm init erstellt. Enthält viele Meta-Informationen und die Abhängigkeiten. package.json
  • 30.
    • node_modules: Verzeichnis,in das die Abhängigkeiten installiert werden (sollte im VCS ignoriert werden). ! • npm install: Installiert sämtliche Abhängigkeiten aus der package.json automatisch. ! • npm install --save: Trägt die Abhängigkeiten in die package.json ein.
  • 31.
  • 32.
    • Installation übernpmjs.org • Installation eines Pakets aus einem Verzeichnis • Installation eines Pakets aus einer .tgz-Datei Voraussetzung: package.json muss vorhanden sein
  • 33.
  • 34.
    Node.js ist imKern klein und leichtgewichtig. Node.js ist Single-Threaded. Node.js schlägt sich als Einzelkämpfer recht gut. ABER: das alles hat auch seine Grenzen.
  • 35.
  • 36.
  • 37.
    child_process Manuelles Forken vonKindprozessen. Prozesse können über Nachrichten kommunizieren. ! ACHTUNG: Kinder kosten… Ressourcen.
  • 38.
    var cp =require('child_process');! ! var sub = cp.fork(__dirname + '/sub.js');! ! sub.on('message', function(m) {! console.log('PARENT got message:', m);! });! ! sub.send({ hello: 'world' }); process.on('message', function(m) {! console.log('CHILD got message:', m);! });! ! process.send({ foo: 'bar' }); Parent Child
  • 39.
    cluster Skalierung für socket-basierteModule wie z.B. http. Betriebssystem übernimmt das Loadbalancing. Die Prozesse teilen sich einen Port.
  • 40.
    var cluster =require('cluster');! var http = require('http');! var numCPUs = require('os').cpus().length;! ! if (cluster.isMaster) {! for (var i = 0; i < numCPUs; i++) {! cluster.fork();! }! ! cluster.on('exit', function(worker, code, signal) {! console.log('worker ' + worker.process.pid + ' died');! });! } else {! http.createServer(function(req, res) {! res.writeHead(200);! res.end("hello worldn");! }).listen(8000);! }
  • 41.
  • 42.
    Loadbalancer Node Server 1Node Server 2 Datenbank
  • 43.
  • 44.
  • 45.
    Performance • Kein synchronerCode • Keine statischen Assets - z.B. Nginx einsetzen • Den Client rendern lassen - JSON-Kommunikation • gzip nutzen • Binärmodule sind schneller - z.B. mySQL
  • 46.
  • 47.
    jslint/jshint npm install -gjslint ! Werkzeuge zur statischen Codeanalyse. Finden Syntaxfehler und Antipatterns. $ jslint index.js ! index.js #1 Unexpected dangling '_' in '__dirname'. app.use('/', express.static(__dirname + '/public')); // Line 9, Pos 29
  • 48.
    Copy-Paste-Detection npm install -gjscpd ! Findet duplizierten Quellcode im Projekt. $ jscpd -f app.js ! info: Found 7 exact clones with 70 duplicated lines in 1 files - app.js:6626 -6635 app.js:6646 -6655
  • 49.
    Plato npm install -gplato ! Visualisierung der Komplexität einer Applikation. Metriken: Maintainability, Lines of Code, Estimated Errors in Implementation, Lint Errors
  • 51.
  • 52.
    KONTAKT Sebastian Springer sebastian.springer@mayflower.de ! Mayflower GmbH Mannhardtstr.6 80538 München Deutschland ! @basti_springer ! https://github.com/sspringer82