기존 Express 서버에 Vue.js 적용해보기 (feat.EJS)
도입 이유
팀에서 쓰는 관리자 페이지에 추가 작업을 할 것이 몇 가지 있었습니다.
반복되는 복잡한 코드와 화면 구조가 바뀔 시 걸리는 작업의 시간 그리고 유지보수 측면의 이유로 인해 많은 고민을 하다 Vue.js 를 적용하게 되었습니다.
기존에는 EJS를 사용하였는데 아래처럼
<%- include ../role/list %>
파일 추가는 가능하나, 해당 파일을 바로 볼 수 없고 (ctrl+click 혹은 cmd+click) 파일 이름 검색 후 찾아서 들어가야 하는 불편한 점이 있었습니다.
또한, 아래의 코드와 같이 <% %> 태그를 사용할 때 문법적 오류를 찾기 힘들고 코드가 깔끔하지 않아 가독성이 떨어져 유지보수 하기가 쉽지 않았습니다.
<% for(var i=0; i< size; i++) { %>
<tr>
<td>
<%= roleList[i].roleNo %>
</td>
<td>
<%= roleList[i].name %>
</td>
<td>
<%= roleList[i].status %>
</td>
</tr>
<% } %>
그리고 jquery를 사용할 때 모듈화를 잘하더라도 새로운 화면 추가나 구조의 변화로 인한 유지보수/개발 시간이 꽤 오래 걸리고 모듈화가 쉽지 않은 점 등으로 인한 불편함으로 인해 Vue.js를 적용하게 되었습니다.
글을 쓰게 된 계기
Node.js + Express + EJS 로 구성되어있는 기존 프로젝트에 Vue.js 를 도입하면서 시행착오가 있었습니다.
많은 검색을 해봤는데 대다수의 글은 새로운 프로젝트 구성을 Node.js + Express + Vue.js 로 세팅해서 사용하는 글들이었고 제가 생각하는 구성과는 다른 부분이 많았습니다.
그래서 기존 프로젝트에 Vue.js를 도입하려는 다른 분들에게 조금이나마 도움이 되었으면 하는 바람으로 글을 쓰게 되었습니다.
고민 또 고민
Vue.js를 도입하기 전 기존 프로젝트에 최대한 영향이 덜 가는 방법이 어떤 것일까 오랜 시간 고민을 했습니다.
그러다 기존 EJS를 한 번에 대체하기에는 시간이 오래 걸리고 위험요소가 있어 Vue.js를 병행하여 개발하기로 결정했습니다.
프론트엔드에 대해서 많이 알지 못하기에 나름의 해결책으로 찾은 세 가지 방안은
- Vue.js를 템플릿 구문에 사용해 기존 EJS를 조금씩 바꿔나간다.
- Build 한 html 파일을 호출한다.
- EJS layout을 이용
- Build 한 html 파일을 호출한다.
- EJS를 사용하지 않음. Vue.js 만 사용
첫번째
“Vue.js를 템플릿 구문에 사용해 기존 EJS를 조금씩 바꿔나간다.” 같은 경우에는
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
를 기존 EJS에 사용해 페이지를 부분적으로 고쳐나가는 방법입니다.
예 :
<div id="app">
<table class="table table-responsive table-hover small">
<thead>
<tr>
<th v-for="key in headers"> {{ key }} </th>
</tr>
</thead>
<tbody>
<tr v-for="list in roleList">
<td>{{ list.roleNo }}</td>
<td>{{ list.name }}</td>
<td>{{ list.status }}</td>
</tr>
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#app',
data: {
headers: ['no', '권한명', '권한 상태'],
roleList: [
{roleNo: 'test', name: 'testName', status: 1},
{roleNo: 'test2', name: 'testName2', status: 1}
]}
})
</script>
하지만 후에는 Vue.js 로 모든 페이지를 변경할 것이기에 애초에 페이지 하나씩 바꿔나가는 것이 좋겠다는 생각에 패스!
두번째
“Build 한 html 파일을 호출한다. (EJS layout을 사용)” 같은 경우는
원래 기본적인 layout 구조가 잡혀있는 (main title , side bar, etc) EJS의 layout 파일을 그대로 사용하면서 그 틀 안에 Build 한 파일을 보이게 하는 것입니다.
res.render(role.html, {data: ‘test’});
이 방법은 hot reload 는 잘 됩니다.
하지만 local에서 Vue.js 를 개발할 때에 기본적인 layout이 보이지 않아 실제 운영 환경(view)과는 다르다는 단점이 있어서 패스 !
build (with 기본 layout)
local (기본 layout 인 side bar, title 제외)
세번째
“Build 한 html 파일을 호출한다. (EJS를 사용하지 않음. Vue.js 만 사용)” 같은 경우에는 axios를 사용하고 build 해서 Vue.js를 쓰는 것입니다.
hot reload도 되고 EJS에서 사용하고 있는 layout을 Vue.js에 넣어서 local 개발 시 같은 환경으로 개발할 수 있어 선택했습니다 !
긴 서론은 끝내고 !! 어드민에 Vue.js를 사용하기 위해 했던 설정으로 넘어가겠습니다.
Setting/설정
기본 설정은 다른 블로그에 많기 때문에 설명하지 않고 중요한 부분만 쓰겠습니다.
저는 client라는 디렉터리를 따로 생성했습니다.
처음 세팅은 프로젝트에 맞는 설정으로 하시면 됩니다.
app.js
app.set('views', [path.join(__dirname, 'views'),
path.join(__dirname ,'dist')]);
EJS view 는 views에 있고 Vue.js를 build 한 건 dist에 있습니다.
두 개를 다 사용하기 위하여 설정해줍니다.
Vue.js를 사용할 때 EJS도 함께 사용하기 때문에 Multiple Page로 개발 하였습니다.
그와 관련된 Config 세팅을 따로 해줘야 합니다. Config 세팅은 아래의 git을 참고하였습니다.
참고 : https://github.com/Plortinus/vue-multiple-pages
vue.config.js
const glob = require('glob')
const pages = {}
glob.sync('./src/pages/**/app.js').forEach(path => {
const chunk = path.split('./src/pages/')[1].split('/app.js')[0]
pages[chunk] = {
entry: path,
template: 'public/index.html',
chunks: ['chunk-vendors', 'chunk-common', chunk]
}
})
module.exports = {
pages,
devServer: {
proxy: {
'/': {
target: 'http://localhost:4000',
changeOrigin: true,
pathRewrite: { '^/': '' },
ws:false
}
},
},
outputDir:'../dist'
}
local 개발 시 프론트 app과 백엔드 서버가 같은 host가 아니면 proxy 설정을 해줘야 합니다.
참고 : https://cli.vuejs.org/config/#devserver-proxy
디렉토리 구조
Multiple page를 위해 설정한 config는 디렉토리 구조에 맞춘 설정입니다. 디렉토리 구조는 아래와 같습니다.
pages 밑에는 각각의 page 별 디렉토리가 있고 그 안에 app.js 파일이 있어야 합니다.
index.html 파일은 공통으로 한 파일만 쓰고 있습니다.
node 서버
/user
function index(req, res) {
res.sendFile(path.join(__dirname, '../dist', 'user.html'))
}
/userList
function userList(req, res) {
return res.json({users: userService.getUser()});
}
/user 호출 시 build 된 user.html을 화면에서 볼 수 있게 합니다.
/userList 호출하면 그와 관련된 data를 넘겨줍니다.
/userList 는 axios 를 사용하여 호출할 것입니다.
client/src/pages 에 user 디렉토리를 생성 후 app.js 파일을 생성합니다. 같은 디렉토리에 App.vue 파일을 생성합니다.
여기에서는 간단하게 설명하기 위하여 모듈화/컴포넌트화는 생략했습니다.
확인
build 후 /user를 호출 ! 혹은 npm run serve 후 user.html 호출
hot reload
편리한 hot reload 또한 사용할 수 있습니다
참고: https://vue-loader.vuejs.org/guide/hot-reload.html
후기
기존 코드를 차근차근 바꿔나가기 위해서 EJS와 Vue.js가 공존하는 형태의 프로젝트를 구성하였는데 생각보다 첫 세팅이 힘들고 오래걸렸습니다. 하지만 코드가 깔끔해지고 가독성이 더 좋아져서 만족합니다.
비슷한 환경에서 세팅하는 분들에게 조금이라도 도움이 되었으면 하여 글을 씁니다. 즐거운 vue하세용 :)