Friday, August 7, 2015

Auto restart node daemon: รีสตาร์ทเมื่อแก้ไขซอร์สโค้ด#2

Update: 25/09/2018
-----------------------
หลังจากใช้ pm2 อยู่นาน ไม่ได้เข้าไปวุ่นวายอะไรมากระบบก็ใช้ได้อยู่อย่างนั้นแหละ แต่เมื่อติดตั้งระบบใหม่ Ubuntu เวอร์ชันใหม่ Node.js ก็ใหม่ขึ้น NPM และ PM2 ก็อัพเดทตาม แต่วิธีการเก่ากลับใช้ไม่ได้ผล

ข้อความที่เขียนไว้ด้านล่างนี้ตอนนี้ใช้ไม่ได้ เมื่อเรียกผ่าน json ไฟล์แล้ว เวลาเราเข้าไปดูรายละเอียด pm2 จะหยุดรัน process นั้นๆ ทำให้เว็บเข้าไม่ได้ พยายามแก้ไขอยู่นาน หาอ่านหลายๆ เว็บก็ไม่เจอทางออก

สุดท้ายลองใน DigitalOcean บน Node.js Droplets แล้ว ถ้าเรียกผ่าน command line จะใช้ได้ เช่น

pm2 start app.js --watch
เอาเป็นว่าตอนนี้ใช้แบบนี้ไปก่อนก็แล้วกัน แล้วค่อยตามอัพเดทกันต่อไป

-----------------------
เมื่อวานเขียนเกี่ยวกับ nodemon เพื่อรีสตาร์ท node.js application เมื่อมีการแก้ไขซอร์สโค้ด ก็ถือว่าใช้งานได้ดีระดับหนึ่ง แต่พอลองใช้จริงๆ แล้วกลับเจอปัญหา ด้วยคู่มือและตัวอย่างต่างๆ ก็ยังไม่ละเอียด จึงมองหา Node Monitor ตัวอื่นๆ ก็พบโปรแกรมชื่อ PM2 หรือ Process Monitor สำหรับ node.js โดยลองหาข้อมูลเทียบๆ ดูแล้วหลายคนบอกว่าใช้ได้ดี เหมาะสำหรับติดตั้งระบบจริง

ปัญหาของ nodemon ที่พบ คือ ต้องรันคำสั่ง nodemon <appname>.js ที่ working directory เท่านั้น ถ้ารันผ่าน path จะไม่อัพเดท เช่น nodemon /var/xxx/yyy/<appname>.js เมื่อแก้ไขแล้วจะไม่มีการรีสตาร์ทโพรเซส ปัญหาที่สอง ถึงแม้จะรัน nodemon แบบทำงานเบื้องหลังแล้ว เมื่อทิ้งไว้นาน ลองเข้าไปเช็กด้วยคำสั่ง ps -A | grep node กลับไม่มีโพรเซสของ node.js

แต่ใช่ว่า pm2 จะจบเลย พอสั่งรัน app แล้ว แต่ไม่อัพเดทการแก้ไข เมื่อดูจากคำสั่ง pm2 list แล้วพบว่า watching เป็น disabled ถ้าหน้าจอใครไม่เหมือนตัวอย่างด้านล่าง แสดงว่าเป็นเวอร์ชันเก่าให้ติดตั้งเวอร์ชั่นใหม่ล่าสุดด้วยคำสั่ง
npm install pm2@lastest -g
เมื่อติดตั้งเสร็จ watching ก็ยังไม่เริ่มต้นทำงาน ต้องเขียนคำสั่งเพิ่มเติมก่อนที่จะรันแอพพลิเคชันก่อน

root@tms:# pm2 list
┌──────────┬────┬──────┬─────┬─────────┬─────────┬────────┬────────┬──────────┐
│ App name │ id │ mode │ pid │ status  │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼─────┼─────────┼─────────┼────────┼────────┼──────────┤
│ ticket   │ 0  │ fork │ 0   │ errored │ 28      │ 0      │ 0 B    │ disabled │
└──────────┴────┴──────┴─────┴─────────┴─────────┴────────┴────────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app
root@tms:#


ถ้าต้องการดูรายละเอียดการของ pm2 ให้ใช้คำสั่ง pm2 show <app_name> ซึ่งจะมีรายละเอียดไฟล์ log และอื่นๆ ดังตัวอย่างด้านล่าง

