EJS는 Embedded JavaScript Template의 약어로 템플릿 엔진 모듈입니다. 템플릿 엔진 모듈은 서버에서 DB 혹은 API에서 가져온 데이터를 미리 정의된 Template에 넣고, html을 그려서 클라이언트에 전달해주는 역할을 합니다. 즉, ejs는 Template에 javascript 내용을 끼워넣어 정적인 html 파일로 변환해주는 역할을 수행하게 됩니다. 기존 html도 javascript를 끼워넣을 수 있지 않냐고 반문할 수 있습니다. 하지만 기존의 경우 html과 script가 script 태그로 분리되어 있어 script를 html에 적용하기에 어려움이 있었습니다. 반면에 ejs는 html의 태그처럼 자바스크립트 내용을 삽입할 수 있습니다. 이 강점을 이용해 페이지를 동적으로 짜는 것이 기존보다 훨씬 수월해집니다. 또한, 서버에서 보낸 변수를 가져와 사용할 수 있기 때문에 ejs 같은 템플릿 엔진을 사용합니다.
다음의 명령어로 ejs를 설치합니다.
$ npm install ejs
express에는 템플릿을 render 할 수 있도록 도와주는 View Engine이라는 것을 제공합니다. express가 실행되는 index.js
에 view engine을 다음과 같이 설정하면 됩니다.
// index.js
const app = express();
app.set('view engine', 'ejs'); //view engine이 사용할 Template Engine
app.set('views', path.join(__dirname, 'views')); // Template가 있는 디렉토리
위와 같이 작성하면, ejs 확장자를 가진 template를 사용하고, 해당 template는 /views
에 존재한다고 설정됩니다.
해당 template를 render하려면 다음과 같이 작성하면 됩니다.
app.get('/', function (req, res) {
res.render('index', { name: '홍길동', message: 'Hello World'});
})
위와 같이 설정하면 /로 시작하는 모든 요청에 대해 index.ejs
를 render 한다는 의미입니다. ejs 확장자가 생략된 이유는 위에서 app.set('view engine', 'ejs');
로 view engine을 설정했기 때문입니다. 이 부분이 없다면 ejs 확장자를 적어야 합니다. { name: '홍길동', message: 'Hello World'}
는 index.ejs
에 전달되는 변수입니다.
ejs는 html과 동일한 구조를 가지고 있고, 다음의 태그를 사용하여 javascript 코드를 삽입할 수 있습니다. (참고: ejs docs )
<%
'Scriptlet' tag, for control-flow, no output
<%=
Outputs the value into the template (HTML escaped)
<%-
Outputs the unescaped value into the template
<!-- index.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1><%=name %></h1>
</body>
</html>
공식 문서에 들어가보면 위의 태그 이외의 것들이 있지만, 주로 사용하는 것만 소개하도록 하겠습니다.
<%=
, <%-
으로 시작하는 구문은, escape를 해주는 지 여부만 다를 뿐 둘 다 내용물을 있는 출력해 주는 역할을 합니다. 차이점은 좀 있다 살펴보도록 하고 우선, 공통적으로 어떻게 출력이 되는지부터 확인하겠습니다.
다음과 같이 입력하면 문자열을 화면에 출력할 수 있습니다.
<%= "Hello World" %> // Hello World
간단한 연산도 가능합니다.
<%= "Hello " + "World"%> // Hello World
<%= 10 - 2 %> // 8
삼항 연산자도 사용 가능합니다.
<%= true ? "참" : "거짓"%> // 참
<%= false ? "참" : "거짓"%> // 거짓
두 태그의 차이는 escape 여부입니다. escape 한다는 것은 html문에서 사용하는 특정 문자열들을 단순한 문자열로서 출력한다는 의미입니다. 예제를 통해 살펴보도록 하겠습니다.
<%= "<h3>escaped</h3>" %>
<%- "<h3>unescaped</h3>" %>
위와 같이 입력하면 어떻게 출력이 될까요? 결과물을 살펴보면 다음처럼 나옵니다.
<%=
의 경우, escaped하기 때문에 <h3>
태그를 단순 문자열로 출력했습니다. 반면에, <%-
의 경우에는 unescaped하기 때문에 <h3>
태그를 적용하게 됩니다. 이러한 차이가 있으므로 만약 삼항 연산자로 html element를 출력하고 싶다면 <%-
을 사용하여 구현할 수 있습니다.
<%- true? "<h1>html tag가 적용되어 출력</h1>":"<div>실패</div>"%>
<%
의 경우 Scriptlet tag라 부릅니다. 어떠한 것도 출력하지 않고 제어흐름을 위해서만 사용되는 태그입니다.
<% "Hello World" %> // 출력 안됨
위와 같이 입력하면, 아무것도 출력이 안되는 것을 확인할 수 있을 것입니다. 즉, 해당 태그는 javascript를 사용하여 흐름을 제어하는 데에만 사용됩니다.
다음처럼 변수를 선언할 수 있습니다.
<% let str = "선언된 변수"%>
<%= str %> // 선언된 변수
<%
에서 변수를 선언하고, 해당 변수를 <%=
로 받아서 사용할 수 있습니다.
다음처럼 if문 사용할 수 있습니다.
<% if (true) { %>
<h2>출력됩니다.</h2>
<% } %>
<% if (false) { %>
<h2>출력되지 않습니다.</h2>
<% } %>
위와 같이 입력하면 다음과 같이 결과물이 나오는 것을 확인할 수 있습니다.
<%if(true){ %>
<div>참</div>
<% } else{%>
<div>거짓</div>
<%}%>
위와 같이 입력하면 다음과 같이 결과물이 나오는 것을 확인할 수 있습니다.
다음과 같이 for문이 작성 가능합니다.
<%for(let i=1; i<=3; i++) { %>
<div><a href="/test/<%= i %>">test <%= i %>로</a></div>
<% } %>
위와 같이 입력하면 다음과 같이 결과물이 나오는 것을 확인할 수 있습니다.
다음과 같이 Array.forEach를 사용해서 결과물을 출력할 수 있습니다.
<% let arr = ["1번", "2번", "3번"]%>
<% arr.forEach((val)=>{ %>
<h3><%= val %> 입니다.</h3>
<% }) %>
다음과 같이 Array.map을 사용해서 결과물을 출력할 수도 있습니다.
<% let arr = ["map 1번", "map 2번", "map 3번"]%>
<% arr.map((val)=>{ %>
<h3><%= val %> 입니다.</h3>
<% }) %>
위의 View Engine을 설명하면서 다음과 같이 Route를 설정하였습니다.
app.get('/', function (req, res) {
res.render('index', { name: '홍길동', message: 'Hello World'});
})
여기서 { name: '홍길동', message: 'Hello World'}
는 index.ejs
에 변수로 전달됩니다. 따라서 index.ejs
에서 <%= name %>
, <%= message %>
로 값을 받아 사용할 수 있습니다.
<h3>이름: <%= name %> </h3>
<h3>메시지: <%= message %> </h3>
서버에서 array나 object를 전달받고 for 문을 사용하여 출력할 수도 있습니다.
app.get('/', function (req, res) {
res.render('index', { persons: [
{ name: '홍길동', age: 13 },
{ name: '김영희', age: 16 },
{ name: '김철수', age: 76 }
]});
})
<% persons.map((person)=>{
Object.entries(person).map(obj=>{
%>
<h4><%= obj[0] %>: <%= obj[1] %></h4>
<% })}) %>