קבצים סטטיים ותבניות (EJS)

לא כל שרת הוא API שמחזיר JSON. הרבה פעמים צריך להגיש אתר: קובצי HTML, CSS, תמונות, ודפים שנבנים עם נתונים מהשרת. לשני הצרכים האלה יש ב-Express פתרון מובנה.

express.static: להגיש תיקייה שלמה

import express from 'express';
import path from 'node:path';

const app = express();

// כל קובץ בתיקייה public זמין בכתובת לפי שמו
app.use(express.static(path.join(import.meta.dirname, 'public')));

app.listen(3000);
public/
├── index.html        →  http://localhost:3000/
├── css/style.css     →  http://localhost:3000/css/style.css
└── img/logo.png      →  http://localhost:3000/img/logo.png
  • index.html מוגש אוטומטית כשפונים לתיקייה.
  • משתמשים ב-import.meta.dirname כדי שהנתיב יעבוד לא משנה מאיזו תיקייה מריצים את השרת.
  • אפשר קידומת: app.use('/static', express.static('public')) מגיש את public/logo.png ב-/static/logo.png.

מטמון בפרודקשן

app.use(express.static('public', {
    maxAge: '1d',     // הדפדפן שומר את הקבצים יום אחד
    etag: true,
}));

מנוע תבניות: HTML עם נתונים

כשהדף תלוי בנתונים (רשימת מוצרים, פרופיל משתמש), בונים אותו בשרת מתבנית. EJS היא התבנית הפשוטה ביותר, כי היא בעצם HTML עם JavaScript קטן בתוכו:

npm install ejs
app.set('view engine', 'ejs');
app.set('views', path.join(import.meta.dirname, 'views'));

app.get('/products', async (req, res) => {
    const products = await getProducts();
    res.render('products', { title: 'המוצרים שלנו', products });
});
<!-- views/products.ejs -->
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head><title><%= title %></title></head>
<body>
    <h1><%= title %></h1>
    <% if (products.length === 0) { %>
        <p>אין מוצרים כרגע.</p>
    <% } %>
    <ul>
        <% products.forEach((product) => { %>
            <li><%= product.name %> - ₪<%= product.price %></li>
        <% }) %>
    </ul>
</body>
</html>
תגיתמה היא עושה
<%= value %>מדפיסה ערך, עם escaping (בטוח לנתונים ממשתמשים)
<%- html %>מדפיסה HTML גולמי. רק לתוכן שאתם כתבתם, אף פעם לא לקלט של משתמש
<% code %>קוד JavaScript (תנאים, לולאות) בלי הדפסה
<%- include('header') %>משלבת תבנית אחרת (כותרת, תפריט)
אבטחה: <%- עם תוכן שמשתמש הזין פותח פרצת XSS: המשתמש יכול להזריק סקריפט לדף של אחרים. ברירת המחדל היא תמיד <%=.

מתי תבניות ומתי API

  • תבניות בשרת - אתר תוכן, דפי ניהול, מקומות שבהם SEO ומהירות טעינה ראשונה חשובים.
  • API + React בצד הלקוח - אפליקציה אינטראקטיבית. אז Express מחזיר JSON, ו-React בונה את הממשק.

אפשר גם לשלב: Express שמגיש את קובצי ה-build של React דרך express.static, ולצידו נתיבי /api.

דוגמאות מלאות להרצה

  • static.js - הגשת תיקיית public עם HTML, CSS ו-JavaScript
  • template.js - דפי EJS עם רשימת משתמשים ודף משתמש

בדקו את עצמכם

נסו לענות לבד לפני שאתם פותחים את התשובה.

  1. מה ההבדל בין <%= %> ל-<%- %> ב-EJS?

    1. <%= לקוד בלבד
    2. <%= עושה escaping ובטוח לקלט של משתמשים, <%- מדפיס HTML גולמי
    3. אין הבדל
    4. <%- מהיר יותר ובטוח יותר
    הצגת התשובה

    תשובה ב. <%- עם קלט של משתמש פותח פרצת XSS.

  2. מה עושה express.static('public')?

    1. מוחק קבצים
    2. מגיש כל קובץ בתיקייה public בכתובת לפי שמו
    3. מקמפל CSS
    4. יוצר תיקייה
    הצגת התשובה

    תשובה ב. public/css/style.css זמין ב-/css/style.css.