Let’s Node.js!
node app.js
Global Object
https://nodejs.org/dist/latest-v6.x/docs/api/globals.html
1 2 3 4 5 6 7 8
| console.log(__dirname); console.log(__filename); /Users/Hsu/code/nodejs/practice /Users/Hsu/code/nodejs/practice/app.js */
|
Modules and require()
https://nodejs.org/dist/latest-v6.x/docs/api/modules.html
EX1
1 2 3 4 5 6
| var counter = function (arr) { return '有 ' + arr.length + ' 個元素在這個陣列。'; }; module.exports = counter;
|
1 2 3 4 5 6 7 8
| var you_can_use_other_name = require('./stuff'); console.log(you_can_use_other_name(['hi', 'bye', 'good'])); 有 3 個元素在這個陣列。 */
|
EX2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| var counter = function (arr) { return '有 ' + arr.length + ' 個元素在這個陣列。'; }; var adder = function (a, b) { return `${a}與${b}的總和是${a+b}。`; } var pi = 3.1415926535; module.exports = { counter: counter, adder: adder, pi: pi }
|
1 2 3 4 5 6 7 8 9 10 11
| var stuff = require('./stuff'); console.log(stuff.counter(['hi', 'bye', 'good'])); console.log(stuff.adder(4, 1)); console.log(stuff.adder(stuff.pi, 1)); 有 3 個元素在這個陣列。 4與1的總和是5。 3.1415926535與1的總和是4.1415926535。 */
|
Events
https://nodejs.org/dist/latest-v6.x/docs/api/events.html
EX1
1 2 3 4 5 6 7 8 9 10
| var events = require('events'); var myEmitter = new events.EventEmitter(); myEmitter.on('someEvent', function (msg) { console.log(msg); }); myEmitter.emit('someEvent', 'the event was emmitted');
|
EX2
https://nodejs.org/dist/latest-v6.x/docs/api/util.html#util_util_inherits_constructor_superconstructor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| var events = require('events'); var util = require('util'); var Person = function (name) { this.name = name; }; util.inherits(Person, events.EventEmitter); var james = new Person('james'); var mary = new Person('mary'); var ryu = new Person('ryu'); var people = [james, mary , ryu]; people.forEach(function (person) { person.on('speak', function (msg) { console.log(person.name + ' 說:' + msg); }) }) james.emit('speak', '你好啊');
|
EX2-ES6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const EventEmitter = require('events'); class Person extends EventEmitter { constructor(name) { super(); this.name = name; } } const james = new Person('james'); const mary = new Person('mary'); const ryu = new Person('ryu'); let people = [james, mary , ryu]; people.forEach( (person) => { person.on('speak', (msg) => { console.log(person.name + ' 說:' + msg); }) }) james.emit('speak', '你好啊');
|
File System
了解同步、非同步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var fs = require('fs'); fs.readFile('README.md', 'utf-8', function(err, data) { console.log("readFile"); }); console.log('end. of readFile'); var data2 = fs.readFileSync('README.md', 'utf-8'); console.log("readFileSync"); console.log('end. of readFileSync'); end. of readFile readFileSync end. of readFileSync readFile */
|
EX:讀寫檔案
1 2 3 4 5 6 7 8 9 10 11
| const fs = require('fs'); const readme = fs.readFile('README.md', 'utf8', function (err, data) { fs.writeFile('WRITEME.md', data); });
|
EX:資料夾、刪除檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const fs = require('fs'); fs.mkdir('stuff', function () { fs.readFile('README.md', 'utf8' ,function (err, data) { fs.writeFile('./stuff/WRITEME.md', data); }); }); fs.unlink('./stuff/WRITEME.md', function () { fs.rmdir('stuff'); });
|
Http
https://nodejs.org/dist/latest-v6.x/docs/api/http.html
1 2 3 4 5 6 7 8 9 10 11
| const http = require('http'); var server = http.createServer(function (req, res) { console.log('有人連進來囉~' + req.url); res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('HiHi'); }); server.listen(3000, 'localhost'); console.log('現在監聽著 Port 3000');
|
Stream
https://nodejs.org/dist/latest-v6.x/docs/api/stream.html
Read Stream
讀檔的時候可以一片段一片段的傳給使用者
https://nodejs.org/dist/latest-v6.x/docs/api/stream.html#stream_event_data
1 2 3 4 5 6 7 8 9
| const fs = require('fs'); var myReadStream = fs.createReadStream(__dirname + '/README.md', 'utf8'); myReadStream.on('data', function (chunk) { console.log('new chunk received'); })
|
Write Stream
https://nodejs.org/dist/latest-v6.x/docs/api/stream.html#stream_writable_streams
1 2 3 4 5 6 7 8 9 10
| const fs = require('fs'); var myReadStream = fs.createReadStream(__dirname + '/README.md', 'utf8'); var myWriteStream = fs.createWriteStream(__dirname + '/WRITEME.md'); myReadStream.on('data', function (chunk) { console.log('new chunk received'); myWriteStream.write(chunk); })
|
Write Stream: Pipe
https://nodejs.org/dist/latest-v6.x/docs/api/stream.html#stream_readable_pipe_destination_options
1 2 3 4 5 6 7
| const fs = require('fs'); var myReadStream = fs.createReadStream(__dirname + '/README.md', 'utf8'); var myWriteStream = fs.createWriteStream(__dirname + '/WRITEME.md'); myReadStream.pipe(myWriteStream);
|
Http + Stream
Read File
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const http = require('http'); const fs = require('fs'); var server = http.createServer(function (req, res) { console.log('有人連進來囉~' + req.url); res.writeHead(200, { 'Content-Type': 'text/plain' }); var myReadStream = fs.createReadStream(__dirname + '/README.md', 'utf8'); myReadStream.pipe(res); }); server.listen(3000, 'localhost'); console.log('現在監聽著 Port 3000');
|
Read HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const http = require('http'); const fs = require('fs'); var server = http.createServer(function (req, res) { console.log('有人連進來囉~' + req.url); res.writeHead(200, { 'Content-Type': 'text/html' }); var myReadStream = fs.createReadStream(__dirname + '/index.html', 'utf8'); myReadStream.pipe(res); }); server.listen(3000, 'localhost'); console.log('現在監聽著 Port 3000');
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <!-- index.html --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style media="screen"> body { background: skyblue; color: #fff; padding: 30px; } .text-center { text-align: center; } </style> </head> <body> <h1 class="text-center">Aha</h1> </body> </html>
|
綜合應用
Return JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const http = require('http'); const fs = require('fs'); var server = http.createServer(function (req, res) { console.log('有人連進來囉~' + req.url); res.writeHead(200, { 'Content-Type': 'application/json' }); var myObj = { name: 'QQ', job: 'Sing' }; res.end(JSON.stringify(myObj)); }); server.listen(3000, 'localhost'); console.log('現在監聽著 Port 3000');
|
Routing 原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const http = require('http'); const fs = require('fs'); var server = http.createServer(function (req, res) { console.log('有人連進來囉~' + req.url); if (req.url === '/') { res.writeHead(200, { 'Content-Type': 'text/html' }); fs.createReadStream(__dirname + '/index.html').pipe(res); } else if (req.url === '/api/goods') { res.writeHead(200, { 'Content-Type': 'application/json' }); var myObj = { name: 'QQ' }; res.end(JSON.stringify(myObj)); } else { res.writeHead(404, {'Content-Type': 'text/plain'}); res.end('404 Not Found'); } }); server.listen(3000, 'localhost'); console.log('現在監聽著 Port 3000');
|
MongoDB 相關
robomongo(GUI)
https://robomongo.org
開源、跨平台
Mongoose
https://www.npmjs.com/package/mongoose
http://mongoosejs.com/
mLab
https://mlab.com
express
https://www.npmjs.com/package/express
https://expressjs.com
Init
npm init
npm install express -S
1 2 3 4 5 6 7 8 9 10
| var express = require('express'); var app = express(); app.get('/', function (req, res) { res.send('HiHi'); }); app.listen(3000);
|
nodemon app.js
SendFile
1 2 3 4 5 6 7 8
| var express = require('express'); var app = express(); app.get('/', function (req, res) { res.sendFile(__dirname + '/index.html'); }); app.listen(3000);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <!-- /index.html --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style media="screen"> body { background: skyblue; color: #fff; padding: 30px; } .text-center { text-align: center; } </style> </head> <body> <h1 class="text-center">Aha</h1> </body> </html>
|
Route Params
1 2 3 4 5 6 7 8 9 10 11 12 13
| var express = require('express'); var app = express(); app.get('/', function (req, res) { res.sendFile(__dirname + '/index.html'); }); app.get('/profile/:id', function (req, res) { res.send('HiHi ' + req.params.id); }); app.listen(3000);
|
Template Engines: ejs
https://expressjs.com/en/4x/api.html#res.sendFile
npm install ejs -S
傳參數
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var express = require('express'); var app = express(); app.set('view engine', 'ejs'); app.get('/', function (req, res) { res.sendFile(__dirname + '/index.html'); }); app.get('/profile/:id', function (req, res) { let data = { name: 'QQQ', age: 99, array: ['A', 'B', 'C'] }; let array = [ { name: 'Q'}, { name: 'QQ'}, { name: 'QQQ'} ]; res.render('profile', { id: req.params.id, data: data, array: array }); }); app.listen(3000);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <!-- views/profile.html --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style media="screen"> body { background: skyblue; color: #fff; padding: 30px; } .text-center { text-align: center; } </style> </head> <body> <h1 class="text-center">Welcome! <%= id %></h1> <p>Name: <%= data.name %></p> <p>Age: <%= data.age %></p> <ul> <% data.array.forEach(item => { %> <li><%= item %></li> <% }); %> </ul> <ul> <% array.forEach(item => { %> <li><%= item.name %></li> <% }); %> </ul> </body> </html>
|
Partial Templates
1
| <% include partials/nav.ejs %>
|
1 2 3 4 5 6 7
| <!-- views/partials/nav.ejs --> <nav> <ul> <li><a href="/">Home</a></li> <li><a href="/profile/QQQ">Profile</a></li> </ul> </nav>
|
Middleware
1 2 3 4 5
| app.use('/assets', function (req, res, next) { console.log(req.url); next(); })
|
Static Files
https://expressjs.com/en/starter/static-files.html
link directory /assets
1 2
| app.use('/assets', express.static('assets'));
|
Query Strings
https://expressjs.com/en/4x/api.html#req.query
1 2 3
| app.get('/query', function (req, res) { res.render('query', { qs: req.query } ); });
|
http://localhost:3000/query?qq=qqqqqqqqqqqq
POST REQUEST
https://expressjs.com/en/4x/api.html#req.body
https://www.npmjs.com/package/body-parser
npm install body-parser
1 2 3 4 5 6 7 8 9
| var bodyParser = require('body-parser') var urlencodedParser = bodyParser.urlencoded({ extended: false }) app.post('/query', urlencodedParser, function (req, res) { console.log(req.body); res.end('post-success ' + JSON.stringify(req.body)); });
|
Express Generate
npm install express-generator -g
express -h
Express Todo List
npm init
npm install express --save
npm install ejs --save
npm install body-parser --save
npm install mongoose --save
https://github.com/lovenery/express-todo
very brief and basic api format example.
NPM
https://www.npmjs.com
nodemon
https://www.npmjs.com/package/nodemon
開發階段可以不重開node.js
npm install -g nodemon
morgan
logger
npm install morgan -S
1 2 3
| var morgan = require('morgan'); app.use(morgan('dev'));
|
cookie, session
https://www.npmjs.com/package/cookie-parser
https://www.npmjs.com/package/express-session
passport.js
http://passportjs.org/
Facobook Login
https://github.com/jaredhanson/passport-facebook
For API
https://github.com/jaredhanson/passport-http-bearer
express-message
快閃資料
https://github.com/expressjs/express-messages
bcrypt
https://www.npmjs.com/package/bcrypt
connect-mongo
MongoDB session store for Express and Connect
https://github.com/jdesboeufs/connect-mongo
pm2, forever
https://github.com/Unitech/pm2
sudo npm install pm2 -g
pm2 start index.js
pm2 stop index.js
需要sudo來使用1024以下之port
sudo npm install pm2 -g
sudo pm2 list
sudo pm2 start index.js
sudo pm2 stop index.js
sudo pm2 delete index.js
sudo pm2 startup
sudo pm2 unstartup
Debuger
budo (client side)
https://github.com/mattdesl/budo
node-inspector (server side)
https://github.com/node-inspector/node-inspector
內建的 不太好用
node debug xxxx.js
還在實驗階段
node --inspect xxxx.js