About EJS
EJS란?
- EJS는 Embedded JavaScript의 약자로, HTML코드 내에 JavaScript 코드를 삽입하여 사용할 수 있게 해주는 템플릿 엔진임.
- 템플릿 엔진이란, 템플릿을 렌더링하여 HTML을 생성해주는 도구임.
- 이는 PHP 또는 ASP의 작성 방식과 흡사하여, 기존에 웹 개발을 해본 사람이라면 쉽게 접근할 수 있음.
- EJS는 Controller단에서 넘겨준 데이터를 가지고 <% %> 태그를 사용하여 코딩이 가능함.
- <% %> 태그 내에서 간단한 자바스크립트 백엔드 로직(if, while, for, foreach 등)을 작성할 수 있음.
- 단 이는 Client단에서 렌더링 되는 것이 아니라, Server단에서 렌더링 되는 것임.
즉, Client단에서는 자바스크립트 코드가 아닌, 렌더링된 HTML 코드가 보여지게 됨.
EJS의 역사
- EJS는 2010년에 TJ Holowaychuk에 의해 만들어짐.
- 2011년에 TJ Holowaychuk가 Express.js를 만들면서 Express.js의 기본 템플릿 엔진으로 채택됨.
EJS on BE
백엔드에서의 EJS의 다양한 사용 방법
- 보통은 Express나 Koa 등에서 사용한다.
- Express를 기준으로, 코드 내에서 Controller까지 호출된 뒤, 아래와 같이 사용하면 된다.
let people = ['강창훈', '우성우', '추원혁', '한고운', '이환영'];
res.render('../team/blogging.ejs', {people: people});
백엔드에서만 사용할 수 있는 템플릿 엔진?
- EJS는 대표적으로 Express와 같은 풀 스택 프레임워크 등에서 널리 사용된다.
- 그렇다고 해서 이 EJS 코드가 서버 상에서만 작동되어야 하는가? 그렇지 않다.
Client-Side에서도 간단하게 EJS를 사용할 수 있다.
EJS on FE
프론트엔드에서의 EJS의 간단한 사용 방법
- HTML DOM 내에서 ejs.js 라이브러리 파일을 참조해 준다.
- 우선 EJS 문법을 렌더링한다. 렌더링 된 결과를 변수에 담아도 좋다.
- 원하는 Target (QuerySelecter로 선택 가능한 아무 HTML태그)을 지정, 해당 Target에 innerHTML을 사용하여 집어넣는다.
<div id="output"></div>
<script src="ejs.min.js"></script>
<script>
const people = ['강창훈', '우성우', '추원혁', '한고운', '이환영'];
let html = ejs.render('<%= people.join(", "); %>', {people: people});
document.getElementById('output').innerHTML = html;
// 실행결과 : 강창훈, 우성우, 추원혁, 한고운, 이환영 문자열이 #output 태그 내에 삽입된다
</script>
아래는 또 다른 사용방법이다.
- Ajax 또는 Axios를 활용하여 EJS 템플릿 원본을 읽어온 뒤 변수에 담는다.
- 담은 변수를 ejs.render를 통해 렌더링하여 새로운 변수에 담는다.
- 렌더링된 HTML 데이터를 Target DOM 내에 주입한다.
<script src="ejs.js"></script>
<div id="target"></div>
<script>
$.get('template.ejs', function(template) { // template.ejs 파일을 읽어들임
var rendered = ejs.render(template, {name: '추원혁'});
$('#target').html(rendered); // 렌더링된 HTML을 DOM에 주입
});
</script>
About `EXPRESS-EJS-LAYOUTS`
EJS도 PHP처럼 Include와 섹션분리를 통한 재참조가 가능하다..?
1. 백문이 불여일견 일단 따라해본다. Express 프로젝트를 기준으로 설명하겠음.
https://www.npmjs.com/package/express-ejs-layouts
2. 우선 npm을 통해 'express-ejs-layouts' 패키지를 설치해야 한다.
# MAC / Linux
sudo npm i express-ejs-layouts
# Windows
npm i express-ejs-layouts
3. 설치가 완료되면 Express의 app.js 내부에 아래와 같은 코드를 추가한다.
var layout = require("express-ejs-layouts");
// 가급적 app = express() 선언보다 위에 가는게 좋을듯..
// ... 코드 본문 ...
app.use(layout);
// 위에서 선언한 express-ejs-layouts를 use 한다.
app.set("layout", "layout");
// Default Layout은 ./views/layout.ejs 를 참조한다는 뜻
// layout.ejs 내부에 <%- body %> 가 있다면 그곳에 body 내용이 주입된다.
app.set("layout extractScripts", true);
// 컨트롤러에 따라 다르게 호출하는 EJS 파일 내부의 스크립트 태그를 쓸어담아 layout.ejs에 전달한다.
// layout.ejs 에서 <%- script %> 로 불러오면 됨!
app.set("layout extractStyles", true);
// extractScripts와 마찬가지로 style을 extract하여 <%- style %> 로 사용할 수 있음!
app.set("layout extractMetas", true);
// extractScripts와 마찬가지로 Metatag를 extract하여 <%- meta %> 로 사용할 수 있음!
4. 곧바로 써본다.
- layout.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<%- meta %>
<title>ORMCAMP</title>
</head>
<body>
<%- style %>
<h1>안녕하세용</h1>
<%- body %>
<%- script %>
</body>
</html>
- index.ejs
<p>안녕하세용 안녕하세용 ㅋㅋ</p>
<script>console.log('콘솔에서도 안녕하세용');</script>
5. 위와 같은 구성을 갖춘다고 가정할때, index.ejs에 할당된 라우트로 접근하면..
<h1>안녕하세용</h1>
<p>안녕하세용 안녕하세용 ㅋㅋ</p>
<script>console.log('콘솔에서도 안녕하세용');</script>
<!-- layout.ejs의 h1태그와 index.ejs 내의 내용이 원래 하나의 html인것처럼 출력된다. -->
기본적으로 웹 페이지 솔루션을 제작할때에는 header, body, footer 등으로 구분하게된다.
이 경우 body만 그때그때 바꿔주고 header와 footer는 고정적으로 가도록 제작하게 된다.
위와 같은 프로세스에 있어서는 필수적으로 적용되어야 하는 개념이다.
php에서 파일을 나눠 서로 include 하듯 ejs도 layout 설정이 가능하다니.
EJS Essentials
EJS 태그 (%) 의 종류
태그 표기법 | 사용에 따른 용도 |
<% | 'Scriptlet' 태그, 제어 흐름을 위한 것, 출력 없음 |
<%_ | 'Whitespace Slurping' Scriptlet 태그, 그 앞의 모든 공백을 제거 |
<%= | 템플릿에 값을 출력 (HTML 이스케이프, HTML 태그로 인식안됨) |
<%- | 템플릿에 값을 출력 (HTML 이스케이프 없음, 원본 그대로 출력) |
<%# | 주석 태그, 실행 없음, 출력 없음 |
<%% | 리터럴 '<%' 출력 (코드 실행이 아니라 '<%' 출력을 원할때) |
%> | 일반적인 닫는 태그 |
-%> | Trim-mode ('newline slurp') 태그. 다음 줄 바꿈을 제거 (띄어쓰기는 제거하지 않음, 줄 바꿈만 제거) |
_%> | 'Whitespace Slurping' 닫는 태그. 그 뒤의 모든 공백을 제거. (줄 바꿈은 제거하지 않음, 띄어쓰기만 제거) |
상황 별 EJS 문법의 사용 예제
1. Scriptlet - ( <% )
<%
let userName = 'Evans Benedict';
let userAge = 25;
%>
<!-- 실행결과 출력 없음. -->
2. Whitespace Slurping Scriptlet ( <%_ ~ _%> )
<ul>
<%_ let fruits = ['사과', '바나나', '체리']; _%>
<%_ fruits.forEach(function(fruit) { _%>
<li><%= fruit %></li>
<%_ }); _%>
</ul>
<!-- 실행결과
<ul>
<li>사과</li>
<li>바나나</li>
<li>체리</li>
</ul>
-->
3. 값 출력 태그 ( <%= ~ %> )
<% const myName = '추원혁'; %>
<p>안녕하십니까. 제 이름은 <%= myName %> 입니다.</p>
<!-- 실행결과
안녕하십니까. 제 이름은 추원혁 입니다.
-->
4. 원본 값 출력 태그 ( <%- ~ %> )
<%- '<script>alert("안녕하세요")</script>' %>
<!-- 실행결과
<script>alert("안녕하세요")</script>
// 유니코드로 Encode되지 않고 원본 그대로의 값이 전달된다.
// 따라서 HTML 코드 등을 전달하고 싶을때 유용하다.
-->
5. 주석 태그 ( <%# ~ %> )
<%# ㅋㅋ 이건 아무도 못 볼거야 %>
<!-- 실행결과 출력 없음. -->
6. 리터럴 태그 ( <%% ~ %> )
<%% 리터럴 %>
<!-- 실행결과
<% 리터럴 %>
// ejs 문법설명시 외에는 쓸일이 없을것 같다..
-->
7. Trim-mode 태그 ( -%> )
<%
let x = 10;
-%>
x의 값은? <%= x %>
<!-- 실행결과
x의 값은? 10
// 에디터에 의한 줄바꿈을 방지하기 위함인가?
// Textarea 태그 등에서 쓸 일이 있을 것 같다.
-->
Javascript On EJS Template
1) 출력 태그
- 화면 출력
<%= "Hello World" %> // Hello World
-데이터 출력
<% let title = "제목" %>
<%= title %> // 제목
- 연산
<%= "Hello"+"World"%> // Hello World
<%= 10-2 %> // 8
- 삼항 연산자
<%= true ? "참" : "거짓" %> // 참
<%= false ? "참" : "거짓" %> // 거짓
- <%= %>, <%- %>의 차이
escape 여부에 따라 <%= %>는 escape 값 출력, <%- %>는 unescaped 값 출력 됨
escape(탈출) 한다는 것은 html문에서 사용하는 특정 문자열들을 단순한 문자열로서 출력한다는 의미
unescape 한다는 것은 html문에서 사용하는 특정 태그들의 속성을 그대로 받아들여서 출력한다는 의미
<%= "<h3>escaped</h3>" %> // <h3>escaped</h3>
<%- "<h3>unescaped</h3>" %> // unescaped
2) 제어 흐름 태그
<%은 Scriptlet Tag로 출력 없이 제어 흐름을 위해서만 사용되는 태그
<% let str = "문자" %>
<%= str %> // 문자
3) 가정문
- if문
<% if (true) { %>
<h2> 출력하기 </h2>
<% } %>
출력해보기
-if-else 문
<% if (true) {%>
<p2> 참 </p2>
<%} else{%>
<p2>거짓</2>
<%} %>
실행결과 :: 참
실제 사용 예시
<div class="col-sm-4">
<div class="form-group">
<label class="control-label">게시여부</label>
<select name="isDisplayCode" id="isDisplayCode" class="form-control">
<option value="9" <% if(article.is_display_code == "9"){ %> selected <% } %> >선택</option>
<option value="1" <% if(article.is_display_code == "1"){ %> selected <% } %> >게시함</option>
<option value="0" <% if(article.is_display_code == "0"){ %> selected <% } %> >게시안함</option>
</select>
</div>
</div>
4) 반복문
- for 문
<% for(let i=0; i<=3; i++) {%>
<a href="/test/<%= i %>" > 경로 <%= i %>로 이동 </a>
<%}%>
<!-- 실행결과
<a href="/test/0" > 경로 0로 이동 </a>
<a href="/test/1" > 경로 1로 이동 </a>
<a href="/test/2" > 경로 2로 이동 </a>
<a href="/test/3" > 경로 3로 이동 </a>
-->
실제 사용 예시
<tbody class="hoverTblBody">
<% for(var i =0;i<articles.length;i++){ %>
<tr>
<td><%=articles[i].article_id%></td>
<td>
<% if(articles[i].board_type_code ==1){%>
공지게시판
<% } else{ %>
기술블로깅
<% }%>
</td>
<td><a href="/article/modify/<%=articles[i].article_id%>"><%=articles[i].title%></a></td>
<td><%=articles[i].view_count%></td>
<td><%=articles[i].ip_address%></td>
<td>
<% if(articles[i].is_display_code ==1){%>
게시함
<% } else{ %>
게시안함
<% }%>
</td>
<td><%=articles[i].reg_date%></td>
</tr>
<% } %>
</tbody>
EJS 뷰 파일로 데이터 전달하기
1) router 설정에서 변수 받기
index.js에서 설정한 {title:'화이팅입니다.'}는 index.ejs에서 변수로 전달됨
index.js
router.get('/', function(req, res, next) {
res.render('index', { title: '화이팅입니다.' });
});
index.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<p>환영합니다. <%= title %></p>
</body>
</html>
출력화면
객체 전달 하기
.js 파일
router.get('/modify/:aid',async(req,res) =>{
// 1)선택한 게시글 고유번호를 파라메터 방식ㅇ로 URL을 통해 전달 받음
var articleIdx = req.params.aid;
// 2)해당 게시글 번호에 해당하는 특정 단일게시글 정보를 DB article테이블에서 조회해 온다.
var article ={
article_id:1,
board_type_code:1,
title:"공지게시글 1번글입니다.",
contents:"공지게시글 1번 내용입니다.",
view_count:10,
ip_address:"111.111.124.44",
is_display_code:1,
article_type_code:1,
reg_date:"2023-12-12",
reg_member_id:"gowoon"
};
// 3) 단일 게시글 정보를 뷰에 전달
res.render('article/modify', {article});
});
ejs 파일
<!-- 글내용 입력영역 -->
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<label class="control-label">글내용</label>
<textarea class="form-control" name="contents" id="contents" rows="10" cols="5"><%=article.contents%></textarea>
</div>
</div>
</div>
2개 이상의 데이터 받기
// 게시글 등록 조회 웹페이지 요청 및 응답 라우팅 메소드
router.get('/list',async(req,res) =>{
var searchOption = {
boardTypeCode:"0",
title:"",
isDisplayCode:"9"
}
// 1) DB에서 모든 게시글 데이터 목록을 조회해 오기
const articles =[
{
article_id:1,
board_type_code:1,
title:"공지게시글 1번글입니다.",
contents:"공지게시글 1번 내용입니다.",
view_count:10,
ip_address:"111.111.124.44",
is_display_code:1,
reg_date:"2023-12-12",
reg_member_id:"gowoon"
},
{
article_id:2,
board_type_code:2,
title:"기술블로깅 게시글 1번글입니다.",
contents:"기술블로깅 게시글 1번 내용입니다.",
view_count:20,
ip_address:"122.111.124.44",
is_display_code:0,
reg_date:"2023-12-13",
reg_member_id:"gowoon"
},
{
article_id:3,
board_type_code:2,
title:"기술 게시글 입니다.",
contents:"기술 게시글 내용입니다.",
view_count:30,
ip_address:"123.111.124.44",
is_display_code:1,
reg_date:"2023-12-14",
reg_member_id:"gowoon"
}
];
// 2) 게시글 전체 목록을 list.ejs뷰에 전달
res.render('article/list',{articles,searchOption});
});
마치며
- 지금까지 나는 Express를 가지고 간단한 페이지를 만들어낼 때 EJS 기본 문법은 조금은 알고 활용해왔다.
- 오늘 자료를 정리하며 여는태그와 닫는태그를 가지고서도 기본적인 기능을 구현할 수 있음에 신기했다.
- 그래도 나는 EJS보단 PHP가 편한것같다..
Dec 22, 2023 Copyright deVlog. All rights reserved.
2023년 12월 22일 deVlog 작성, 모든 권리 보유
'Coding > JavaScript' 카테고리의 다른 글
pm2를 통한 NodeJS Application 관리 기법 (0) | 2024.02.02 |
---|