Templatte Engine ทำให้เราสามารถใช้งาน ไฟล์ template ใน Application
ของเราได้ หลักการทำงาน คือ ตัว template engine จะทำการแทนค่าตัวแปรต่างๆ
ลงไปในไฟล์ template จากนั้นแปลง template ให้อยู่ในรูปแบบ HTML ไฟล์ แล้วส่งกลับ
มาแสดงยังผู้ใช้ ซึ่งทำให้การออกแบบหน้าตาของเพจ ทำได้ง่ายขึ้น
ใน Express มี template engine หลักๆ ได้แก่ Pug, Mustache, และก็ EJS ซึ่งเราจะใช้เป็น
ตัว EJS เนื่องจากมีรูปแบบการใช้งานเที่ง่าย เรียนรู้และจดจำไม่ยาก เพราะเป็นการใช้งาน JS ปกติทั่วไป
ร่วมกับ HTML ไฟล์ หรือไฟล์ template คล้ายๆ กับเราเขียนโค้ด PHP แทรกเข้าไปในไฟล์ HTML แต่ถ้าใคร
สนใจใช้งาน template engine ตัวอื่นๆ ก็สามารถเลือกใช้งานได้ตามต้องการ
ติดตั้ง EJS ใน Express
การใช้งาน Template Engine ใน Express ไม่ว่าจะเป็นตัวใดๆ ก็ตาม รวมถึง EJS ด้วย เราต้องทำการกำหนด
การตั้งค่า Application Property โดยใช้คำสั่ง app.set() ในไฟล์ app.js ก่อน ดังนี้
ค่า "views" เป็นการกำหนดโฟลเดอร์ที่เราเก็บไฟล์ template ต่างๆ ไว้ ปกตินิยมใช้ชื่อโฟลเดอร์ว่า "views"
โดยกำหนดการตั้งค่าเป็นดังนี้
app.set('views', './views')
แต่การใช้งานจริง ควรกำหนดร่วมกับการใช้งาน Path Module ซึ่งจะใช้เป็น
app.set('views', path.join(__dirname, 'views'));
ค่า "view engine" เป็นการกำหนด template engine ที่จะใช้งาน เช่นในที่เราจะใช้ EJS ก็กำหนดเป็น
app.set('view engine', 'ejs');
หลังจากตั้งค่าการใช้งาน template engine ร่วมกับ Express เรียบร้อยแล้ว ต่อไป ก็ให้เราทำการติดตั้ง template
npm install ejs --save
เท่านี้ เราก็พร้อมเรียกใช้งาน template engine ใน Express app ของเราได้แล้ว
ก่อนไปหัวข้อต่อไป มาทำความรู้จัก กับการใช้งานคำสั่ง app.set() เพิ่มเติม
คำสั่ง app.set() เป็นคำสั่งที่ใช้กำหนดค่า ให้กับชื่อที่ต้องการ โดยจะเป็นค่าอะไรก็ได้ แต่มีบางชื่อที่เป็นชื่อสำหรับ
ใช้ในการกำหนดการตั้งค่าให้กับ app ตารางชื่้อที่ใช้กำหนดค่าใน app ดูได้ที่ Application settings
ในการตั้งค่าให้กับค่า boolean ที่เป็น true หรือ false นอกจากเราสามารถใช้ app.set() แล้ว เรายังสามารถใช้คำสั่ง
app.enable() และ app.disable() แทนได้ ยกตัวอย่างเช่น
app.set('foo', true) // สามารถใช้คำสั่ง app.enable('foo') app.set('foo', fasle) // สามารถใข้คำสั่ง app.disable('foo')
สำหรับการใช้งานค่า ที่ได้กำหนดไว้ สามารถใช้คำสั่ง app.get() ตามตัวอย่างดังนี้
app.set('title', 'My Site'); // กำหนดค่า app.get('title'); // ดึงค่ามาใช้ ก็จะได้ค่า title = "My Site"
ในการกำหนดค่าให้กับ application setting มีข้อควรจำ กรณีนำค่าไปใช้ใน sub app หรือ app ย่อย เช่น การใช้งาน
ในก router โดย การสืบทอด หรือส่งต่อค่าต่างๆ ที่กำหนด จะเป็นไปลักษณะดังนี้ คือ
- สำหรับค่าใดๆ ที่มีการกำหนดค่าเริ่มต้นไว้ เราต้องกำหนด การตั้งค่าใน sub app ใหม่ทุกครั้ง เพราะจะไม่มีการส่งต่อค่า
ที่เรากำหนด เช่น "view engine" ไม่มีค่าเริ่มต้น หากเรากำหนดค่าให้กับส่วนนี้ในไฟล์ app.js ก็จะมีผล ให้ใน sub app
อย่าง router ก็สามารถใช้งานค่าดังกล่าวๆได้ เลย โดยไม่ต้องกำหนดค่าใหม่
- สำหรับค่าใดๆ ที่ไม่มีการกำหนดค่าเริ่มต้นไว้ หากเรากำหนดค่านั้นในไฟล์ app.js จะมีผล sub app ย่อย เราไม่ต้องกำหนด
ค่าใหม่ทุกครั้ง หากต้องการใช้งาน แต่ถ้า ต้องการให้ค่าแตกต่างไปตามแต่ละ sub app ก็สามารถกำหนดค่าใหม่ให้กับ sub
app นั้น ตามค่าที่ต้องการได้
ข้อยกเว้น: จะมี "trust proxy" ที่ ถึงมีค่าเริ่มต้น แต่ถ้ากำหนดค่าใหม่ ก็จะส่งค่าต่อไปยัง sub app
และมี "view cache" ที่ มีค่าเริ่มต้น แต่มีผลต่อ sub app เฉพาะกรณีมีการกำหนด "NODE_ENV"
เท่ากับ "production"
สามารถดูเพิ่มเติม ที่ Application Settings
การใช้งาน EJS ใน Express
เรามาดูโครงสร้างไฟล์ และโฟลเดอร์ของเรา ก่อนกำหนดการใช้งานกับ EJS เป็นโครงสร้างโฟลเดอร์ในโปรเจ็คคร่าวๆ
ที่สัมพันธ์กับเนื้อหาที่ผ่านๆ มา
เรามี public โฟลเดอร์ ที่ใช้เก็บ static ไฟล์ต่างๆ มีไฟล์ app.js ไฟล์หลักสำหรับรัน web app เริ่มต้น หลักๆ ก็จะประมาณนี้
สิ่งที่เราจะเพิ่มเข้ามาอีก 2 ส่วนในการพัฒนาก็คือ
1. ส่วนของโฟลเดอร์ routes สำหรับเก็บ sub app หรือก็คือเก็บ router ที่เป็น mini-app ย่อยต่างๆ เปรียบเสมือนหน้าเพจ
ที่ทำงานต่างๆ กันไป ยกตัวอย่าง หน้า users เป็นต้น
2. ส่วนของโฟลเดอร์ views สำหรับเก็บไฟล์ template ซึ่งในที่นี้ เราใช้เป็น EJS ไฟล์ template จริงๆ แล้วก็คือไฟล์ที่มีรูป
แบบโค้ดด้านในเป็น HTML เสียส่วนใหญ่ แต่จะมีการแทรกส่วนของ EJS หรือที่เป็นรูปแบบในลักษณะคล้าย JavaScript แทรกเข้าไป
และไฟล์นั้นๆ จะใช้นามสกุลเป็น ejs สมมติเช่น ไฟล์ template ของหน้า users ก็อาจจะใช้เป็น users.ejs เป็นต้น
ด้านล่างคือไฟล์ app.js ของเราสำหรับเริ่มต้นโปรเจ็คการใช้งาน EJS
const express = require('express') // ใช้งาน module express const app = express() // สร้างตัวแปร app เป็น instance ของ express const path = require('path') // เรียกใช้งาน path module const port = 3000 // port // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); app.use(express.json()) app.use(express.urlencoded({ extended: false })) app.use(express.static(path.join(__dirname, 'public'))) // ส่งกลับข้อความ "hello world" เมื่อมี GET request มายังหน้า homepage app.get('/', function (req, res) { res.send('hello world ') }) app.listen(port, function() { console.log(`Example app listening on port ${port}!`) })
จะเห็นว่า ถ้ารัน app เมื่อเข้ามาหน้าแรก จะเป็นการแสดงคำว่า "hello world" เราจะเปลี่ยนการใช้งานตรงนี้
โดยสร้างหน้าแรกเป็น sub app ชื่อว่า indexRouter แทน พร้อมทั้งเรียกใช้งานให้แสดงหน้าแรกด้วย template engine
EJS ดังนั้น สิ่งที่เราต้องสร้างเพิ่มเข้ามาคือไฟล์ index.js ใน routers โฟลเดอร์ เป็น router module สำหรับกำหนดการ
ทำงานในหน้าแรก และ ก็สร้าง index.ejs ใน views โฟลเดอร์ เป็น template ไฟล์ จะได้โครงสร้างไฟล์ พร้อมตัวอย่าง
template หน้า index.ejs เป็นดังนี้
<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='css/mycss.css' /> </head> <body> <h1><%= title %></h1> <p>Welcome to <%= title %></p> </body> </html>
ในไฟล์ index.ejs ข้างต้น เราจะเห็นรูปแบบการแสดงค่าตัวแปร ใน EJS template โดยใช้รูปแบบ
<%= [ชื่อตัวแปร] %> // ข้างต้นก็คือ <%= title %>
ถูกนำไปใช้แสดงใน 3 ส่วนคือ <title>, <h1> และ <p>
รูปแบบการใช้งาน <% และ %> ก็คล้ายๆ กับคำสั่งเปิดปิด แท็ก PHP ด้านในคือรูปแบบคำสั่งในลักษณะ JavaScript
อย่างไรก็ตาม ก่อนที่เราจะไปต่อ จะขอเปลี่ยนการใช้งานจากเครื่องหมาย <% และ %> เป็น <? และ ?> ทั้งนี้ก็เพราะว่า
หากเราพิมพ์ในแป้น keyborad เครื่องหมาย % จะอยู่ห่างจาก < และ > ทำให้เวลาเราพิมพ์กำหนดคำสั่งจะไม่สะดวก
จึงใช้ความสามารถของ EJS ที่เรากำหนดการใช้งานส่วนนี้เองได้ ซึ่งเดียวเราจะไปตั้งค่าเพิ่มเติมในไฟล์ app.js ในลำดับต่อไป
ก็จะได้เป็น
<html> <head> <title><?= title ?></title> <link rel='stylesheet' href='css/mycss.css' /> </head> <body> <h1><?= title ?></h1> <p>Welcome to <?= title ?></p> </body> </html>
ต่อด้วยไฟล์ index.js ที่เป็น sub app หรือ mini-app ย่อยของหน้าแรก เรากำหนดโค้ดเป็นดังนี้
const express = require('express') const router = express.Router() // เมื่้อเข้ามาที่หน้าแรก path: "/". router.get('/', function(req, res, next) { res.render('index', { title: 'Express' }) }) module.exports = router
เมื่อข้ามาที่ route: "/" ซึ่งเป็นหน้าแรก เราใช้คำสั่ง res.render() เพื่อแปลงข้อมูลจากไฟล์ template ให้อยู่ในรูปแบบ
HTML แล้วส่งกลับไปแสดง คำสั่ง res.render('[ชื่อไฟล์ template ไม่ต้องระบุนามสกุลไฟล์]) มาดูรูปแบบกัน
res.render('index', { title: 'Express' });
ส่วนของชื่อไฟล์ template ก็คือ index ซึ่งเป็นชื่้อไฟล์ที่อยู่ในโฟลเดอร์ "views" เหตุที่เราไม่ระบุชื่อโฟลเดอร์ไปด้วยก็เพราะ
ว่าเราได้กำหนดการตั้งค่า ในตอนต้นไปแล้วในไฟล์ app.js เช่นเดียวกัน กับที่เราไม่ต้องระบุนามสกุลไฟล์ นอกจากนั้น
ในการ render เราก็ได้ทำการส่งค่าตัวแปร objext เข้าไปใน template ซึ่งเราได้เห็นการนำค่าไปแสดงแล้วในไฟล์ index.ejs
title คือ object property ที่ถูกส่งเข้าไป
{ title: 'Express' }
หรือเราจะกำหนดเป็นตัวแปร แล้วค่อยเรียกใช้ก็ได้ เช่น
// เมื่้อเข้ามาที่หน้าแรก path: "/". router.get('/', function(req, res, next) { var data = { title: 'Express' } res.render('index', data) })
สุดท้ายส่วนของ app.js อย่างที่ได้บอกไป เรามีการใช้งาน "?" แทน "%" ใน EJS ดังนั้่นเราต้องกำหนด option เพิ่มเติม
ให้กับ "view" โดยใช้คำสั่ง
app.set('view options', {delimiter: '?'});
ดูแนวทางการกำหนดค่าเพิ่มเติมได้ที่ Using EJS with Express
จะได้ไฟล์ app.js ที่เรียกใช้งานหน้าแรกผ่าน router และมีการใช้งานร่วมกับ EJS ดังนี้
const express = require('express') // ใช้งาน module express const app = express() // สร้างตัวแปร app เป็น instance ของ express const path = require('path') // เรียกใช้งาน path module const port = 3000 // port // ส่วนของการใช้งาน router module ต่างๆ const indexRouter = require('./routes/index') // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); app.set('view options', {delimiter: '?'}); app.use(express.json()) app.use(express.urlencoded({ extended: false })) app.use(express.static(path.join(__dirname, 'public'))) // เรียกใช้งาน indexRouter app.use('/', indexRouter) app.listen(port, function() { console.log(`Example app listening on port ${port}!`) })
ทดสอบการทำงาน จะได้ผลลัพธ์เป็นดังนี้
คำสั่ง และการใช้งาน EJS เบื้องต้น
รูปแบบคำสั่ง EJS
หรือเรียกอีกอย่างว่า EJS “tag” มีรูปแบบการกำหนดเบื้องต้นเป็นดังนี้ คือ
<starting content closing>
ช่องว่างระหว่าง ส่วนริ่มต้นคำสั่งกับเนื้อหา และส่วนกับเนื้อหากับส่วนปิดคำสั่ง ไม่จำเป็นต้องมีก็ได้ แต่ด้วยเหตุผลสำหรับ
ให้สามารถอ่านโค้ดได้ง่ายขึ้น ช่องว่างจึงถูกนำมาใช้ ตัวอย่าง เช่น <%=title%> ก็เท่ากับ <%= title %>
แต่แบบหลังอ่านง่ายกว่า จึงนิยมมีช่องว่าง เมื่อเปิดเ และก่อนปิดคำสั่งเสมอ
Delimiters (อักขระตัวคั่น)
อย่างที่เราเห็นรูปแบบเบื้องต้นมาแล้ว จะเห็นว่าตัวคั่น ที่กำหนดใน EJS "tag" จะใช้ "%" แต่เราสามารถใช้เป็นตัวอื่นแทนได้
เพื่อให้การใช้งานคำสั่ง ทำได้ง่ายและสะดวกขึ้น อย่างในที่นี้เราจะใช้ "?" แทน ยกตัวอย่างจากโค้ดที่ผ่านมา
<?= title ?>
Starting tags (ส่วนเปิดคำสั่ง EJS)
จะประกอบด้วย 4 รูปแบบ ดังนี้
<?=: Escaped output
ใช้แสดงข้อมูล โดยมีการแปลงสัญลักษณะที่อยู่ในรูป HTML เป็น ตัวอักขระเฉพาะ เช่น
ตัวอย่างด้านล่าง
ตัวแปร data object
{ "name": "Timoth<y>" }
EJS
<p>Hello, <?= name ?>.</p> <p>Hello, <?= 'the Most Honorable ' + name ?>.</p>
HTML
<p>Hello, Timoth<y>.</p> <p>Hello, the Most Honorable Timoth<y>.</p>
ตัว < และ > ถูกแปลงเป็น < และ > ตามลำดับ ทั้งนี้ก็เพื่อไม่ให้ถูกตีความเป็น HTML tag
<?-: Unescaped output
ใช้แสดงข้อมูล ที่รองรับการแสดงข้อมูลที่เป็น HTML ในกรณีที่เราต้องการแสดงข้อมูลนั้น ในรูปแบบ HTML
จึงไม่จำเป็นที่ต้องแปลงตัวอักขระนั้นๆ เหมือนในกรณีแรก อย่างไรก็ตาม เราต้องมั่นใจหรือรับรู้อย่างชัดเจนว่า
ข้อมูลนั้นๆ จะต้องเป็นข้อมูลที่ปลอดภัย เพื่อป้องกันการโจมตีในรูปแบบ cross-site scripting (XSS) ในลักษณะ
เป็น script คำสั่งอย่าง JavaScript เช่น <script>alert('ok');</script> ถ้าคำสั่งหรือข้อมูลนี้ไม่ถูกแปลง ก็จะกลาย
เป็นการรันคำสั่ง แทนการแสดงเป็นข้อความ
ตัวแปร data object
{ "myHtml": "<strong>Timothy</strong>" , "myMaliciousHtml": "</p><script>document.write()</script><p>" }
EJS
<p>Hello, <?- myHtml ?>.</p> <p>Hello, <?= myHtml ?>.</p> <p>Hello, <?- myMaliciousHtml ?>.</p> <p>Hello, <?= myMaliciousHtml ?>.</p>
HTML
<p>Hello, <strong>Timothy</strong>.</p> <p>Hello, <strong>Timothy</strong>.</p> <p>Hello, </p><script>document.write()</script><p>.</p> <p>Hello, </p><script>document.write()</script><p>.</p>
จะเห็นว่า การเปรียบเทียบของทั้งสองรูปแบบที่ใช้งาน <?- ?> และ <?= ?> ให้ผลลัพธ์แตกต่างกัน
และแบบ <?- ?> จะมีความเสี่ยงกรณี ข้อมูลนั้นๆ เป็น script คำสั่งที่ไม่ปลอดภัย ดังนั้น ในการจะใช้งาน
เราต้องรู้แหล่งที่มาของข้อมูลนั้นๆ อย่างเช่น เป็นข้อมูลที่ใครก็ได้ ส่งเข้ามา แล้ว เราแสดงในลักษณะดังกล่าวา
ก็เสี่ยงที่จะถูกโจมตีในรูปแบบ (XSS) แต่ถ้าเป็นข้อมูลที่เรากำหนดเอง เป็นตัวแปรที่เรากำหนด ก็มั่นใจได้ว่าเราสามารถ
ใช้งานการแสดงในรูปแบบดังกล่าวได้ ไม่มีปํญหา
<?#: Comments
ใช้สำหรับกำหนด comment โดยข้อความในส่วนนี้จะไม่มีผลในการทำงานหรือในการแปลงไปเป็น HTML
แต่จะทำให้เกิดช่องว่าง ขึ้นในส่วนของ HTML ซึ่งเราสามารถให้ไม่แสดงหรือตัดการแสดงช่องว่างได้ โดยการปิด
ด้วยคำสั่ง -?> ดูตัวอย่าง โค้ดด่านล่างประกอบ
EJS
<div> <?# comment ?> </div> <div> <?# comment -?> </div>
HTML
<div> </div> <div> </div>
<?: Scriptlet
ใช้สำหรับแทรกโค้ดต่างๆ ลงไปใน EJS template โดยสามารถกำหนดโค้ดด้านในเป็น JavaScript หรือ จะใช้ EJS
ร่วมกับ JavaScript ก็ได้
การใช้งาน JavaScript Comments
เราสามารถใช้ comment ใน javascript ใน ส่วนนี้ได้
<?# comment ?> <?/* comment */?> <?// comment ?>
การใช้งานเครื่องหมาย { }
เราควรใช้งาน เครื่องหมายปีกาเปิด/ปิด ทุกๆ ครั้งที่ใช้งานในการกำหนดเงื่อนไข หรือลูป
<?# Bad practice ?> <? if (true) ?> <p>Yay it's true!</p> <?# Good practice ?> <? if (true) { ?> <p>Yay it's true!</p> <? } ?>
การขึ้นบรรทัดใหม่
เราสามารถทำการขึ้นบรรทัดใหม่ หรือทำคำสั่งในบรรทัดใหม่ได้
<? var stringToShow = thisIsABooleanVariableWithAVeryLongName ? 'OK' : 'not OK' ?>
การใช้งานเครื่องหมาย (;)
เช่นเดียวกับใน JavaScript เราไม่จำเป็นต้องกำหนดเครื่อง semicolon (;) เมื่อสิ้นสุดคำสั่งในบรรทัดนั้น
แต่ถ้าต้องการใช้งาน เพื่อแสดงถึงการจบบรรทัด ก็สามารถใช้งานได้
การจัดการกับช่องว่าง
ในการใช้คำสั่ง <? อาจจะมีบางกรณีที่ทำให้เกิดช่องว่าง เราสามารถตัดช่องว่าง ที่อาจจะเกิดขึ้นเหล่านี้ด้วยคำสั่งดังนี้
- ปิดด้วยคำสั่ง -?>
- เปิดด้วยคำสั่ง <?_
<?_: Scriptlet, ลบช่องว่างด้านหน้า
ใช้สำหรับแทรกโค้ดต่างๆ ลงไปใน EJS template เหมือนกับการใช้งาน <? แต่ตัวนี้ จะมีการลบ
ส่วนของช่องว่าง ที่อยู่ด้านหน้าออกไปด้วย ดูตัวอย่าง เปรียบเทียบผลัพธ์
EJS
<ul> <? users.forEach(function(user, i, arr){ -?> <li><?= user ?></li> <? }); -?> </ul> <ul> <?_ users.forEach(function(user, i, arr){ -?> <li><?= user ?></li> <?_ }); -?> </ul>
HTML
<ul> <li>Anne</li> <li>Bob</li> </ul> <ul> <li>Anne</li> <li>Bob</li> </ul>
Ending tags (ส่วนปิดหรือจบชุดคำสั่ง EJS)
จะประกอบด้วย 2 รูปแบบ ดังนี้
?>: Regular ending tag
เป็นรูปแบบมาตรฐานหรือรูปแบบทั่วไปของการปิดชุดคำสั่ง EJS
-?>: Newline-trimming ending tag
เป็นรูปแบบที่ใช้สำหรับตัด บรรทัด ส่วนเกินที่เกิดขึ้นจากการใช้งาน <? หรือจากการใช้งาน comment <?#
Literal tags (การแสดงค่าจริงตัวอักขระ)
การแสดงค่าจริงตามตัวอักขระ โดยไม่ต้องแปลงค่า อย่างสมมติเช่น เราต้องการให้แสดง <? และ ?>
เราต้องกำหนดเป็น <?? และ ??> เพื่อไม่ให้ถูกตีความเป็นรูปแบบคำสั่ง
EJS
<pre>This is literal: <??</pre> <pre>This is literal too: <?? ?></pre> <pre>This is literal as well: ??></pre>
HTML
<pre>This is literal: <?</pre> <pre>This is literal too: <? ?></pre> <pre>This is literal as well: ?></pre>
การ Includes ไฟล์
เราสามารถทำการ Include ไฟล์ ejs โดยใช้คำสั่ง include ยกตัวอย่างเช่น เราต้องการ include ไฟล์
"./views/user/show.ejs" เราก็สามารถใช้เป็น
<?- include('user/show') ?>.
เราต้องระบุชื่อไฟล์เข้าไปในคำสั่ง include โดยไม่ต้องระบุนามสกุลไฟล์ ก็ได้ นอกจากนั้น จะเห็นว่า เรามีการ
ใช้งาน <?- ซึ่งเป็นรูปแบบ แสดงข้อมูลที่รองรับ HTML และ script คำสั่ง
ตัวอย่างการใช้งาน
<ul> <? users.forEach(function(user){ ?> <?- include('user/show', {user: user}) ?> <? }); ?> </ul>
ค่าตัวแปร หรือข้อมูลที่กำหนดใน application-level หรือที่เรียกว่า top-level data object จะสามารถเรียกใช้งานได้
ในทุกๆ ไฟล์ที่ include เว้นแต่เป็นค่าตัวแปร หรือข้อมูลที่กำหนดภายในไฟล์นั้นๆ หากจะใช้งานในไฟล์ include เรา
ต้องทำการส่งค่าเข้าไปด้วย อย่างตัวอย่างโค้ดด้านบน
การใช้งาน Layouts
เราสามารถจัดการ layout โดยการใช้การ include ไฟล์มาช่วย เช่น การกำหนดส่วนของ header หรือ footer
ตัวอย่างการใช้งาน
<?- include('header') -?> <h1> Title </h1> <p> My page </p> <?- include('footer') -?>
ทั้งหมดนี้เป็นแนวทางเบื้องต้น สำหรับการใช้งาน Template Engine ใน Express ซึ่งในที่นี้ใช้งาน EJS
เนื้อหานี้เป็นแนวทางสำหรับทำความเข้าใจ ในส่วนอื่นๆ เพิ่มเติมต่อไป