OSCON 2011 - Node.js Tutorial
Upcoming SlideShare
Loading in...5
×
 

OSCON 2011 - Node.js Tutorial

on

  • 14,572 views

 

Statistics

Views

Total Views
14,572
Views on SlideShare
13,940
Embed Views
632

Actions

Likes
54
Downloads
633
Comments
2

22 Embeds 632

http://sugyan.no.de 224
http://www.oscon.com 168
http://lanyrd.com 128
http://staging.conferize.com 27
http://www.nitinkatkam.com 25
http://tweetedtimes.com 14
http://twitter.com 13
http://localhost 5
https://twitter.com 5
http://fasoulas.posterous.com 4
http://tenkao.tumblr.com 3
http://ruben.i.conferize.com 2
http://www.techgig.com 2
http://blog.fasoulas.com 2
http://us-w1.rockmelt.com 2
https://www.linkedin.com 2
http://a0.twimg.com 1
http://115.112.206.134 1
http://posterous.com 1
https://home.jolicloud.com 1
http://www.onlydoo.com 1
http://www.i.conferize.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

CC Attribution-ShareAlike LicenseCC Attribution-ShareAlike License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • Running order\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Service behind traffic server\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

OSCON 2011 - Node.js Tutorial OSCON 2011 - Node.js Tutorial Presentation Transcript

  • Node.js WorkshopTom Hughes-CroucherChief Evangelist / Node Tech Lead@sh1mmertom@joyent.com
  • Overview• Introduction• Why Server-Side JavaScript?• What is Node?• Using Node• Understanding Node• Node Ecosystem• Programming Style• More Complex applications• Deploying Node apps to the cloud
  • Introduction• Tom Hughes-Croucher• Chief Evangelist at Joyent• Node.js core contributor• Author of "Up and Running with Node.js"
  • Scalable Server-Side Code with JavaScriptNode Up and Running Tom Hughes-Croucher
  • Major update this week
  • Why Server-Side JavaScript?
  • JavaScriptprogrammers 3>2>1
  • Massive Code base of jQuery and other JS libraries
  • Laziness or “I’m sickof writing stuff twice”I could have said efficiency, but I think we allsecretly long to sit around in our underwear.
  • ProgressiveEnhancement is free*Remember WWCD (What Would Crockford Do) *close enough
  • TL;DR:SSJS is Awesome Like a Unicorn riding a Narwhal
  • If SSJS is so awesomewhy is it "new"?
  • 1. Professionalism
  • “Yahoo!s corporate motto is: Dont be eval().“
  • 2. JavaScript Runtimes
  • Runtimes• V8 (Google), C++• Spider Monkey (Mozilla), C++• Rhino (Mozilla), Java
  • V8 Spider MonkeyJavaScript Performance
  • 8xSep 08! Mar 11!
  • Anatomy of SSJS
  • Node { !
  • Runtime != Browser
  • No DOM(By default, anyway)
  • Summary• Benefits of SSJS • Lots of JavaScript expertise • Lots of web code in JS libraries • Write once, run anywhere • Progressive Enhancement• Why SSJS happened now • Professionalism in JavaScript • New generation of JavaScript runtimes
  • What is Node?
  • Node• JavaScript programming environment• Uses V8 runtime• Event Driven• Non-blocking libraries• Supports CommonJS module format• Supports C/C++ based add-ons
  • Woah! Overload.
  • 1. Its JavaScript
  • See Above.
  • 2. Its Fast
  • concurrency=300, Smaller is Better 400 300response time (ms) server nginx 200 thin tornado node_buffer 100 24 26 28 210 212 214 216 218 response size (bytes)
  • 3. Its easy to extend
  • Modules in JSAdd-ons in C
  • 4. Node is _not_ Rails/ Django/etc
  • Node is bare-bone to the metal
  • However, the Nodecommunity are making Rails/Django/etc
  • 5. Node is young
  • Stable is "stable"Unstable moves fast
  • Using Node
  • Using Node• Part 1. Installation• Part 2. Basics• Part 3. Getting stuck in
  • Part 1. Installation
  • Navea.k.a the easy way
  • Enki:~ $ wget -q http://github.com/isaacs/nave/raw/master/nave.shEnki:~ $ chmod 755 nave.shEnki:~ $ ./nave.sh install latest
  • Nave• Installs and versions Node• Allows Node shells with specific versions• Allows you to get latest <-- Stable• May add unstable option in future
  • Manual Installation
  • Go to http://nodejs.org/#downloadand get the URL of the current stable release
  • Enki:~ $ wget -q http://nodejs.org/dist/node-v0.4.10.tar.gzEnki:~ $ tar xzf node-v0.4.10.tar.gzEnki:~ $ cd node-v0.4.10Enki:~/node-v0.4.10 $
  • Local or system?
  • Local
  • Enki:~/node-v0.4.10 $ mkdir ~/localEnki:~/node-v0.4.10 $ ./configure --prefix=~/localChecking for program g++ or c++ : /usr/bin/g++Checking for program cpp : /usr/bin/cpp...Checking for fdatasync(2) with c++ : noconfigure finished successfully (3.466s)
  • Enki:~/node-v0.4.10 $ makeWaf: Entering directory `/Users/sh1mmer/node-v0.4.10/buildDEST_OS: darwinDEST_CPU: x86Parallel Jobs: 1[ 1/69] cc: deps/libeio/eio.c -> build/default/deps/libeio/eio_1.o/usr/bin/gcc -rdynamic -D_GNU_SOURCE -DHAVE_CONFIG_H=1-DEV_MULTIPLICITY=0 -pthread -g -O3 -DHAVE_OPENSSL=1 -DX_STACKSIZE=65536 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_FDATASYNC=0 -DPLATFORM="darwin" -DNDEBUG -Idefault/deps/libeio -I../deps/libeio -Idefault -I.. ../deps/libeio/eio.c -c -o default/deps/libeio/eio_1.o...
  • Enki:~/node-v0.4.10 $ make installWaf: Entering directory `/Users/sh1mmer/node-v0.4.10/buildDEST_OS: darwinDEST_CPU: x86Parallel Jobs: 1* installing build/default/config.h as /Users/sh1mmer/local/include/node/config.h* installing build/default/node as /Users/sh1mmer/local/bin/node* installing build/default/src/node_config.h as /Users/sh1mmer/local/include/node/node_config.hWaf: Leaving directory `/Users/sh1mmer/node-v0.4.10/buildinstall finished successfully (0.373s)Enki:~/node-v0.4.7 $
  • Enki:~/node-v0.4.10 $ echo $PATH/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/usr/local/git/bin:/Users/croucher/Code/narwhal/bin:/opt/local/bin:/usr/local/git/bin:/Users/sh1mmer/binEnki:~/node-v0.4.10 $ node -v-bash: node: command not foundEnki:~/node-v0.4.10 $ echo PATH=~/local/bin:$PATH>> ~/.profileEnki:~/node-v0.4.10 $ node -vv0.4.10
  • System
  • Enki:~/node-v0.4.10 $ ./configure...Enki:~/node-v0.4.10 $ make...Enki:~/node-v0.4.10 $ sudo make install...Enki:~/node-v0.4.10 $ node -vv0.4.7Enki:~/node-v0.4.10 $
  • Exercise• Get Node head from Github using Git• Install to ~/node
  • Part 2. Basics
  • node-replInteractive JavaScript terminal
  • $Enki:~ $ node
  • $Enki:~ $ node>3>2>1false> true == 1true> true === 1false
  • > console.log(Hello World);Hello World> .help.clear Break, and also clear the local context..exit Exit the prompt.help Show repl options> .clearClearing context...> .exitEnki:~ $
  • Enki:~ $ node> var foo = "bar";> foo;bar> .clearClearing context...> fooReferenceError: foo is not defined at [object Context]:1:1 at Interface.<anonymous> (repl:98:19) at Interface.emit (events:27:15) at Interface._ttyWrite (readline:295:12) at Interface.write (readline:132:30) at Stream.<anonymous> (repl:79:9) at Stream.emit (events:27:15) at IOWatcher.callback (net:489:16)
  • var http = require(http);http.createServer(function (req, res) { res.writeHead(200, {Content-Type: text/plain}); res.end(Hello Worldn);}).listen(8124, "127.0.0.1");console.log(Server running at http://127.0.0.1:8124/);
  • var http = require(http);//include the http library
  • http.createServer(function (req, res) {}).listen(8124, "127.0.0.1");//create an http server//when ‘stuff’ happens call this anonymous function//listen on port 8124 of the IP 127.0.0.1
  • http.createServer(function (req, res) { res.writeHead(200, {Content-Type: text/plain}); res.end(Hello Worldn);})//when ‘stuff’ happens my function fires//I get a request object and a response object//I write to the response object header//HTTP status 200 and content-type ‘text/plain’//close the response with the body://Hello World
  • console.log(Server running at http://127.0.0.1:8124/);//write Server is running at http://127.0.0.1:8124///to the console
  • Interactive Debugging
  • Enki:~/Code/node-examples $ node --debughelloworld.jsdebugger listening on port 5858Server running at http://127.0.0.1:8124/
  • Enki:~ $ npm install node-inspectornode-inspector@0.1.8 ./node_modules/node-inspector websocket-server@1.4.04 paperboy@0.0.2Enki:~ $ node-inspectorvisit http://0.0.0.0:8080/debug?port=5858 to startdebugging
  • Exercises• Modify the HTTP server to return the text "Im learning Node"• Change the HTTP response to HTML and return your text in an HTML page• Return the User-Agent string from the browser as part of your HTML page• Return different textual responses to 2 (or more) browsers
  • Part 3. Getting Stuck In
  • HTTP Client
  • var http = require(http);var request = http.request({host: www.google.com,port: 80, path: /, method:GET});request.on(response, function (response) { console.log(STATUS: + response.statusCode); console.log(HEADERS: +JSON.stringify(response.headers)); response.setEncoding(utf8); response.on(data, function (chunk) { console.log(BODY: + chunk); });
  • Streaming API
  • write(data) write(data) DestinationRequest end() (google.com) response(headers) data(chunk) data(chunk) Response data(chunk) end()
  • Exercise• Fetch the NYTimes.com and output the contents to the console• Create a web server • Create an HTTP client • POST data to your web server • Output the POST data to console
  • Events
  • object.on(event, function() { //stuff} );
  • EventEmitter
  • EventEmitter• manage "event handlers" • list of functions to be called per event• provide mechanism to trigger events
  • var util = require(util), EE = require(events).EventEmitter;util.inherits(MyClass, EE);var myObj = new MyClass();//nb using first class functionsmyObj.on(something, function);
  • exports.inherits = function (ctor, superCtor) { ctor.super_ = superCtor; ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false } });};
  • More than just core
  • CommonJS Modules
  • Library format for SSJS
  • math.jsexports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) { sum += args[i++]; } return sum;};increment.jsvar add = require(math).add;exports.increment = function(val) { return add(val, 1);};var inc = require(increment).increment;var a = 1;inc(a); // 2
  • Protipexports.awesome = function() { //yay my code is awesomesauce};var exports.fail = function() { //exports is a global //by redeclaring it as //a local variable //your code _will_ fail};
  • Exercise• Create a CommonJS module called "fish" • Provide functions to: • swim • mouth breath • flop around• Import your module into a node project• Call the various functions
  • Node PackageManager (NPM)
  • NPM is written inJavaScript for Node
  • Enki:~ $ cat `which npm`#!/usr/bin/env node;(function () { // wrapper in case were in module_context modevar log = require("../lib/utils/log")log.waitForConfig()log.info("ok", "it worked if it ends with")var fs = require("../lib/utils/graceful-fs") , path = require("path") , sys = require("../lib/utils/sys") , npm = require("../npm") , ini = require("../lib/utils/ini") , rm = require("../lib/utils/rm-rf")
  • Enki:~/Code/node(master) $ npm install expressexpress@2.3.11 ../../node_modules/express mime@1.2.2 connect@1.4.2 qs@0.1.0Enki:~/Code/node(master) $
  • Yay. Easy.
  • Install instructions https://github.com/isaacs/npm
  • Express.js
  • Sinatra Style MVC framework
  • var app = require(express).createServer();app.get(/, function(req, res){ res.send(hello world);});app.listen(3000);
  • HTTP Verb Oriented
  • Middleware
  • app.use(express.bodyParser());app.use(express.cookieParser());app.post(/, function(req, res){ // Perhaps we posted several items with a form // (use the bodyParser() middleware for this) var items = req.body.items; console.log(items); res.send(logging);});
  • Templating
  • var express = require("express");app.configure(function () { var public = __dirname + "/../public/"; public = require("path").normalize(public); app.set("views", __dirname + "/views"); app.set("view engine", "jade");});app.get("/", function (req, res) { res.render("index", { locals : { h1: Router Stats, scripts : [ "/public/smoothie.js", "/public/raphael.js", "/public/base.js", "/public/gfx.js", "/public/explore.js", "/public/app.js" ] } }});
  • Exercise• Create an Express server• Serve two different pages based on value of the HTTP Get param "page"• Create a redirect from /old to /new• Set a cookie on the client
  • Express in depth
  • Routes• Routes are based on verbs • GET • POST • PUT • DELETE • ALL (not a real verb, but obvious)
  • Simple routes
  • app.get(‘/’, function(req,res) { res.send(‘hello root’);});
  • Routes with variables
  • app.get(‘/user/:id’, function(req,res) { res.send(‘hello ‘ + req.params.id);});
  • Optional flags in routes
  • app.get(‘/:filename?’, function(req,res) { if(req.params.filename) { res.send(req.params.filename); } else { res.send(‘root’); }});
  • Regex as routes
  • app.get(///, function(req, res) { //like using ‘/’ ? res.send(‘/’);});
  • app.get(/^/d+/?$/, function(req,res) { res.send(‘matches a number’);});
  • app.get(/^/(.+)/?$/, function(req,res) { //note translation of %23, etc res.send(‘Got: ’ + req.params[0]); //also captures become an array});
  • Using regex todefine parameters
  • app.get(‘/index.:format((html|json))’,function(req,res) { res.send(Got: + req.params.format);});
  • app.get(/:id(d+), function(req,res) { //only digits, right? res.send(req.params.id);});
  • app.get(/:id(d+), function(req,res) { //escape your in strings res.send(req.params.id);});
  • Routing magic: Router.jsfunction normalizePath(path, keys) { path = path .concat(/?) .replace(//(/g, (?:/) .replace(/(/)?(.)?:(w+)(?:((.*?)))?(?)?/g, function(_, slash, format, key,capture, optional){ keys.push(key); slash = slash || ; return + (optional ? : slash) + (?: + (optional ? slash : ) + (format || ) + (capture || ([^/]+?)) + ) + (optional || ); }) .replace(/([/.])/g, $1) .replace(/*/g, (.+)); return new RegExp(^ + path + $, i);}
  • Routing magic• If . before :variable? then . is also optional• If ? is not after a variable then only the previous character is affected• / at the end of URLs automatically optional• * Can be used as a wildcard in routes• Includes when end of URL is optional e.g. /app/e?• Regex can be used any place in a route string e.g. /app/(d)r?
  • Exercises• Create an express app with routes that capture / /products and /services• Create a route that captures the product ID after /product/ e.g. /product/abc12 and returns it in the response• Use a regular expression to restrict the ID parameter to 3 letter followed by 3-5 numbers• Create a route using a regex that matches the entire route
  • Passing Control• Routes are actually stacked middleware• You can pass control between routes• The next() function calls the next matching route
  • app.get(/users/:id, function(req, res, next){ var id = req.params.id; if (checkPermission(id)) { // show private page } else { next(); }});app.get(/users/:id, function(req, res){ // show public user page});
  • Passing Control• next() is a function of router (and defined in the closure containing the route)• router will grab routes in the order they were declared• e.g. since/* will match everything so it should be the last route!• router doesnt care about verbs so you can use all() to operate on all verbs/routes and then use next() to pass to get(), put(), etc
  • Exercises• Create a simple check for correct product IDs if not pass control to a route showing a custom error page• Use app.all() to check user permission before showing (mock-up) edit controls on a web site
  • Middleware
  • Its a pattern
  • req, resnext()next()next()
  • req, resnext()next() Dispatchernext() req res
  • req, res, next
  • var express = require(express), app = express.createServer();var middleware = function (req, res, next) { req.foo = bar; next();};app.use(middleware);app.get(/, function(req, res) { res.send(req.foo);
  • var express = require(express), app = express.createServer();var middleware = function (req, res, next) { var send = res.send; res.send = function(d) { res.send = send; res.send(hijacked! + d); } next();};app.use(middleware);app.get(/, function(req, res) { res.send(hi);});
  • Connect middleware (Renamed express.* for convenience)• logger • profiler• bodyParser • responseTime• cookieParser • basicAuth• session • favicon• static • vhost• errorHandler
  • var express = require(express), app = express.createServer();app.use(express.logger());app.use(express.bodyParser());app.use(express.cookieParser());app.use(app.router);app.use(express.static(__dirname + /images));app.use(express.errorHandler());app.get(/, function(req, res) { res.send(<html><img src="/image.png"></html);});app.listen(9003);
  • Ordering matters
  • Router uses "internalmiddleware"
  • var express = require(express), app = express.createServer();var middleware = function (req, res, next) { req.foo = bar; next();};app.get(/, middleware, function(req, res) { res.send(req.foo);});
  • var a, b, c, d;a = b = c = d = function(req,res,next) { next();}var set1 = [a,b];var set2 = [c,d];var all = [set1, set2];app.get(/set1, set1, function(req,res) { res.send(output);});app.get(/set2, [c,d], function(req,res) { res.send(output);});app.get(/all, all, function(req,res) { res.send(output);});
  • Middleware factories
  • Middleware are just functions
  • var a, b, c, d;a = b = c = d = function(req,res,next) { next();}var set1 = [a,b];var set2 = [c,d];var all = [set1, set2];app.get(/set1, set1, function(req,res) { res.send(output);});app.get(/set2, [c,d], function(req,res) { res.send(output);});app.get(/all, all, function(req,res) { res.send(output);});
  • var mFactory = function(letter) { return function(req,res,next) { var send = res.send; res.send = function(d) { res.send = send; res.send(letter + + d); } next(); }};var set1 = [mFactory(a),mFactory(b)];var set2 = [mFactory(c),mFactory(d)];var all = [set1, set2];app.get(/set1, set1, function(req,res) { res.send(output);});app.get(/set2, set2, function(req,res) { res.send(output);});app.get(/all, all, function(req,res) { res.send(output);});
  • Exercise• Create a middleware to detect mobile phone browsers and attach a boolean to req• Create an express app that serves up links to an image using staticProvider• Modify Profiler to profile your app and write each profile to a log file• Create a middleware factory that sets the HTTP Expires header based on roles
  • Error handling
  • function NotFound(msg){ this.name = NotFound; Error.call(this, msg); Error.captureStackTrace(this, arguments.callee);}NotFound.prototype.__proto__ = Error.prototype;app.get(/404, function(req, res){ throw new NotFound;});app.get(/500, function(req, res){ throw new Error(keyboard cat!);});
  • app.error(function(err, req, res, next){ if (err instanceof NotFound) { res.render(404.jade); } else { next(err); }});
  • View Rendering
  • app.get(/, function(req, res){ res.render(index.ejs, { title: Falsy Demo });});
  • Enki:~/Code/express-demo $ tree. app.js lib public views index.ejs layout.ejs layout1.ejs partials stylesheet.ejs4 directories, 5 filesEnki:~/Code/express-demo $
  • Dont forget to installnpm install ejsnpm install jade
  • layout.ejs<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <title><%= title %></title> </head> <body> <%- body %> </body></html>
  • • layout is a framework unless you turn it off• body is a special variable for layout referring to the file specified
  • app.set(view engine, ejs);app.get(/, function(req,res) { res.render(index, { title:Falsy Demo});});
  • //globalapp.set(view options), { layout: false;});//or per routeres.render(index, {layout: false});
  • Partial views
  • View Partials• Repeating elements• Take a collection• Iterate over the collection• "Built in" variables for managing collections
  • layout.ejs<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <%- partial(stylesheet, stylesheets) %> <title><%= title %></title> </head> <body> <h1><%= header %></h1> <%- body %> </body></html>
  • partials/stylesheet.ejs<link rel="stylesheet" type="text/css" href="<%-stylesheet %>">
  • res.render(index, { locals: {title: title, header: header, content: content, stylesheets: [/public/style.css] }, });
  • Exercises• Create an express server that use jade, haml, ejs to render an index page• Create a public folder and include file from it (CSS, images, etc) in your layout• Create a route for /blog/id to accept only digits• Make a fake database (array) of blog posts and use a middleware to validate each id is valid• Create a view for the /blog/id show the correct post• Use a view partial to a preview of each blog post on the index page
  • Questions