프론트와 백그라운드 개발 환경 분리, 파셀(Parcel)
파셀(Parcel)은 나온지 얼마되지 않는 젊은(?)축에 속하는 기술 입니다.
웹 어플리케이션 번들러라고 불리는 파셀의 정의는 아래와 같습니다.
Parcel은 워커 프로세스를 이용하여 멀티코어 컴파일을 가능케 하고,
심지어 재시작 후라 해도 빠른 리빌드를 할 수 있도록 파일시스템 캐시를 갖고 있습니다.
말이 쉽지가 않는데,
요약을 하면 장황하게 쓰여진 자바스크립트(Javascript)와 각종 css, 기타 파일들을 한번에 압축 및 정리하여 배포 가능한 형태로 만들어주는 역할을 하는 번들러 입니다.
- 번들러(bundler) : 지정한 단위로 파일들을 하나로 만들어 요청에 대한 응답으로 전달할 수 있는 환경을 만들어주는 역할
파셀(Parcel)을 통해 개발 영역을 분리함으로써 앵귤러(Angular) 또는 리엑트(React)와 같은 형태의 개발 환경을 만들 수 있었습니다.
파셀을 사용하기 위해서는 Node.js가 설치되어 있어야 합니다.
Nodejs 설치방법은 쉬우므로 넘어가겠습니다.
※ Node.js와 npm과 관련된 내용을 전혀 모르면 해당 내용을 먼저 파악하고 접근하는 것이 좋습니다.
이제부터 개발 환경구축에 대해서 소개하여 보겠습니다.
#1. 프로젝트 초기화 및 파셀 설치
프론트 프로젝트를 초기화 하기 위해서 원하는 디렉토리를 만든 다음에 아래 명령어를 실행 합니다.
* 명령어 : npm init
이어서 파셀을 설치하는 방법은 매우 간단 합니다.
아래 명령어를 통해 파셀을 어디서든 사용할 수 있게(Global) 설치하여 줍니다.
* npm install -g parcel-bundler
여기까지가 개발환경 구성의 가장 기초부분 입니다.
#2. 프로젝트의 구성
파셀(parcel)은 cmd에서 parcel src/index.html 등 이러한 방식으로 동작시킬 수 있습니다.
그러나 파셀을 CMD에서 명령어를 통해(cli 방식) 실행하는 것은 2가지 문제가 존재 합니다.
바로 크로스 도메인 문제와 html 파일의 include 입니다.
1) 교차출처 정책, 크로스 도메인(same origin policy, cross domain) 이슈
- 파셀은 실행되면 특정 포트로 동작합니다. (서버입니다)
- 마찬 가지로, 데이터에 접속하는 어플리케이션 서버는 Java, php, Node.js 등 다양한 언어로 개발 할 수 있습니다.
- 그러므로 프론트에서(파셀) 백그라운드로 요청을 하면 서버와 서버간의 요청이 이루어지게 됩니다.
- 서로 다른 서버에서의 비동기 호출 방식(ajax)은 일반적으로 허용되지 않습니다.
2) 반복적인 내용이 포함되어 있는 코드의 분리 제한
- 자바스크립트(Javascript)의 문법에서는 html 파일을 html파일에 포함하는 include 기능을 지원하지 않습니다.
- 이러한 기능은 일반적으로 서버에서 include라는 명령어, 아니면 프레임워크 등을 통해서 해결 합니다.
그러므로 명령어(cli)방식으로 개발환경을 구성하는 것은 위 2가지 이슈가 존재하게 되므로 좋은 방법이 아닙니다.
여기서는 파셀(Parcel)에서 제공하는 api 방식을 통해서 환경 구성을 하려 합니다.
api 방식은 js파일을 만들어 각종 설정 값과 위 2개의 문제를 해결 할 수 있는 라이브러리를 넣어 준 다음 Node.js의 명령어를 통해 해당 파일을 동작하게 하는 것을 의미 합니다.
api 방식으로 프로젝트를 구성하려면 아래 3개의 추가 라이브러리를 설치 합니다.
# 교차출처(proxy) 정책 대비 : http-proxy-middleware
npm install http-proxy-middleware
# 프론트 접속을 위한 대비 : express
npm install express
# html 파일 include를 위한 대비 : posthtml-include
npm install posthtml-include
이어서 파셀 기능을 동작할 js 파일을 만들어 줍니다.
파일 이름은 아무거나 해도 상관 없습니다.
여기서는 bundler.js 로 하였습니다.
* 파일 이름 : bundler.js
const {createProxyMiddleware} = require('http-proxy-middleware');
const Bundler = require('parcel-bundler');
const express = require('express');
const options = {
outDir: './dist', //결과가 저장될 디렉토리 입니다.(나중에 서버 프로젝트 경로로 해도 좋을 듯 합니다.)
publicUrl: '/', //서버상의 위치 입니다.
watch: true, // 파일 변경을 감지해서 변경시 다시 빌드할지에 대한 여부 입니다.
cache: true, // 캐시를 여부 입니다.
https: false, // 파일을 https로 서빙할지 http로 할지 여부 입니다.
hmr: false, // 자동으로 파일변경되면 웹 브라우저가 스스로 리로딩 되는 것을 설정 합니다. true, false
global: 'parcelApp' // 파셀에서 만든 글로벌 변수 이름 입니다.
}
const app = express();
let bundler;
async function runBundle() {
bundler = new Bundler('src/*', options) //src폴더 내부를 대상으로 합니다.
}
new Promise((succ, fail) => {
try {
runBundle()
succ(true);
} catch (e) {
console.log(e)
succ(false);
}
}).then(() => { // 아래와 같은 방법으로 프록시를 설정 할 수 있습니다.
app.use('/api', createProxyMiddleware({
target: 'http://127.0.0.1:8080/', //데이터베이스 서버 입니다.
changeOrigin: true
}));
app.use(bundler.middleware());
app.listen(1234); // 1234포트에서 동작하게 합니다.
}).catch(() => {
console.log('error')
})
src 디렉토리는 파셀이 바라볼 디렉토리를 의미 합니다. 해당 디렉토리에서 작업을 하면 됩니다.
그리고 dist 디렉토리는 파셀이 src 디렉토리를 대상으로 빌드(build)할 디렉토리를 의미 합니다.
물론 src와 dist 디렉토리 이름은 바꾸어도 상관 없습니다.
다음으로 app.listen(1234) 라는 부분에서 1234포트 번호로 개발용 서버가 동작하게 하였습니다.
파셀이 동작하는 서버는 http://127.0.0.1:1234/ 입니다.
그리고 createProxyMiddleware 함수가 보입니다.
createProxyMiddleware함수는 파셀 내부에서 api라는 경로로 호출(Request)이 존재하면 http://127.0.0.1:8080/api로 전달하여 주는 역할을 합니다.
포워딩 또는 프록시(proxy) 방법이라고 합니다.
위 사진을 예로들어 프록시에 대해서 다시 설명하여 보겠습니다.
파셀에서(http://127.0.0.1:1234/) api라는 주소에 요청이 들어가면 자동으로 데이터베이스에 연결된 서버(http://127.0.0.1:8080/api)로 포워딩(proxy)하여 내용을 전달하여 줍니다.
이러한 방법을 통해서 크로스 도메인 이슈를 해결 할 수 있습니다.
다음으로 .posthtmlrc 라는 파일을 package.json이 위치한 곳에 만들어 준 다음 아래 내용을 입력 합니다.
* 파일명에 주의하여 주세요!
* 파일명 : .posthtmlrc
{
"plugins": {
"posthtml-include": {
root: './src'
}
}
}
해당 내용은 posthtml이라는 라이브러리가 include라는 테그를 만나면 src 디렉토리에서 해당 파일을 찾아 포함시켜주는 역할을 의미 합니다.
여기 까지의 내용을 사진으로 살펴본 뒤에 잘못된 부분이 없는지 확인하여 줍니다.
여기 까지가 개발환경 구성의 마지막 단계 입니다.
bundler.js는 파셀을 실행하기 위한 세부내용이 담겨있는 파일이라고 생각하면 좋을 것 같습니다.
#3. 테스트
테스트를 위해서 데이터베이스에 접속하는 서버로 SpringBoot를 사용 하였습니다.
그리고 파셀에서는 ajax 기능이 존재하는 클래스를 만든 뒤에 호출하여 보았습니다.
결과는 정상적으로 작동하는 것을 볼 수 있었습니다.
실행하는 방법은 앞에서 만든 파일인 bundler.js를 실행하여 주면 됩니다. (명령어 : node bundler.js)
* index.html파일 샘플
<html>
<head>
<meta charset="utf-8">
<title>index</title>
<include src="./common.html"></include>
</head>
<body>
<include src="./template/head.html"></include>
<include src="./template/left.html"></include>
<img src="./etc/test.png" width="200" height="400">
<a href="board.html" class='main'>go board page</a>
<button type='button' onclick="insert()">데이터 등록</button>
</body>
</html>
<script>
var clas = new parcelApp.MainClass();
clas.request('/api/getBoardData',{abcd:'1234'}, arg=>{
console.log(arg);
})
function insert(){
clas.request('/api/insertData',{parcel:'Im Parcel!', title:'파셀',contents : '컨텐츠'}, arg=>{
console.log(arg);
})
}
</script>
위 index.html 파일에서의 살펴보아야 할 부분은 2가지 입니다.
1) include 는 src 디렉토리에 존재하는 파일을 참조하여 포함시켜 줍니다.
2) parcelApp이라는 변수는 bundler.js에서 설정한 변수 명칭 입니다. javascript를 <script> 테그로 분리할 경우에
사용 합니다.
모든 내용을 정리하기가 참 어려운 것 같습니다.
이럴 때는 역시 샘플코드를 직접 만저보는 것이 좋은 듯 합니다!
아래 샘플코드를 다운받아서 환경을 한번 구성한 다음에 실행하여 보면 좋을 것 같습니다.
물론, 데이터베이스에 접속하는 서버는 따로 만드셔야 합니다. ^^
파일 받기 귀찮으시면 아래 깃을 통해서 확인하셔도 될 듯 합니다.
이상으로, 파셀(Parcel) 개발 환경 구축에 대해서 살펴 보았습니다.
궁금한 점이나 틀린부분은 언제든 연락주세요!