root@tms:# pm2 show ticket
Describing process with id 0 - name ticket
┌───────────────────┬───────────────────────────────────────┐
│ status            │ errored                               │
│ name              │ ticket                                │
│ id                │ 0                                     │
│ path              │ /var/ast/public_html/nodejs/ticket.js │
│ args              │                                       │
│ exec cwd          │ /var/ast/public_html/nodejs           │
│ error log path    │ /root/.pm2/logs/ticket-error-0.log    │
│ out log path      │ /root/.pm2/logs/ticket-out-0.log      │
│ pid path          │ /root/.pm2/pids/ticket-0.pid          │
│ mode              │ fork_mode                             │
│ node v8 arguments │                                       │
│ watch & reload    │                                     │
│ interpreter       │ node                                  │
│ restarts          │ 28                                    │
│ unstable restarts │ 0                                     │
│ uptime            │ 0                                     │
│ created at        │ N/A                                   │
└───────────────────┴──────────── ──────────────────────────┘

root@tms:#

จากนั้นให้เขียนไฟล์ <app_name>.json เอาไว้ที่ใดที่หนึ่งที่ต้องการจะสั่งรัน เช่น หน้าหลักของ user หรือ /root ก็ได้ ตัวอย่างผู้เขียนไว้ที่ home ของ user เป็น inet999 และใช้ชื่อ ticket.json มีรายละเอียดภายในดังนี้
{  "apps": [{    "name": "ticket",    "script": "/var/www/ast/public_html/ticket.js",    "log_file": "/var/log/pm2/ticket.log",    "error_file": "/var/log/pm2/ticket-err.log",    "watch": true,    "ignore_watch": ["files"]  }]}
ที่สำคัญที่สุดคือ สองบรรทัดตัวอักษรสีแดง ที่จะสั่งให้ pm2 เฝ้าดูไฟล์สคริปส์ที่กำหนดไว้ข้างบน จากนั้นก็สั่งรันด้วยคำสั่ง

root@tms:/home/inet999# pm2 start ticket.json
เมื่อเรียบร้อยจะได้ข้อความแสดงรายละเอียดของ App และ pid ดังนี้

[PM2] restartProcessId process id 0
[PM2] restartProcessId process id 1
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid   │ status │ restart │ uptime │ memory      │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
ticket   │ 0  │ fork │ 28359 │ online │ 14      │ 0s     │ 19.859 MB   │  enabled
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app
root@tms:/home/inet99#


เมื่อเรียบร้อยแล้วลองแก้ไขไฟล์สคริปส์แล้ว และรันคำสั่ง pm2 list จะเห็นหมายเลข pid เปลี่ยนแปลงไปเรื่อยๆ จากนั้นลอง ก็ไปกำหนดให้รัน pm2 ทุกครั้งที่มีการรีสตาร์ทเครื่องเซิร์ฟเวอร์ด้วยคำสั่ง

root@tms:~/.pm2/logs# pm2 startup ubuntu
โดยระบบจะสร้างไฟล์เพื่อเปิดโปรแกรม pm2 หลังจากรีสตาร์ทเครื่องดังนี้

[PM2] Generating system init script in /etc/init.d/pm2-init.sh
[PM2] Making script booting at startup...
[PM2] -ubuntu- Using the command:
      su -c "chmod +x /etc/init.d/pm2-init.sh && update-rc.d pm2-init.sh defaults"
 Adding system startup for /etc/init.d/pm2-init.sh ...
   /etc/rc0.d/K20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc1.d/K20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc6.d/K20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc2.d/S20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc3.d/S20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc4.d/S20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc5.d/S20pm2-init.sh -> ../init.d/pm2-init.sh
[PM2] Done.
root@tms:~/.pm2/logs#


และหากต้องการยกเลิกโพรเซสของ pm2 เพื่อที่จะเริ่มต้นใหม่สามารถใช้คำสั่ง 
pm2 kill
สุดท้ายทดสอบด้วยการสั่ง restart เครื่องอีกครั้งหนึ่ง และเข้าไปดูโพรเซส ก็จะเห็นมี node ทำงานอยู่แล้ว และใช้คำสั่ง pm2 list ก็จะเห็นรายละเอียดการเฝ้าติดตามอยู่ (ต้องล็อกอินให้ถูกตามชื่อผู้ใช้งานที่สั่งรัน pm2 ด้วย)

