├── .gitignore └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn node 2 | A one day introductory workshop on Node! 3 | 4 | By the end of this workshop you'll be able to answer the following questions: 5 | * [ ] What is Node? Why do you need it? 6 | * [ ] What is a server? 7 | * [ ] What is npm? How do you use it? 8 | * [ ] What are node modules? 9 | * [ ] What is a package.json? 10 | * [ ] What are 'module exports' and 'require'? 11 | * [ ] What is a module? 12 | 13 | We'll be doing the following things: 14 | * Installing Node 15 | * Creating a basic 'Hello world' Node server 16 | * Learning how to use the 'fs' core module to read and write from the file system 17 | * Setting up 'nodemon' for your development environment 18 | * Creating a route for your server 19 | 20 | ## What is Node? 21 | 22 | In one sentence it's 'Javascript for the server'!! 23 | 24 | Wikipedia says: 25 | 26 | > Node.js is a packaged compilation of 27 | > Google’s V8 JavaScript engine, the libuv 28 | > platform abstraction layer, and a core library, which is itself primarily written in JavaScript. 29 | 30 | Node has an asynchronous, event-driven I/O model. Node is an interface to the V8 JavaScript runtime – the JavaScript interpreter that runs in the Chrome browser. 31 | 32 | This is a pretty good intro video: 33 | [What is Node.js Exactly? - a beginners introduction to Nodejs](https://www.youtube.com/watch?v=pU9Q6oiQNd0) 34 | 35 | Node v4.0.0 is now available and supports lots of ES6 features. 36 | (ES6 - aka ECMAScript 6 or ECMAScript 2015 - is a newer version of JavaScript with a bunch of new features. It's not 100% supported everywhere yet, but it will be eventually). 37 | 38 | For a detailed description of node checkout [@heron2014](https://github.com/heron2014)'s '['what-is-node tutorial'](https://github.com/node-girls/what-is-node). 39 | 40 | If you want to learn ES6 Look up [@benjaminlees](https://github.com/benjaminlees)'s [tutorial](https://github.com/benjaminlees/Es6)! 41 | 42 | ### So what is a server? And why do I need one? 43 | 44 | ***Servers*** are computer programs that receive requests from other programs, ***the clients*** and send back a response e.g share data, information or hardware and software resources. 45 | 46 | In a typical web app a server could perform some of these functions: 47 | 48 | * Handle manipulation of data in the database 49 | * File manipulation 50 | * Authentication 51 | * Lots of secret logic 52 | 53 | Client side code sends requests to a server which sends back data to the front end which can then be displayed. 54 | 55 | Front end Javascript is executed in the site visitor's browser whereas server-side code runs on a site's web server. 56 | 57 | ## Installing Node 58 | 59 | Download Node from the [NodeJS website](https://docs.npmjs.com/getting-started/installing-node) 60 | 61 | ### The interactive node.js shell 62 | 63 | If Node is installed properly, you should be able to invoke the interactive node.js shell by typing `node` into the command line. You can then type any Javascript code and it will be executed. 64 | 65 | ```js 66 | $ node 67 | > console.log('Hello World'); 68 | Hello World 69 | ``` 70 | 71 | The shell is a great way to test simple one liners. In order to escape from the shell, simply press Ctrl + C. 72 | 73 | # SECTION 1 74 | 75 | ## Node Modules and the Node Package Manager (NPM) 76 | 77 | Modules are just small programs you can integrate with the bigger program you are writing. 78 | 79 | 'Core' Node modules come with Node automatically. But there are thousands of open-source, 3rd-party Node modules that other clever people have written. You can download useful 3rd-party modules (also known as "packages") from the Node Package Manager. 80 | 81 | The NPM website says: 82 | 83 | > ***npm*** makes it easy for JavaScript 84 | > developers to share and reuse code, and it 85 | > makes it easy to update the code that 86 | > you're sharing. 87 | 88 | Node comes with npm installed. However, npm gets updated more frequently than Node does so make sure it's the latest version. 89 | 90 | Check the version 91 | 92 | ```js 93 | $ npm --version 94 | // the version should be 3.3.4 95 | ``` 96 | 97 | If it is not the latest version then type: 98 | 99 | ```js 100 | sudo npm install npm -g 101 | ``` 102 | 103 | By default, npm installs any dependency in the local mode - the node_modules directory in the folder where Node application is present. The `-g` flag means npm will be installed globally so not just for a particular project. 104 | 105 | Now you can use npm to create and install external modules for your project! 106 | 107 | ### Creating a new NodeJS projects 108 | 109 | Type this command into your terminal in the folder you want to create the project. 110 | 111 | ```js 112 | npm init 113 | 114 | ``` 115 | 116 | This takes you through the process of creating a file called a `package.json` which is a json object that contains information about your project and its dependencies. It looks a bit like this: 117 | 118 | ```js 119 | { 120 | "name": "autocomplete-nikki", 121 | "version": "1.0.2", 122 | "description": "find words in English dictionary with autosuggestion!", 123 | "main": "index.js", 124 | "directories": { 125 | "test": "test" 126 | }, 127 | "scripts": { 128 | "test": "node test/test.js" 129 | }, 130 | "repository": { 131 | "type": "git", 132 | "url": "https://github.com/nikhilaravi/autocomplete.git" 133 | }, 134 | "keywords": [ 135 | "autocomplete", 136 | "english", 137 | "dictionary", 138 | "suggestions" 139 | ], 140 | "author": "nikhilaravi", 141 | "license": "ISC", 142 | "bugs": { 143 | "url": "https://github.com/nikhilaravi/autocomplete/issues" 144 | }, 145 | "homepage": "https://github.com/nikhilaravi/autocomplete", 146 | "engines": { 147 | "node": ">= 0.10" 148 | }, 149 | "dependedncies": { 150 | "pre-commit": "^1.0.7" 151 | } 152 | } 153 | 154 | ``` 155 | The package.json is the file that makes it possible for others to install and run your project, once you've built it. When someone installs your project, npm will look through the package.json and install any modules that your project depends on, hence the name *dependencies*. 156 | 157 | Key attributes in the package.json: 158 | 159 | * name 160 | * version 161 | * description 162 | * homepage 163 | * author 164 | * contributors 165 | * scripts - these are commands that you define. You can run them from the command line using `npm run `. We'll use this to run tests and start our server 166 | * dependencies 167 | * repository - repository type and url of the git repository 168 | * main 169 | * keywords 170 | 171 | Remember: 172 | 173 | * You can't add comments to a .json file! 174 | * Watch out for trailing commas in your json object as this will cause errors when trying to `npm install`! 175 | 176 | ### Installing new node modules 177 | 178 | ```js 179 | npm install --save 180 | 181 | ``` 182 | 183 | This creates a folder called `node_modules` within your project and installs the node module's files in it. The `--save` flag saves the name of the module into the `dependencies` in the package.json. You can leave out the `--save` flag, but then you would have to remember to add the module to your package.json manually. 184 | 185 | The version of the module is also shown using the ['Semver Rule'](https://docs.npmjs.com/getting-started/semantic-versioning) 186 | 187 | Remember to add `node_modules` to your `.gitignore` file so you don't push all the node module files up to Github! The package.json is all someone would need to run your project. Once the package is in node_modules, you can use it in your code. 188 | 189 | When you clone a Node.js project or pull down the latest version of your project from GitHub you should install any new node modules using the command. 190 | 191 | ```js 192 | npm install 193 | 194 | or 195 | 196 | npm i 197 | ``` 198 | 199 | This installs the modules listed in your package.json to the node_modules folder e.g. 200 | 201 | ``` 202 | var mandrill = require('mandrill'); //Mandrill is a module for setting up an email client 203 | 204 | ``` 205 | 206 | # SECTION 2 207 | 208 | ## Structuring a module 209 | 210 | We've already mentioned two types of module: 211 | - Core Node modules that come with Node.js 212 | - 3rd-party modules that you can download and use into your code (sometimes called "packages") 213 | 214 | There's a third type of module in Node - your own modules! 215 | To keep your project organised, you might separate out some of your code into a different file. You can `require` a file into another one, just as you would with a core Node module or a 3rd-party module. Hence, these are *also* called modules. 216 | 217 | We will try this out now. Create a file called `library.js`. 218 | 219 | ```js 220 | "use strict"; 221 | 222 | var books = { 223 | "Emma": { 224 | author: 'Jane Austen', 225 | published: 'December 25, 1815' 226 | }, 227 | "Harry Potter and the Goblet of Fire": { 228 | author: 'JK Rowling', 229 | published: 'July 8, 2000' 230 | }, 231 | "Eloquent Javascript": { 232 | author: 'Marijn Haverbeke', 233 | published: '2011' 234 | } 235 | }; 236 | 237 | function getBookAuthor(name) { 238 | return books[name].author 239 | }; 240 | 241 | function getDatePublished(name) { 242 | return books[name].published 243 | }; 244 | 245 | ``` 246 | To enable the functions to be used by other files, you need to export the functions. 247 | 248 | Add this line to the end of library.js: 249 | 250 | ```js 251 | 252 | module.exports = { 253 | getBookAuthor: getBookAuthor, 254 | getDatePublished: getDatePublished 255 | }; 256 | 257 | ``` 258 | 259 | Other files can then import `library.js` and use the methods returned. 260 | 261 | In another file (e.g. librarian.js): 262 | 263 | ```js 264 | var Library = require('./library.js'); 265 | 266 | Library.getBookAuthor("Emma"); 267 | 268 | ``` 269 | Node modules and Javascript files do not need an extension (e.g. 'js') when being specified inside `require()`. However it can be helpful to add '.js' to the end of your local javascript files so it's easier to differentiate between your own files and node modules. 270 | 271 | E.g. 272 | 273 | ``` 274 | var http = require('http'); 275 | var myFile = require('myFile.js'); 276 | 277 | ``` 278 | 279 | Inside the call to `require`, the path to the file needs to be specified. 280 | 281 | > A required module prefixed with '/' is an absolute path to the file. For > example, require('/home/marco/foo.js') will load the file at /home/marco/foo.js. 282 | 283 | > A required module prefixed with './' is relative to the file calling > require(). That is, circle.js must be in the same directory as foo.js for > require('./circle') to find it. 284 | 285 | Use the '../' prefix for a file in the directory above the current file. 286 | 287 | Relative paths are explained in more detail in the [Node Docs](https://nodejs.org/api/modules.html#modules_file_modules) 288 | 289 | # SECTION 3 290 | 291 | ## Create your first http server! 292 | 293 | Node.js has several modules compiled into the binary e.g. 'http', 'fs', 'querystring' . These are called 'core modules'. 294 | 295 | Core modules are always preferentially loaded. For instance, require('http') will always return the built-in http module, even if there is a file by that name. 296 | 297 | Create a file called server.js and add the following code: 298 | 299 | ```js 300 | var http = require('http'); 301 | 302 | // set the port for the server 303 | var port = process.env.PORT || 8000; 304 | ``` 305 | 306 | This loads in the `http` module which we will use to create a web server that processes requests using http. 307 | 308 | When a request reaches the server, we need a way of responding to it. In comes the `handler` function. This is just a function that takes in a `request` and `response` object and sends the response back to the client along with some information. We call it handler because it 'handles' requests and responses. 309 | 310 | ```js 311 | 312 | function handler(request, response) { 313 | //display 'HELLO WORLD' when the user is on the home page 314 | var url = request.url; //e.g. '/' 315 | if (url.length === 1) { 316 | response.writeHead(200, {"Content-Type": "text/html"}); 317 | response.end("HELLO WORLD!"); 318 | } 319 | } 320 | 321 | http.createServer(handler).listen(port); 322 | 323 | console.log('node http server listening on http://localhost:' + port); 324 | ``` 325 | 326 | Inside the call to `http.createServer()'` we pass in our handler function. The handler gets called every time someone connects to the app. Lets take a closer look at the two parameters the handler function takes: 327 | 328 | * ***request*** - this object contains the information about what the visitor asked for including name of the page that was requested, the settings, and any fields filled in on a form. 329 | 330 | * ***response*** - this is the object which contains the information that you send back to the user. 331 | 332 | `response.writeHead(200)` sends back a status code of 200 in the response header to the request to say that everything is okay. The response headers are used to describe the resource being fetched or the behavior of the server. 333 | The status code is a 3-digit http status code, like 404. The second argument of the `writeHead` function are the response headers. This function must be called before `response.end()`. 334 | 335 | Now start the server! In the command line type: 336 | 337 | ```js 338 | node server.js 339 | ``` 340 | 341 | In the browser navigate to `http://localhost:8000`. You should see your 'Hello world' message! 342 | 343 | # SECTION 4 344 | 345 | ## Reading from the file system 346 | 347 | We're going to create an index.html file and then serve it up when the user navigates to the home page. You can use the template below or create your own! 348 | 349 | ```js 350 | 351 | 352 | 353 |

