Express EJS shabloni bilan ishlash
Hozirgacha server ikki narsa qaytardi: JSON yoki tayyor statik HTML fayl. Lekin sahifa ma’lumot bilan to’ldirilgan HTML bo’lishi kerak bo’lsa-chi? Vazifalar ro’yxatini serverda tayyorlab, foydalanuvchiga to’liq sahifa yuborish kerak. Shablon aynan shu ish uchun.
Muammo: HTML ni qo’lda yopishtirish
Ma’lumotni HTML ga qo’shishning noto’g’ri yo’li:
// ❌ Bunday yozilmaydi
app.get("/tasks", (request, response) => {
let html = "<h1>Vazifalar</h1><ul>";
for (const task of tasks) {
html = html + "<li>" + task.title + "</li>";
}
html = html + "</ul>";
response.send(html);
});
Uch muammo bor. HTML tuzilishi JavaScript qatorlari orasida yo’qoladi.
Tahrirlash uchun kod ichini kavlash kerak. Eng jiddiysi — task.title
ichida <script> bo’lsa, u brauzerda bajariladi.
Shablon shu uchala muammoni yechadi.
EJS ni ulash
O’rnatamiz:
npm install ejs
Serverga ikki qator qo’shamiz:
const express = require("express");
const path = require("path");
const app = express();
// Shablon dvigatelini tanlaymiz
app.set("view engine", "ejs");
// Shablonlar qaysi papkada turishini aytamiz
app.set("views", path.join(__dirname, "views"));
app.listen(3000, () => {
console.log("Server ishga tushdi: http://localhost:3000");
});
app.set("view engine", "ejs") yozilgandan keyin require("ejs") kerak
emas — Express paketni nomi bo’yicha o’zi topadi.
views papkasini yarating. Loyiha tuzilishi:
express-app/
├── public/
│ └── style.css
├── views/
│ └── tasks.ejs
├── app.js
└── package.json
Birinchi shablon
views/tasks.ejs faylini yarating:
<!DOCTYPE html>
<html lang="uz">
<head>
<meta charset="UTF-8" />
<title><%= pageTitle %></title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<h1><%= pageTitle %></h1>
<p>Jami: <%= tasks.length %> ta vazifa</p>
</body>
</html>
Marshrutda response.render() chaqiriladi:
const tasks = [
{ id: 1, title: "Kitob o'qish", isDone: false },
{ id: 2, title: "Kod yozish", isDone: true },
];
app.get("/tasks", (request, response) => {
// Birinchi argument — fayl nomi (.ejs yozilmaydi)
// Ikkinchi argument — shablonga uzatiladigan ma'lumot
response.render("tasks", {
pageTitle: "Vazifalar ro'yxati",
tasks: tasks,
});
});
Brauzerda http://localhost:3000/tasks ni oching:
Vazifalar ro'yxati
Jami: 2 ta vazifa
response.render() uch ish qiladi: views papkasidan tasks.ejs ni
topadi, uzatilgan obyekt kalitlarini shablonga o’zgaruvchi sifatida
beradi va tayyor HTML ni yuboradi.
Ikki teg — eng muhim farq
EJS da qiymat chiqaradigan ikki teg bor. Ular o’xshash ko’rinadi, lekin farqi juda jiddiy.
| Teg | Nima qiladi |
|---|---|
<%= qiymat %> |
Qiymatni ekranlab chiqaradi |
<%- qiymat %> |
Qiymatni xom HTML sifatida chiqaradi |
Farqni misolda ko’ramiz. Aytaylik, foydalanuvchi vazifa sarlavhasiga shunday matn yozdi:
<script>alert("Saytingiz buzildi")</script>
Bu matn <%= task.title %> bilan chiqarilsa, brauzerda aynan shu qator
matn sifatida ko’rinadi — hech narsa bajarilmaydi. Sahifa manbasida
esa ekranlangan shakli turadi:
<script>alert("Saytingiz buzildi")</script>
Xuddi shu matn <%- task.title %> bilan chiqarilsa, brauzer uni haqiqiy
<script> tegi deb qabul qiladi va kodni ishga tushiradi.
Yodda saqlash uchun qisqa qoida: tenglik belgisi (=) xavfsiz, chiziq
(-) xavfli.
Sikl va shart
EJS ichida to’liq JavaScript ishlaydi. Buning uchun <% %> — tengliksiz
teg ishlatiladi. U kod bajaradi, lekin hech narsa chiqarmaydi.
views/tasks.ejs ni to’ldiramiz:
<!DOCTYPE html>
<html lang="uz">
<head>
<meta charset="UTF-8" />
<title><%= pageTitle %></title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<h1><%= pageTitle %></h1>
<% if (tasks.length === 0) { %>
<p>Hozircha vazifa yo'q.</p>
<% } else { %>
<ul>
<% for (const task of tasks) { %>
<li>
<%= task.title %>
<% if (task.isDone) { %>
<strong>(bajarildi)</strong>
<% } %>
</li>
<% } %>
</ul>
<% } %>
</body>
</html>
Brauzerda:
Vazifalar ro'yxati
• Kitob o'qish
• Kod yozish (bajarildi)
Uch teg turini ajratib oling:
| Teg | Vazifa | Misol |
|---|---|---|
<%= %> |
Qiymat chiqaradi, ekranlaydi | <%= task.title %> |
<%- %> |
Qiymat chiqaradi, ekranlamaydi | Ishonchli HTML uchun |
<% %> |
Kod bajaradi, chiqarmaydi | <% if (...) { %> |
include bilan takrorni yo’qotish
Har sahifada <head>, menyu va futer takrorlanadi. EJS ularni alohida
faylga chiqarish imkonini beradi.
views/partials papkasini yaratib, ichiga ikki fayl qo’ying.
views/partials/header.ejs:
<!DOCTYPE html>
<html lang="uz">
<head>
<meta charset="UTF-8" />
<title><%= pageTitle %></title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<nav>
<a href="/tasks">Vazifalar</a>
<a href="/about">Biz haqimizda</a>
</nav>
views/partials/footer.ejs:
<footer>
<p>Vazifalar ilovasi</p>
</footer>
</body>
</html>
Endi views/tasks.ejs qisqaradi:
<%- include("partials/header") %>
<h1><%= pageTitle %></h1>
<ul>
<% for (const task of tasks) { %>
<li><%= task.title %></li>
<% } %>
</ul>
<%- include("partials/footer") %>
Yangi sahifa qo’shish endi oson:
app.get("/about", (request, response) => {
response.render("about", { pageTitle: "Biz haqimizda" });
});
views/about.ejs:
<%- include("partials/header") %>
<h1><%= pageTitle %></h1>
<p>Bu ilova Express va EJS bilan yozilgan.</p>
<%- include("partials/footer") %>
Menyuni o’zgartirish kerak bo’lsa, header.ejs ni bir marta
tahrirlaysiz — hamma sahifada yangilanadi.
Shablon va API — ikkalasi birga
Bitta ilovada ikki xil javob yashay oladi:
// Brauzer uchun — HTML sahifa
app.get("/tasks", (request, response) => {
response.render("tasks", { pageTitle: "Vazifalar ro'yxati", tasks: tasks });
});
// Dastur uchun — JSON
app.get("/api/tasks", (request, response) => {
response.json(tasks);
});
Farqni ajrating: /tasks ni odam brauzerda ochadi, /api/tasks ga esa
boshqa dastur yoki fetch murojaat qiladi.
| Javob turi | Kim uchun | Metod |
|---|---|---|
| HTML sahifa | Brauzerdagi foydalanuvchi | response.render() |
| JSON | Frontend kodi, mobil ilova | response.json() |
Server sahifani tayyorlab yuborishi CSR, SSR va SSG darsida tasvirlangan usullardan biri.
Amaliy mashq
express-app loyihasida davom eting:
ejsni o’rnatib,app.set("view engine", "ejs")vaviewsyo’lini sozlang;views/tasks.ejsyaratib,pageTitleni<%= %>bilan chiqaring;forsikli bilan vazifalarni ro’yxat qilib chiqaring va bajarilganiga(bajarildi)qo’shing;- Massivga sarlavhasi
<b>Qalin</b>bo’lgan vazifa qo’shing va uni<%= %>bilan chiqaring — teg matn bo’lib ko’rinishini tasdiqlang; - Xuddi shu qiymatni vaqtincha
<%- %>ga o’zgartirib, matn qalin bo’lib qolishini ko’ring, so’ng darhol<%= %>ga qaytaring; partials/header.ejsvapartials/footer.ejsyaratib, ikki sahifadaincludebilan ulang.
4 va 5-qadam birga eng muhimi: ikki tegning farqini o’z ko’zingiz bilan
ko’rasiz. Sinovda <b> tegi ishlatilgani bejiz emas — u zararsiz, lekin
farqni aniq ko’rsatadi.
Qisqacha xulosa
- Shablon — o’rinbosarlari ma’lumot bilan to’ldiriladigan HTML fayl.
- EJS ikki qator bilan ulanadi:
app.set("view engine", "ejs")vaapp.set("views", ...). response.render("tasks", { ... })shablonni topadi, to’ldiradi va yuboradi; kengaytma yozilmaydi.<%= %>ekranlaydi va xavfsiz,<%- %>xom HTML beradi va foydalanuvchi ma’lumoti uchun xavfli.- Ekranlanmagan foydalanuvchi matni XSS hujumiga yo’l ochadi.
<% %>tegi kod bajaradi:ifvaforshu bilan yoziladi.includetakrorlanadigan bo’laklarni bir joyga yig’adi va bitta ilova ham HTML sahifa, ham JSON qaytara oladi.
Keyingi darsda yakuniy loyiha — CRUD API, shablon va statik fayllarni bitta ishlaydigan ilovaga birlashtiramiz.