จากไฟล์ ticket.json จะกำหนดไฟล์ log ไว้ใน /var/log/pm2/ticket-0.log ซึ่งเป็นไฟล์ที่เก็บข้อมูลที่ส่งออกมาจาก node.js เราสามารถดูรายละเอียดด้วยคำสั่ง cat หรือ tail -f ก็ได้

ลองดูนะครับ หากมีข้อคิดเห็น ข้อเสนอแนะ หรือมีสิ่งใดผิดพลาดรบกวนช่วยชี้แนะด้วยครับ...

Thursday, August 6, 2015

Auto restart node daemon: รีสตาร์ทเมื่อแก้ไขซอร์สโค้ด#1

Node.js เป็นเทคโนโลยีที่ยังใหม่อยู่ในขณะนี้ (6/8/2015) และยังเป็นเซิร์ฟเวอร์ที่ต้องรันเซอร์วิสของ node.js เมื่อมีการเปลี่ยนแปลงซอร์สโค้ดทุกครั้งต้องปิดเซอร์วิสแล้วค่อยเปิดใหม่

ปกติแล้วการรันในเซิร์ฟเวอร์หรือในเครื่องทั่วไปก็ไม่มีปัญหามากนัก เพียงแค่รีโมทเข้าไปปิด-เปิดใหม่ก็ใช้ได้แล้ว เพราะไม่ค่อยได้อัพเดทกันบ่อยๆ

แต่สำหรับคนที่ทำระบบโดยไม่เข้าถึง Shell โดยตรงแล้วจะยากสำหรับการเข้าไปปิด-เปิด หรือ รีสตาร์ทเซอร์วิส แต่อย่างไรก็ตามใช่ว่าจะไร้หนทางเสียทีเดียวเมื่อมีคนเขียนโปรแกรมไว้รองรับเรียกว่า nodemon การติดตั้งก็ง่ายแสนง่ายรันผ่าน npm ได้เลย

npm install -g nodemon 

และการใช้งานก็เรียกแทน node.js ได้เลย
nodemon <app.js> 

คุณสมบัติของ nodemon

  • รีสตาร์ทโปรแกรมแบบอัตโนมัติเมื่อเปลี่ยนแปลงซอร์สโค้ด
  • ตรวจสอบไฟล์นามสกุลที่มอนิเตอร์อัตโนมัติ
  • สนับสนุน node และ coffeescript 
  • เฝ้าดูไดเรคทอรี่ที่ระบุ
  • เป็น Opensorce ดาวน์โหลดฟรีที่ github

การแก้ไขปัญหา

สำหรับคนที่ใช้ ubuntu เมื่อรัน node แล้วจะไม่พบไฟล์ ระบบจะแนะนำให้ติดตั้งโปรแกรมอื่นๆ ที่คาดว่าจะมีโปรแกรม node แต่ถ้ารัน nodejs จะสามารถใช้งานได้เช่นกัน ซึ่งบางคนติดรูปแบบการเรียน node มากกว่า มีวิธีแก้ไขโดยสร้างลิงค์ไฟล์ใหม่ คือ
sudo ln -s /usr/bin/nodejs /usr/local/bin/node
เพียงแค่นี้ก็จะเรียกใช้คำสั่ง node ได้แล้ว

เมื่อมีการแก้ไขที่หน้าจอ Console (ถ้ายังไม่ยกเลิกออกไปเสียก่อน) จะมีข้อความ
7 Aug 00:34:10 - [nodemon] restarting due to changes...
7 Aug 00:34:10 - [nodemon] starting `node ticket.js`
server start app onready
และเมื่อดูจากโพรเซสจะเห็นตัวเลขเปลี่ยนไป
14890 pts/0    00:00:00 node
15075 pts/0    00:00:00 node
root@tms:# nano ticket.js
root@tms:# ps -A | grep node
14890 pts/0    00:00:00 node
15183 pts/0    00:00:00 node
root@tms:# nano ticket.js
root@tms:# ps -A | grep node
14890 pts/0    00:00:00 node
15227 pts/0    00:00:00 node
root@tms:# nano ticket.js
root@tms:# ps -A | grep node
14890 pts/0    00:00:00 node
15283 pts/0    00:00:00 node