Hello

354 | 355 | 356 | 357 | ``` 358 | 359 | Back to our server file. Import the 'fs' core node module - this allows reading and writing to the file system. 360 | 361 | Then read in the index.html file and save it as a variable. `__dirname` is used to get the name of the directory that the currently file resides in. 362 | Don't forget the '/' after `__dirname` :wink: 363 | 364 | ```js 365 | var fs = require('fs'); 366 | fs.readFile(__dirname + '/index.html', function (error, index) { 367 | // send the index back to the client! 368 | }); 369 | ``` 370 | 371 | Then send back the html file in the response, with `response.write()`. 372 | ```js 373 | response.write(index); 374 | response.end(); 375 | ``` 376 | 377 | Psst! A shorthand version is to leave out `response.write()` and pass the data directly into `response.end()`. Change the call to `response.end` to be: 378 | ```js 379 | response.end(index); 380 | ``` 381 | 382 | Restart the server and you should see the page from index.html! 383 | 384 | # SECTION 5 385 | 386 | ## Server Routes 387 | 388 | For different requests you might want to carry out different functions or retrieve specific data. These can be specified through the URL of the request and you can create specific routes in your server to handle these requests. 389 | 390 | Lets look at an example: 391 | 392 | Lets say you have a button on your home page that when clicked sends an http request with a url of `/cat`. It might look something like this: 393 | 394 | ```js 395 | var request = new XMLHttpRequest(); 396 | request.onreadystatechange = function() { 397 | if(request.readyState === 4) { 398 | displayImage(request.responseText); 399 | }; 400 | }; 401 | request.open("GET", "/cat", true); 402 | request.send(); 403 | ``` 404 | 405 | Don't worry about the `displayImage` function for now - let's pretend it takes html string with an image and adds it to the page. 406 | 407 | On the server you would look at the url of the request and if it is `/cat` you want to send back the cat image requested by the client: 408 | 409 | ```js 410 | function(request, response) { 411 | var url = request.url 412 | if (url.indexOf('/cat') > -1) { 413 | // check if the url contains /cat and if so send back a link to a cat image e.g. from a database or an API 414 | response.writeHead(200, {"Content-Type": "text/html"}); 415 | response.end('') 416 | } 417 | } 418 | ``` 419 | 420 | You can also have nested urls e.g. `/cat/lion`. In the server you can split the request url to get this additional information: 421 | 422 | ```js 423 | var type = url.split('/')[2].toString(); 424 | 425 | ``` 426 | 427 | # SECTION 6 428 | 429 | ## Generic route handler 430 | 431 | When you add css or js files in your index.html they won't load the same as just a purely front end app. You need to create a route in your server to serve these files. 432 | 433 | Create a `main.css` file and add a link to this file to your `index.html` page e.g. 434 | 435 | ```js 436 | 437 | 438 | 439 | 440 | 441 | 442 |

Hello

443 | 444 | 445 | 446 | ``` 447 | 448 | Add the following code to your server handler as a final `else` branch. 449 | 450 | ```js 451 | fs.readFile(__dirname + url, function(error, file){ 452 | if (error){ 453 | console.log(error); 454 | response.end(); 455 | } else { 456 | var ext = url.split('.')[1]; 457 | response.writeHead(200, {'Content-Type' : 'text/' + ext}); 458 | response.end(file); 459 | } 460 | } 461 | ``` 462 | 463 | Okay let's break down this function: 464 | 465 | 1. To load the main.css file the client sends a request to the server with a url of `main.css`. 466 | 2. The url is the filename, so the function can read the contents of the file from the filesystem. 467 | 3. To know what type of file it is (e.g. css, js, html), we split the url on the `.`. So for `url = main.css`, `url.split('.')` would result in an array with two elements: `[main, css]`. We take the second element of the array and set this to be the content type in the response header. 468 | 4. Finally we send back the contents of the file in the response of the http request. 469 | 470 | ## Nodemon 471 | 472 | Instead of having to restart the server every time you change any of your code you can install a module that will monitor for any changes in your javascript files and automatically restart the server! 473 | 474 | ```js 475 | npm install -g nodemon 476 | ``` 477 | 478 | In the scripts part of your package.json add the following line: 479 | ```js 480 | "start": "nodemon server.js" 481 | ``` 482 | 483 | You can then start the server by typing `npm start` in the command line. 484 | 485 | # Extensions 486 | 487 | ## EventEmitters 488 | 489 | If you make a post request and send some data with the request you need a way of reading the data on the server side. For this you need to listen for the 'data' event on the request. 490 | 491 | ```js 492 | var requestData = ''; 493 | request.on('data', function(chunk) { 494 | requestData += chunk; 495 | }); 496 | ``` 497 | 498 | ## Environment variables 499 | 500 | If you are using APIs, you don't want to push the API Keys up to Github. To keep the keys secret we want to save them as environment variables. 501 | 502 | Follow [@nelsonic](https://github.com/nelsonic)'s tutorial to learn how this works! 503 | [https://github.com/dwyl/learn-environment-variables](https://github.com/dwyl/learn-environment-variables) 504 | 505 | ## Install the Node.js version manager module 506 | 507 | `npm install -g n` 508 | 509 | Use this to set which version of node you are running. In the future you may want to switch between versions of node or use io.js and you can easily do this by typing 'n' into the terminal and toggling the up and down arrows. 510 | --------------------------------------------------------------------------------