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

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
14,934
On Slideshare
14,302
From Embeds
632
Number of Embeds
22

Actions

Shares
Downloads
637
Comments
2
Likes
54

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

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • \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

Transcript

  • 1. Node.js WorkshopTom Hughes-CroucherChief Evangelist / Node Tech Lead@sh1mmertom@joyent.com
  • 2. 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
  • 3. Introduction• Tom Hughes-Croucher• Chief Evangelist at Joyent• Node.js core contributor• Author of "Up and Running with Node.js"
  • 4. Scalable Server-Side Code with JavaScriptNode Up and Running Tom Hughes-Croucher
  • 5. Major update this week
  • 6. Why Server-Side JavaScript?
  • 7. JavaScriptprogrammers 3>2>1
  • 8. Massive Code base of jQuery and other JS libraries
  • 9. 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.
  • 10. ProgressiveEnhancement is free*Remember WWCD (What Would Crockford Do) *close enough
  • 11. TL;DR:SSJS is Awesome Like a Unicorn riding a Narwhal
  • 12. If SSJS is so awesomewhy is it "new"?
  • 13. 1. Professionalism
  • 14. “Yahoo!s corporate motto is: Dont be eval().“
  • 15. 2. JavaScript Runtimes
  • 16. Runtimes• V8 (Google), C++• Spider Monkey (Mozilla), C++• Rhino (Mozilla), Java
  • 17. V8 Spider MonkeyJavaScript Performance
  • 18. 8xSep 08! Mar 11!
  • 19. Anatomy of SSJS
  • 20. Node { !
  • 21. Runtime != Browser
  • 22. No DOM(By default, anyway)
  • 23. 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
  • 24. What is Node?
  • 25. Node• JavaScript programming environment• Uses V8 runtime• Event Driven• Non-blocking libraries• Supports CommonJS module format• Supports C/C++ based add-ons
  • 26. Woah! Overload.
  • 27. 1. Its JavaScript
  • 28. See Above.
  • 29. 2. Its Fast
  • 30. 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)
  • 31. 3. Its easy to extend
  • 32. Modules in JSAdd-ons in C
  • 33. 4. Node is _not_ Rails/ Django/etc
  • 34. Node is bare-bone to the metal
  • 35. However, the Nodecommunity are making Rails/Django/etc
  • 36. 5. Node is young
  • 37. Stable is "stable"Unstable moves fast
  • 38. Using Node
  • 39. Using Node• Part 1. Installation• Part 2. Basics• Part 3. Getting stuck in
  • 40. Part 1. Installation
  • 41. Navea.k.a the easy way
  • 42. Enki:~ $ wget -q http://github.com/isaacs/nave/raw/master/nave.shEnki:~ $ chmod 755 nave.shEnki:~ $ ./nave.sh install latest
  • 43. Nave• Installs and versions Node• Allows Node shells with specific versions• Allows you to get latest <-- Stable• May add unstable option in future
  • 44. Manual Installation
  • 45. Go to http://nodejs.org/#downloadand get the URL of the current stable release
  • 46. 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 $
  • 47. Local or system?
  • 48. Local
  • 49. 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)
  • 50. 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...
  • 51. 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 $
  • 52. 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
  • 53. System
  • 54. 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 $
  • 55. Exercise• Get Node head from Github using Git• Install to ~/node
  • 56. Part 2. Basics
  • 57. node-replInteractive JavaScript terminal
  • 58. $Enki:~ $ node
  • 59. $Enki:~ $ node>3>2>1false> true == 1true> true === 1false
  • 60. > 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:~ $
  • 61. 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)
  • 62. 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/);
  • 63. var http = require(http);//include the http library
  • 64. 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
  • 65. 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
  • 66. 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
  • 67. Interactive Debugging
  • 68. Enki:~/Code/node-examples $ node --debughelloworld.jsdebugger listening on port 5858Server running at http://127.0.0.1:8124/
  • 69. 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
  • 70. 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
  • 71. Part 3. Getting Stuck In
  • 72. HTTP Client
  • 73. 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); });
  • 74. Streaming API
  • 75. write(data) write(data) DestinationRequest end() (google.com) response(headers) data(chunk) data(chunk) Response data(chunk) end()
  • 76. 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
  • 77. Events
  • 78. object.on(event, function() { //stuff} );
  • 79. EventEmitter
  • 80. EventEmitter• manage "event handlers" • list of functions to be called per event• provide mechanism to trigger events
  • 81. var util = require(util), EE = require(events).EventEmitter;util.inherits(MyClass, EE);var myObj = new MyClass();//nb using first class functionsmyObj.on(something, function);
  • 82. exports.inherits = function (ctor, superCtor) { ctor.super_ = superCtor; ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false } });};
  • 83. More than just core
  • 84. CommonJS Modules
  • 85. Library format for SSJS
  • 86. 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
  • 87. 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};
  • 88. 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
  • 89. Node PackageManager (NPM)
  • 90. NPM is written inJavaScript for Node
  • 91. 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")
  • 92. 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) $
  • 93. Yay. Easy.
  • 94. Install instructions https://github.com/isaacs/npm
  • 95. Express.js
  • 96. Sinatra Style MVC framework
  • 97. var app = require(express).createServer();app.get(/, function(req, res){ res.send(hello world);});app.listen(3000);
  • 98. HTTP Verb Oriented
  • 99. Middleware
  • 100. 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);});
  • 101. Templating
  • 102. 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" ] } }});
  • 103. 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
  • 104. Express in depth
  • 105. Routes• Routes are based on verbs • GET • POST • PUT • DELETE • ALL (not a real verb, but obvious)
  • 106. Simple routes
  • 107. app.get(‘/’, function(req,res) { res.send(‘hello root’);});
  • 108. Routes with variables
  • 109. app.get(‘/user/:id’, function(req,res) { res.send(‘hello ‘ + req.params.id);});
  • 110. Optional flags in routes
  • 111. app.get(‘/:filename?’, function(req,res) { if(req.params.filename) { res.send(req.params.filename); } else { res.send(‘root’); }});
  • 112. Regex as routes
  • 113. app.get(///, function(req, res) { //like using ‘/’ ? res.send(‘/’);});
  • 114. app.get(/^/d+/?$/, function(req,res) { res.send(‘matches a number’);});
  • 115. app.get(/^/(.+)/?$/, function(req,res) { //note translation of %23, etc res.send(‘Got: ’ + req.params[0]); //also captures become an array});
  • 116. Using regex todefine parameters
  • 117. app.get(‘/index.:format((html|json))’,function(req,res) { res.send(Got: + req.params.format);});
  • 118. app.get(/:id(d+), function(req,res) { //only digits, right? res.send(req.params.id);});
  • 119. app.get(/:id(d+), function(req,res) { //escape your in strings res.send(req.params.id);});
  • 120. 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);}
  • 121. 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?
  • 122. 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
  • 123. Passing Control• Routes are actually stacked middleware• You can pass control between routes• The next() function calls the next matching route
  • 124. 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});
  • 125. 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
  • 126. 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
  • 127. Middleware
  • 128. Its a pattern
  • 129. req, resnext()next()next()
  • 130. req, resnext()next() Dispatchernext() req res
  • 131. req, res, next
  • 132. 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);
  • 133. 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);});
  • 134. Connect middleware (Renamed express.* for convenience)• logger • profiler• bodyParser • responseTime• cookieParser • basicAuth• session • favicon• static • vhost• errorHandler
  • 135. 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);
  • 136. Ordering matters
  • 137. Router uses "internalmiddleware"
  • 138. 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);});
  • 139. 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);});
  • 140. Middleware factories
  • 141. Middleware are just functions
  • 142. 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);});
  • 143. 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);});
  • 144. 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
  • 145. Error handling
  • 146. 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!);});
  • 147. app.error(function(err, req, res, next){ if (err instanceof NotFound) { res.render(404.jade); } else { next(err); }});
  • 148. View Rendering
  • 149. app.get(/, function(req, res){ res.render(index.ejs, { title: Falsy Demo });});
  • 150. 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 $
  • 151. Dont forget to installnpm install ejsnpm install jade
  • 152. layout.ejs<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <title><%= title %></title> </head> <body> <%- body %> </body></html>
  • 153. • layout is a framework unless you turn it off• body is a special variable for layout referring to the file specified
  • 154. app.set(view engine, ejs);app.get(/, function(req,res) { res.render(index, { title:Falsy Demo});});
  • 155. //globalapp.set(view options), { layout: false;});//or per routeres.render(index, {layout: false});
  • 156. Partial views
  • 157. View Partials• Repeating elements• Take a collection• Iterate over the collection• "Built in" variables for managing collections
  • 158. 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>
  • 159. partials/stylesheet.ejs<link rel="stylesheet" type="text/css" href="<%-stylesheet %>">
  • 160. res.render(index, { locals: {title: title, header: header, content: content, stylesheets: [/public/style.css] }, });
  • 161. 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
  • 162. Questions