เท่าที่ทดสอบแล้ว nodemon ถือว่าเป็นโปรแกรมที่ช่วยอำนวยความสะดวกให้กับนักพัฒนาสาย JavaScripts ได้เป็นอย่างดี ไม่ต้องรีโมทบ่อยครั้ง เพียงแค่อัพโหลดไฟล์ผ่าน ftp ไปยังเซิร์ฟเวอร์ที่เหลือเป็นหน้าที่ของ nodemon รับช่วงต่อไป แต่อย่างไรก็ตาม หากอัพโหลดแล้วหากระบบไม่ทำงาน ให้ลองตรวจสอบคำสั่งอีกครั้งหนึ่ง บางครั้งคำสั่งที่แก้ไขนั่นแหละไม่ทำงาน เช่น ใช้คำสั่ง alert ในฝั่งเซิร์ฟเวอร์ซึ่งไม่สามารถใช้งานได้ เพราะฟังค์ชัน alert ไม่มีในสภาพแวดล้อมของ node.js แต่สามารถสั่งรันในฝั่ง client ได้ 

ปกติหากแก้ไขครั้งหนึ่งสั่งรัน node daemon กันครั้งหนึ่งก็ไม่มีปัญหาเพราะหากมีความผิดพลาดอะไรก็จะแสดงออกมาให้เห็นทันที แต่กรณีใช้ nodemon เราก็มองไม่เห็นเพราะอยู่บนฝั่งเซิร์ฟเวอร์ ดังนั้นควรที่จะตรวจสอบและระมัดระวังสักนิด...



Sunday, March 15, 2015

การเรียกใช้ Server ของ Node.js

การเขียนโปรแกรมบน Node.js ก่อนอื่นเราต้องเข้าใจโครงสร้าง และหลักการก่อน โดยเริ่มจากการเรียกใช้และสร้างเว็บเซิร์ฟเวอร์แบบง่ายๆ เพื่อให้เข้าใจเสียก่อน

แบบที่ 1
var http = require('http');
var express = require('express');
var app = express();

var server = http.createServer(app);
server.listen(port);

แบบที่ 2
เหมือนแบบแรก โดยแทนค่าที่ server

var http = require('http');
var express = require('express');
var app = express();

//var server = http.createServer(app);
http.createServer(app).listen(port);


แบบที่ 3
แบบง่ายๆ 
var express = require('express');
var app = express();
...
// Start server
app.listen(3030);

การสร้าง Route
หลังจากที่ทำให้เว็บเซิร์ฟเวอร์ทำงานได้แล้วก็ต้องสร้าง route เพื่อเรียกไปยังส่วนต่างๆ เช่น

app.js
var express = require('express');
var app = express();

app.get('/', function(req, res, next){
    res.send("Index page");
});

app.get('/about', function(req, res, next){
    res.send('About page');
});

app.listen(3030, function(err){
    console.log('Listening http://localhost:3030');
});

การเรียกใช้งาน
node app.js

 ตัวอย่างหน้าจอที่เรียกใช้งาน


app.get('/', function(...){...});

app.get('/about', function(...){...});

Friday, March 13, 2015

เก็บไฟล์ css ไว้ที่ไหน

เป็นคำถามง่ายๆ สำหรับมือใหม่ เพราะลองสร้างไฟล์ css แล้วเอาไปเก็บไว้ที่ไหนๆ ก็ใช้ไม่ได้สักที ไม่ว่า / หรือ /views หรือ /router พยายามค้นหาใน google ก็หายากพอควร อ่านไปอ่านมาเจอข้อมูลว่า

Node js จะแยกเก็บไฟล์ไว้ใน /public เพื่อให้สามารถเรียกถึงโดยตรงได้ 
ถ้าเก็บไว้ที่อื่นการเรียกถึงจะกลายเป็น route สำหรับเข้าถึงเว็บเพจ ซึ่งระบบของ Node.js จะแปลงเป็นการรับข้อมูลแบบ get ทันที ตามตัวอย่างในรูป


กำหนดให้เรียกในพาธปัจจุบันที่เรียกใช้ในที่นี้จะเป็น ./custom_style.css

แต่ผลที่ได้กลายเป็นการเรียกข้อมูลแบบ get

หลังจากที่นำไฟล์ css ไปไว้ในโฟลเดอร์ /public/stylesheet แล้วเรียกใช้ใหม่อีกครั้งก็ใช้ได้เลย นี่เป็นเส้นผมบังภูเขาดีๆ นี่เอง แต่ก็นำมาบันทึกไว้ที่นี้ เผื่อว่าใครจะเจอปัญหาเดียวกันครับ...




