템플레이팅(Templating) 은 주로 웹 개발에서 사용되는 기법으로, 동적인 콘텐츠를 생성할 때 미리 정의된 형식(템플릿)을 이용하는 것이다.
템플릿은 HTML, XML, JSON 등 다양한 형식으로 작성될 수 있으며, 주로 데이터와 템플릿의 결합을 통해 최종 결과물을 만든다.
Express는 여러 템플릿 엔진을 지원하며, 가장 일반적으로 사용되는 것들은 EJS, Pug(구 Jade), Handlebars 등이 있다.
동적 데이터 처리 : 데이터에 따라 다양한 콘텐츠를 쉽게 생성할 수 있다.
가독성 : HTML 코드와 데이터가 분리되어 있어 코드가 더 깔끔해진다.
재사용성 : 동일한 템플릿을 다양한 데이터와 함께 재사용할 수 있다.
npm install express ejs
const express = require('express');
const app = express();
// 템플릿 엔진 설정
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.set('view engine',engine): 사용할 템플릿 엔진을 지정한다. 위의 예에서는 EJS를 사용한다.
app.set('views', path): 템플릿 파일이 위치한 디렉터리를 지정한다.
__dirname 은 Node.js에서 사용되는 전역 변수로, 현재 실행 중인 스크립트 파일의 디렉터리 경로이다.
path 모듈
app.set('views', __dirname + '/views');부분은 path 모듈을 사용하여
app.set('views', path.join(__dirname,'/views'))로 바꿀 수 있다.
const express = require('express');
const app = express();
// EJS 템플릿 엔진 설정
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.get('/', (req, res) => {
const title = '홈페이지';
const message = '안녕하세요, EJS를 사용한 페이지입니다!';
res.render('index', { title, message }); // 'index.ejs' 파일 렌더링
});
app.listen(3000, () => {
console.log('서버가 3000번 포트에서 실행 중입니다.');
});
<%= %> (HTML 이스케이프 처리)<%= %> 은 JavaScript 표현식을 평가하고 결과를 HTML로 출력한다. 이 때, HTML 이스케이프가 적용되어 HTML 태그가 있는 경우에는 태그가 안전하게 출력된다. HTML 태그 적용 X
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>사용자 페이지</title>
</head>
<body>
<h1>안녕하세요, <%= user.name %>님!</h1>
</body>
</html>
<%- %> (HTML 이스케이프 해제)<%- %> 은 JavaScript 표현식을 평가하고 결과를 HTML로 출력한다. 이 경우, HTML 이스케이프가 적용되지 않으므로 HTML 태그가 그대로 해석된다. HTML 태그 적용 O
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>아이템 목록</title>
</head>
<body>
<h2>구매한 아이템:</h2>
<ul>
<%- itemsHTML %>
</ul>
</body>
</html>
만약 itemsHTML의 값이 <li>사과</li><li>바나나</li><li>체리</li>라면, 출력 결과는:
<ul>
<li>사과</li>
<li>바나나</li>
<li>체리</li>
</ul>
<% %> (avaScript 코드를 삽입 및 실행)<% %> 구문은 JavaScript 코드를 실행하기 위해 사용되며, HTML로 출력되지 않는다.
이 구문을 통해 조건문, 반복문 등을 작성하여 동적인 콘텐츠를 생성할 수 있다.
<ul>
<% users.forEach(function(user) { %>
<li><%= user.name %></li>
<% }); %>
</ul>
세 구문의 차이
<%= %>: HTML 이스케이프 처리된 값을 출력 (안전한 출력 이므로 태그 해석 X)
<%- %>: HTML 이스케이프 해제된 값을 출력 (태그 해석)
<% %>: JavaScript 코드를 실행 (HTML로 출력 없음)
Express.js에서 정적 assets는 HTML, CSS, JavaScript 파일, 이미지, 폰트 등과 같이 서버에서 직접 제공하는 파일들을 의미한다. 이러한 정적 파일들은 클라이언트가 요청할 때 서버가 직접 응답하여 브라우저에 표시된다.
const express = require('express');
const path = require('path');
const app = express();
// 정적 파일을 제공할 폴더 설정
app.use(express.static(path.join(__dirname, 'public')));
├── public
│ ├── css
│ │ └── styles.css
│ ├── js
│ │ └── script.js
│ ├── images
│ │ └── logo.png
│ └── index.html
└── server.js
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>정적 Assets 활용</title>
<link rel="stylesheet" href="/css/styles.css"> <!-- CSS 파일 -->
</head>
<body>
<header>
<img src="/images/logo.png" alt="로고"> <!-- 이미지 파일 -->
<h1>안녕하세요, EJS와 정적 파일!</h1>
</header>
<p>이 페이지는 EJS 템플릿을 사용하고 있습니다.</p>
<script src="/js/script.js"></script> <!-- JavaScript 파일 -->
</body>
</html>
/public을 경로에 붙이지 않는 이유
/public을 경로에 붙이지 않는 이유는 Express.js에서 express.static 미들웨어를 사용하여 public 폴더를 정적 파일의 기본 제공 경로로 설정했기 때문이다.
Javascript, CSS, Image 등 웹 서비스에서 사용하기 위해 미리 서버에 저장해 놓은 파일이다.
파일 자체가 고정되어 있고, 서비스 중에도 추가되거나 변경되지 않는다.
우리가 페이지를 만들 때 쓰임이 정해져있는 파일들이기 때문에 개발하는 단계에서 이러한 파일들을 관리한다.
외부 환경에 관계 없이 일정한 결과값을 제공해주는 걸 의미한다.
정적 Assets은 동적 경로 설정(직접 파일의 경로를 지정)을 할 때보다 경로가 간결 하고 관리가 용이하며, 성능과 보안 측면에서 유리하다.
낮은 처리 비용: 정적 파일은 서버에서 직접 파일을 읽고 전송하는 간단한 작업이다. 동적 파일은 데이터베이스 쿼리, 템플릿 렌더링 등 복잡한 처리가 필요하여 서버 자원을 더 많이 소모한다.CPU 사용 감소: 정적 파일은 서버가 계산이나 로직을 수행할 필요가 없기 때문에 CPU 사용량이 적다.빠른 전송: 정적 파일은 미리 생성되어 있기 때문에 클라이언트 요청에 대해 즉시 응답할 수 있다. 동적 페이지는 처리 시간이 필요해 상대적으로 느리다.캐싱: 브라우저와 CDN은 정적 파일을 캐싱할 수 있다. 이렇게 하면 동일한 파일을 요청할 때 서버에 다시 요청할 필요가 없어져 응답 속도가 빨라진다.코드 노출 최소화: 정적 파일은 서버의 로직이나 데이터베이스에 접근할 필요가 없어 보안이 강화된다. 사용자가 요청할 수 있는 파일만 노출되므로 잠재적인 공격 면이 줄어든다.정적 검증 가능: 정적 파일은 사전에 검토되고 배포되기 때문에, 배포 시 코드 오류나 취약점을 쉽게 점검할 수 있다.EJS 파일 분할은 대규모 애플리케이션에서 코드의 재사용성과 유지 관리를 향상시키기 위해 템플릿을 여러 파일로 나누는 방법이다.
이를 통해 각 파일의 책임을 명확히 하고, 가독성을 높이며, 코드 중복을 줄일 수 있다.
my-app/
├── views/
│ ├── partials/
│ │ ├── header.ejs
│ │ ├── footer.ejs
│ │ └── sidebar.ejs
│ └── pages/
│ ├── index.ejs
│ └── about.ejs
│
└── server.js
주 템플릿 파일로, 다른 템플릿을 포함할 기본 구조를 정의합니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title><%= title %></title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<%- include('partials/header'); %> <!-- 헤더 포함 -->
<div class="container">
<%- body; %> <!-- 페이지별 콘텐츠 -->
</div>
<%- include('partials/footer'); %> <!-- 푸터 포함 -->
</body>
</html>
헤더 부분을 별도로 정의합니다.
<header>
<h1>내 웹사이트</h1>
<nav>
<ul>
<li><a href="/">홈</a></li>
<li><a href="/about">소개</a></li>
</ul>
</nav>
</header>
푸터 부분을 정의합니다.
<footer>
<p>© 2024 내 웹사이트. 모든 권리 보유.</p>
</footer>
EJS를 설정하고 요청을 처리합니다.
const express = require('express');
const path = require('path');
const app = express();
// EJS 설정
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.get('/', (req, res) => {
res.render('pages/index', { title: '홈페이지', body: '<h2>홈페이지 내용</h2>' });
});
app.get('/about', (req, res) => {
res.render('pages/about', { title: '소개', body: '<h2>소개 페이지 내용</h2>' });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`서버가 ${PORT}번 포트에서 실행 중입니다.`);
});