Friday, March 6, 2015

กำหนดรูปแบบวันที่ด้วย momentjs

การเขียน JavaScript เรื่องวันที่เวลาไม่ใช่เรื่องยากสามารถเขียนเป็นฟังค์ชันได้ แต่สำหรับ Node.js แล้วไม่ต้องเขียนฟังค์ชันด้วยตนเอง สามารถติดตั้งและนำมาใช้งานได้ง่าย ด้วยคำสั่ง

npm install moment
หลังจากนั้นก็เข้าสู่ขั้นตอนการเรียกใช้โดยเพิ่มในหน้าจอที่เรียก app

var express = require('express');
var app = express();
 
// Set template path and render engine, not necessary.
app.locals.moment = require('moment'); 

 แค่นี้ก็สามารถนำเอาฟังค์ชัน moment() ไปใช้งานได้ทุกหน้า jade template แล้ว ตัวอย่างเช่น

extends layout
extends index
block append content
  p Append from main.jade (3, append)
  span= 'Date: '+moment(Date.now()).format('DD-MM-YYYY')

block prepend content
  p Prepend from main (4, prepend)


ผลการรันตัวอย่างนี้


สำหรับ momentjs ยังฟังค์ชันในการจัดการวันที่อีกมาก สามารถเข้าไปดูในเว็บ momentjs.com และต่อไปจะหาวิธีนำเสนอการใช้งานอื่นๆ อีกหลายประการ...

ใช้งาน jQuery จาก jade tamplate

jQuery เป็น Library ของ JavaScript เป็นตัวช่วยทำให้รูปแบบของเว็บเพจสวยงามขึ้น โดยปกติแล้วการสั่งให้หน้าเว็บแสดงผลอย่างสวยงามหรือมีลูกเล่นต่างๆ นั้นต้องเขียนคำสั่ง เขียนฟังค์ชันเป็นจำนวนมาก แต่ด้วยหลักการ OOP ทำให้สามารถนำเอาฟังค์ชันต่างๆ มาใช้งานซ้ำได้อย่างมีประสิทธิภาพ

การเขียน template ผ่าน jade นั้นก็สามารถแทรก jQuery เข้าไปได้ ตามตัวอย่างนี้

html
head
  script(src="/javascripts/jquery-1.8.2.js")
  script
    $("#rollButton").click(function() {
       alert("sas");
    });
body
  input#rollButton(type="button", value="Roll")

แต่ถ้าต้องการเรียก script จากเว็บเลยก็เปลี่ยนเป็น

script(src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js")

แค่นี้แหละครับ ส่วนรายละเอียดปลีกย่อยอื่นๆ สามารถศึกษาจากเว็บไซต์ทั่วไปได้

---------

ที่มา:
http://stackoverflow.com/questions/12665666/jade-button-and-jquery-click-event

Template Inheritance ใน jade template

การสืบทอดคุณสมบัติต่างๆ เป็นวิธีการเขียนโปรแกรมแบบบ Object Oriented ซึ่งทำให้สามารถเขียนโปรแกรมได้รวดเร็ว เพราะสร้างโมดูล หรืองานขึ้นมาชิ้นหนึ่งสามารถนำมาเวียนใช้ได้อีกหลายครั้ง และทำให้เกิดรูปแบบมาตรฐานเดียวกัน

ตัวอย่างง่ายๆ ที่ใช้กันในอดีต ก็คือ เว็บเพจจะแบ่งเป็น ส่วนหัว (Header), ส่วนเนื้อหา (Content) และส่วนท้ายหน้า (Footer) ซึ่งเนื้อหาจะเปลี่ยนหรือแสดงผลในส่วน Content แต่ Header และ Footer จะไม่ค่อยเปลี่ยนแปลง (อาจจะมีเปลี่ยนแปลงบ้าง) โดยแต่ละหน้าจะต้องเหมือนกันถึงจะเกิดความสวยงาม

ใน jade ก็เช่นกัน สามารถสืบทอดจากหน้าอื่นมาไว้ในหน้าของงานใดๆ ก็ได้ และมีวิธีการที่ไม่ซับซ้อน สามารถทำความเข้าใจได้ง่ายๆ

ก่อนอื่นที่จะเริ่มไปเขียนงานที่ซับซ้อนเราต้องเข้าใจโครงสร้างของ template เสียก่อน จะทำให้งานง่ายขึ้นและแก้ไข เพิ่มเติมได้ง่ายขึ้นตามไปด้วย

ตัวอย่างที่จะพูดถึงวันนี้ประกอบด้วย ไฟล์ layout.jade, index.jade และ main.jade


  • layout.jade จะเป็นไฟล์โครงสร้างเริ่มต้นของระบบ
  • index.jade เป็นหน้าหลักของ / จะเรียกใช้งาน layout.jade ผ่านคำสั่ง extends layout
  • maint.jade เป็นอีกหน้าหนึ่ง /main จะเรียกใช้งาน layout.jade ผ่าน index.jade อีกครั้งหนึ่ง โดยจะเรียกด้วยคำสั่ง extends layout และ extends index ตามลำดับ
ภายใน layout จะกำหนดโครงสร้างไว้เป็น block เช่น block header, block script, block content และ block footer การใช้งาน block ในไฟล์ jade อื่นๆ จะมี 3 แบบ คือ Replace, Append และ Prepend

Replace 
การเรียกใช้ Block แบบ Replace จะแทนที่ข้อมูลใน Block เดิมด้วย ข้อมูลในที่เรียกใช้งานล่าสุด เช่น

layout.jade

...
block content
    p Content from layout.jade
...

index.jade

extends layout
block content
    p Content from index.jade

เมื่อสั่งรันเว็บเพจแล้วหน้าจอจะแสดงข้อความ Content from index.jade เพราะเป็นการเรียกแบบ Replace


Append
การเรียกแบบ Append จะไปต่อท้าย Block ที่เรียก เช่น

index.jade

extends layout
block append content
    p Content from index.jade

เมื่อสั่งรันหน้าเว็บแล้วจะมีข้อความสองบรรทัด คือ 

Content from layout.jade 
Content from index.jade

Prepend
การเรียกแบบเพิ่มในบรรทัดแรกของ Block

index.jade

extends layout
block prepend content
    p Content from index.jade

เมื่อสั่งรันเว็บเพจจะได้ข้อความสองบรรทัดกลับกันกับ append คือ


Content from index.jade 
Content from replace.jade



หน้าจอการเรียกใช้ block แบบต่างๆ


หน้าจอที่ได้จาก index.jade (2) โดยเรียก layout.jade (1) ตอนเริ่มต้น



หน้าจอ main.jade (3, 4) เรียกใช้ layout.jade (1) และ index.jade (2) ในตอนแรกของไฟล์



อธิบายเพิ่มเติมการเรียกจากส่วนต่างๆ ตามลำดับตัวเลขในวงเล็บ


รายละเอียดใน View source page ทำให้มองเห็นลำดับได้ง่ายขึ้น


จากข้อมูลและรูปภาพข้างบนจะเห็นได้ว่า jade template นั้นง่ายต่อการใช้งาน และเรียกใช้จากเว็บอื่นๆ ได้ง่ายตามไปด้วย


ตัวอย่าง Source code:

app.js
var express = require('express'); 
var app = express(); 
// Set template path and render engine, not necessary.
app.set('views', __dirname + '/views');
 
app.set('view engine', 'jade'); 
app.locals.pretty = true; 
app.get('/', function(req, res) { 
  res.render('index.jade');}); 
  app.get('/main', function(req, res){ 
  res.render('main.jade'); 
}); 
// Start server 
app.listen(3030);

layout.jade
!!!html 
head 
  block stylesheet 
  block script      
      script <!-- script from layout.jade (1) -->  
body    
  block content 
  h1 Hello from layout.jade (1)


index.jade
extends layout 
block stylesheet 
  <!-- Overwrite to block stylesheet (2) -->  
  link(href='bootstrap.min.css' rel='stylesheet') 
block prepend script  
  script <!-- prepend to [block script](2) --> 
block append content   
  h2 Hello from index.jade (2, append)

main.jade
extends layout 
extends index 
block append content  
  p Append from main.jade (3, append) 
block prepend content 
  p Prepend from main (4, prepend)


--------------------

อ้างอิง:
สามารถเข้าไปดูตัวอย่างได้ที่:
http://runnable.com/Umoh1jpWr_o6ABKm/extends-and-blocks-in-jade-for-node-js

ทำ View Source ให้สวยงามใน Node.js

การพัฒนาเว็บไซต์ย่อมหนีไม่พ้นเรื่องการจัดหน้า source code ให้สวยงาม เพื่อตรวจสอบดูได้ง่าย แต่หลายคนมักจะไม่ค่อยสนใจ source ของ html ที่เป็นเอ้าท์พุท เพราะปกติก็ดูแต่ source code ที่เป็นภาษาสำหรับพัฒนาโปรแกรม

แต่อันที่จริงแล้ว source code ของเว็บเพจ เป็นตัวช่วยให้เราสามารถค้นหาสิ่งผิดปกติ หรือช่วยพัฒนาให้โปรแกรมดีขึ้นได้ ขึ้นอยู่กับว่าจะใช้หรือเปล่า


หน้าจอ View Source ที่ยังไม่ได้จัดเรียงใหม่ ทำให้ดูยาก


หน้าจอ View Source ที่จัดเรียงใหม่แล้ว ทำให้สามารถตรวจสอบได้ง่าย


สำหรับ Node.js เป็น Platform ของ JavaScript ที่ทำให้เป็น Web Application ทำงานผ่าน Chrome JavaScript Runtime โดยมี Express เป็น Web Application Framework ช่วยลดการเขียนโค้ดโปรแกรมได้เป็นอย่างมาก



Node.js 


Express



ที่ขาดไม่ได้ คือ Jade ซึ่งเป็นตัวกลางในการเขียนโค้ด HTML ให้ง่าย กระทัดรัดไม่รกรุงรังเหมือนการเขียน HTML โดยตรง จริงๆ แล้วยังมี ejs อีกตัวหนึ่งที่เป็น html template แต่จะเขียนแบบ html ซึ่งต่างจาก jade โดย jade นั้นจะใช้ Indent เป็นตัวแยกหมวดหมู่ ซึ่งต้องระมัดระวังพอควร แต่อย่างไรก็ตาม jade จะแสดงความผิดพลาดออกทางหน้าจอให้สามารถแก้ไขได้ง่ายๆ
jade-language

EJS, JavaScript Template

การจัดการ Source Code ให้อ่านง่ายๆ นั้นไม่ได้ทำอะไรยุ่งยากเลย เพียงแต่เพิ่มคำสั่งเข้าไปใน Express เพียงบรรทัดเดียวหรือคำสั่งเดียว คือ

app.locals.pretty = true;
โดย app นั้นเป็น object ของ Express

var express = require('express'); 
... 
var app = express(); 
...
app.locals.pretty = true;

ง่ายๆ แค่นี้แหละก็ทำให้การแก้ไขโปรแกรมทำได้ง่ายๆ ไม่ยุ่งยากแล้วครับ...

Wednesday, March 4, 2015

ข้อความเตือน จาก Jade, Warning: missing space before text

ตอนนี้ยังไม่แน่ใจว่ามีเครื่องมือตัวไหนดีที่สุดเพราะลองใช้เพียง jade เท่านั้น ความรู้สึกตอนนี้ถือว่าใช้ได้ดีเลยที่เดียว เพราะเขียนง่าย แก้ไข เพิ่ม และดูได้ง่ายกว่าดูใน html คงเพราะลบแท็กออกไปก็ช่วยให้สบายตามากขึ้น

jade ถือว่าเป็น indent format การเขียนใช้การเว้นวรรคเป็นตัวกำหนดรูปแบบ ซึ่งถือว่าสำคัญเลยทีเดียว
เพราะ jade ยอมรับการเว้นวรรคทั้ง spacebar หรือ tab แต่จะใช้เพียงอย่างใดอย่างหนึ่งทั้งไฟล์ จะผสมกันไม่ได้

แต่กระนั้นก็ไม่ต้องกังวล เพราะถ้าเผลอใช้เมื่อใด เมื่อรันไฟล์ jade ก็จะมีข้อความบอก และบอกด้วยว่า บรรทัดไหนที่มีปัญหา


จากรูปนี้ผู้เขียนลองเปลี่ยนจาก tab ให้เป็น space ดังในรูปด้านล่าง



ในบรรทัดที่ 34 จะมีทั้ง tab (ขีดยาว) และ space (จุด 4 จุด)

นอกจากนี้ jade ยังรายงานผลการเตือนที่ไม่มีผลกระทบมากต่อระบบไปที่ console ที่รันโปรแกรมครั้งแรก (npm start)

โดยที่ console มีคำเตือน

Warning: missing space before text for line 50 of jade file "/Users/yothinin/ex/views/addcategories.jade"

เมื่อไปดูในบรรทัดที่ 50 จะพบว่ามี tab อยู่หลัง input ด้วย เมื่อลบออกคำเตือนก็หายไป


นี่แหละคือ ข้อควรระวังเวลาเขียนไฟล์ jade ซึ่งต้องเคร่งครัดเรื่องระเบียบการเขียนเป็นอย่างมาก ไม่เหมือน html ที่เขียนวางไว้ตรงไหน เยื้องอย่างไร จะ tab หรือ space จะเพิ่มมากหรือน้อยอย่างไรก็ได้ ทำให้ไฟล์ html ค่อนข้างเละเทะ ไม่เป็นระเบียบ (สำหรับบางคน)



ใช้ pool mysql แล้วหน้าจอค้าง

หลังจากที่พอจะรู้เรื่อง Node.js, Express และ Jade บ้างแล้ว ก็เริ่มลงมือทำอะไรเล่นๆ เพื่อฝึกซ้อมฝีมือ ยิ่งใช้ไปยิ่งหลงรัก jade พอสมควร เพราะช่วยลดขยะ html ลงได้เยอะมาก ดูเรียบร้อยเป็นสัตว์ส่วนแก้ไขก็ง่าย แต่ยังไม่ได้ลอง คือ ใช้งาน jQuery ร่วมกับ jade คงต้องผ่านขั้นตอนของ ลองใช้งานฐานข้อมูลไปก่อน

การติดต่อผ่าน MySQL ทำได้หลายวิธี แต่สำหรับการติดต่อแบบ Multi Used เป็นการติดต่อฐานข้อมูลเพียงครั้งเดียวแล้วสามารถเรียกใช้งานได้หลายครั้งไม่ต้องติดต่อฐานข้อมูลบ่อยๆ

ตัวอย่าง

  var mysql =  require('mysql');                  
  var pool =  mysql.createPool({
 host : “hostName”,
 user : “username”,
 password: “password”
  }); 


การเรียกใช้งาน:

pool.getConnection(function(err, connection){
  connection.query( “select * from table1”,  function(err, rows){
   if(err) {
    throw err;
   }else{
    console.log( rows );
   }
  });
  
  connection.release();
});


ปัญหา:
เมื่อใช้ไปสักพักแล้วเกิดอาการหน้าจอค้าง เหมือนกำลังทำงานอยู่ เมื่อตรวจสอบไปที่ MySQL แล้วพบว่ามี process ค้างอยู่เป็นจำนวนมาก ตามที่ส่งเขาไป

แก้ไขปัญหา:
ปัญหาข้างต้นยังแก้ไม่ได้ แต่ลองเปลี่ยนวิธีการใช้งาน pool ผ่าน mysql-pool

ติดตั้ง:

npm install mysql-pool
npm install mysql@0.9.6 (แก้ไข Error ในเวอร์ชันใหม่)

เรียกใช้งาน:

var MySQLPool = require("mysql-pool").MySQLPool;
var pool = new MySQLPool({
  poolSize: 4,
  user:     'root',
  password: 'root',
  database: 'test'
});


pool.query("SELECT 'Hello, World!' AS hello", function(err, rows, fields) {
  if(err) throw err;
  console.log(rows[0].hello);
});

ตอนนี้ลองใช้งานดูแล้วยังไม่พบปัญหาของหน้าจอค้าง แต่ยังไม่มีเวลาลงลึกว่าเป็นเพราะเหตุใด โดยแบบหลังจะกำหนด poolSize = 4 ซึ่งอาจจะมีส่วนเกี่ยวข้อง เพราะแบบแรกก็มีออฟชันกำหนดตัวหนึ่งคือ

var connection =  mysql.createConnection( { multipleStatements: true } );
อีกสักพักจะได้ลองกลับมาทดสอบอีกครั้งหนึ่ง ตอนนี้ขอเดินหน้าไปก่อนครับ...

ข้อมูล:
https://github.com/Kijewski/node-mysql-pool
http://stackoverflow.com/questions/14070188/getting-error-while-running-node-mysql-tutorial
http://www.thegeekstuff.com/2014/01/mysql-nodejs-intro/