Event Binding(이벤트 바인딩)과 Event Handler(이벤트 핸들러)

Event Binding


바인딩이란, 서로 묶어서 연결해 준다는 뜻이다. 이벤트 바인딩이란, 발생하는 이벤트와 그 후에 어떤 일이 벌어질지 알려주는 함수(콜백함수)와 묶어서 연결해 준다는 뜻이다. 예를 들어, 어떤 버튼을 사용자가 클릭하게 되면, 클릭(‘click’)이벤트가 발생하게 되고, 그 이벤트가 발생했을 때 어떤 일이 벌어진다는 것을 알려주는 콜백함수를 실행하게 된다. 이때, 이 콜백함수를 이벤트 핸들러라고 한다.

이벤트 바인딩에는 대표적으로 3가지 방식이 있다.

  1. HTML 이벤트 핸들러
  2. 전통적인 DOM 이벤트 핸들러
  3. Event Listener를 이용한 이벤트 핸들러

1~2번의 단점을 보완한 방식이 Event Listener를 이용한 이벤트 핸들러 방식이다.


1. HTML 이벤트 핸들러

HTML 요소의 이벤트 Attribute에 이벤트 핸들러를 대응시키는 방법이다.

1
2
3
4
5
<button onclick="clickBtn()">Click me</button>

function clickBtn() {
alert('Button clicked!');
}

옛날 코드를 보게 되면 위와 같은 방식을 사용한 코드가 있다. 그래서 혹시 모를 상황에 대비해 알아둘 필요는 있지만, 현재 이 방식은 사용되지 않고, 사용해서도 안된다. 또한, 이렇게 되면 HTML과 Javascript가 혼용이 되는데, 이 둘은 관심사가 다르기 때문에 같이 사용하는 것을 피해야 한다.


HTML 이벤트 핸들러 내부의 this

HTML 이벤트 핸들러 방식의 경우, 이벤트 핸들러 내부의 this는 window를 가리킨다.

1
2
3
4
5
6
7
<button onclick="clickBtn()">Click me</button>

function clickBtn() {
alert('Button clicked!');
console.log(this); // window
console.log(event.currentTarget); // <button onclick="clickBtn()">Click me</button>
}


2. 전통적인 DOM 이벤트 핸들러

HTML Event Handler의 보완점:

  • HTML과 Javascript가 혼용되는 문제는 해결

단점:

  • 이벤트 핸들러에 하나의 함수만을 바인딩할 수 있다.
  • 함수에 인수를 전달할 수 없다.
  • 바인딩된 이벤트 핸들러가 2개 이상일 경우, 제일 마지막에 추가된 코드의 바인딩된 이벤트 핸들러만 실행된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
<button id="myBtn">Click me</button>

var myBtn = document.getElementById('myBtn');

// 첫번째 바인딩된 이벤트 핸들러 => 실행되지 않는다.
myBtn.onclick = function () {
alert('Button clicked 1');
};

// 두번째 바인딩된 이벤트 핸들러
myBtn.onclick = function () {
alert('Button clicked 2');
};


전통적인 DOM 이벤트 핸들러 내부의 this

전통적인 DOM 이벤트 핸들러 방식에서 이벤트 핸들러 내부의 this는 이벤트에 바인딩된 요소를 가리킨다. 이것은 이벤트 객체의 currentTarget 프로퍼티와 같다.

1
2
3
4
5
6
7
8
<button id="myButton">Click me!!!</button>

var myBtn = document.getElementById('myButton');
myBtn.onclick = function() {
console.log(this); // <button id="myButton">Click me!!!</button>
console.log(event.currentTarget); // <button id="myButton">Click me!!!</button>
console.log(this === event.currentTarget); // true
};

myButton이란 id를 가진 button 요소(myBtn)가 이벤트에 바인딩된 요소를 말한다. 이것은 이벤트 객체의 currentTarget 프로퍼티와 같다.


3. Event Listener를 이용한 이벤트 핸들러

addEventListener 함수를 이용하여 대상 요소(Event Target)에 이벤트를 바인딩하고, 해당 이벤트가 발생했을 때 실행될 콜백 함수를 지정한다.

1
2
3
4
target.addEventListener(type, listener[, useCapture]);

var el = document.getElementById("outside");
el.addEventListener("click", function(){modifyText("four")}, false);

addEventListener 함수의 인수:

  • type: 이벤트 타입
  • listener: 이벤트 핸들러, 즉 이벤트가 발생했을 때, 실행될 콜백함수
  • useCapture: true면 Capturing, false면 Bubbling(Default: false)

Event Listener를 이용한 이벤트 핸들러의 장점

  • 하나의 이벤트에 대해 하나 이상의 핸들러를 추가할 수 있다.
  • 캡처링(Capturing)과 버블링(Bubbling)을 지원한다.
  • HTML 요소뿐만아니라 모든 DOM 요소에 대해 동작한다.
1
2
3
4
5
6
7
<label for='email'>Your Email</label>
<input type='text' id='email'>

var elem = document.getElementById('email');
elem.addEventListener('blur', function() {
alert('Your Email!');
});

참고로, addEventListener 함수는 IE 9 이상에서 동작한다. IE 8 이하에서는 attachEvent 함수를 사용한다.

만약 addEventListener 함수 앞에 대상요소(elem)를 지정하지 않으면, blur 이벤트는 전역객체 window에 바인딩된다.


Event Listener를 이용한 이벤트 핸들러 내부의 this

addEventListener 함수에서 지정한 이벤트 핸들러 내부의 this는 Event Listener에 바인딩된 요소(currentTarget)를 가리킨다. 이것은 이벤트 객체의 currentTarget 프로퍼티와 같다.

1
2
3
4
5
6
7
8
<button id="myBtn">Click me!!!</button>

var myBtn = document.getElementById('myBtn');
myBtn.addEventListener('click', function (event) {
console.log(this); // <button id="myBtn">Click me!!!</button>
console.log(event.currentTarget); // <button id="myBtn">Click me!!!</button>
console.log(this === event.currentTarget); // true
});

Event와 Event 종류

Event(이벤트)란 무엇인가?


이벤트는 어떤 사건을 말한다. 브라우저에서 사건(Event)이란, 예를 들어, 사용자가 어떤 웹페이지에서 버튼을 클릭했을 ‘때’ 또는 어떤 박스에서 값을 입력했을 ‘때’를 의미한다.

이벤트는 이벤트가 발생했을 때, 그에 맞는 대응을 하도록 코드를 작성해야 한다. 이를 위해서는 보통, 이벤트는 함수에 연결되며 그 함수는 이벤트가 발생하기 전에는 실행되지 않다가 이벤트가 발생하면 실행되는데, 이 함수(콜백함수)를 이벤트 핸들러라고 한다.

1
2
3
4
var elem = document.getElementById('alertButton');
elem.addEventListener('click', function() {
alert('Hello World');
});

id가 alertButton인 DOM 요소의 버튼을 클릭했을 때(이벤트), ‘Hello World’를 보여주는 alert가 실행되는 콜백함수가 이벤트 핸들러이다.


Event 종류


브라우저에 사용하는 이벤트는 다양하지만, 자주 사용되거나 대표적인 이벤트만 정리한다.


1. UI Event


Event Description
load 웹페이지의 로드가 완료되었을 때
unload 웹페이지가 언로드될 때(주로 새로운 페이지를 요청한 경우)
error 브라우저가 자바스크립트 오류를 만났거나 요청한 자원이 존재하지 않는 경우
resize 브라우저 창의 크기를 조절했을 때
scroll 사용자가 페이지를 위아래로 스크롤할 때
select 텍스트를 선택했을 때


load 이벤트를 사용하는 예제

1
2
3
window.addEventListener("load", function(event) {
console.log("All resources finished loading!");
});


2. Keyboard Event


Event Description
keydown 키를 누르고 있을 때
keyup 누르고 있던 키를 뗄 때
keypress 키를 누르고 뗏을 때


keyup 이벤트를 사용하는 예제

1
2
3
4
5
inputTodo.addEventListener('keyup', function (e) {
if (e.keyCode !== 13 || !inputTodo.value) return;
addTodo(inputTodo.value);
inputTodo.value = '';
});


3. Mouse Event


Event Description
click 마우스 버튼을 클릭했을 때
dbclick 마우스 버튼을 더블 클릭했을 때
mousedown 마우스 버튼을 누르고 있을 때
mouseup 누르고 있던 마우스 버튼을 뗄 때
mousemove 마우스를 움직일 때 (터치스크린에서 동작하지 않는다)
mouseover 마우스를 요소 위로 움직였을 때 (터치스크린에서 동작하지 않는다)
mouseout 마우스를 요소 밖으로 움직였을 때 (터치스크린에서 동작하지 않는다)


click 이벤트를 사용하는 예제

1
2
3
4
todoList.addEventListener('click', function (e) {
if (!e.target || e.target.nodeName !== 'SPAN' || e.target.parentNode.nodeName === 'LABEL') return;
removeTodo(e.target.dataset.id);
});


4. Focus Event


Event Description
focus 요소가 포커스를 얻었을 때
blur 요소가 포커스를 잃었을 때


focus와 blur 이벤트를 사용하는 예제

1
2
3
4
5
6
7
8
var form = document.getElementById("form");
form.addEventListener("focus", function( event ) {
event.target.style.background = "pink";
}, true);

form.addEventListener("blur", function( event ) {
event.target.style.background = "";
}, true);


5. Form Event


Event Description
input input 또는 textarea 요소의 값이 변경되었을 때
change select box, checkbox, radio button의 상태가 변경되었을 때
submit form을 submit할 때 (버튼 또는 키)
reset reset 버튼을 클릭할 때 (최근에는 사용 안함)


change 이벤트를 사용하는 예제

1
2
3
4
5
6
7
8
9
10
todoList.addEventListener('change', function (e) {
toggleTodoComplete(e.target.id);
});

var toggleTodoComplete = function (id) {
todos = todos.map(function (todo) {
return todo.id === +id ? Object.assign({}, todo, { completed: !todo.completed }) : todo;
} );
renderTodos();
};


6. Clipboard Event


Event Description
cut 콘텐츠를 잘라내기할 때
copy 콘텐츠를 복사할 때
paste 콘텐츠를 붙여넣기할 때


copy 이벤트를 사용하는 예제

1
2
3
4
5
document.addEventListener('copy', function(e){
e.clipboardData.setData('text/plain', 'Hello, world!');
e.clipboardData.setData('text/html', '<b>Hello, world!</b>');
e.preventDefault(); // We want our data, not data from any selection, to be written to the clipboard
});


7. Websocket Event


Event Description
open 웹소켓 연결이 되었을 때
message 웹소켓을 통해 메세지가 전달되었을 때
error 몇개의 메세지가 전달이 안된 상태로 웹소켓 연결이 끝났을 때
close 웹소켓 연결이 끝났을 때


8. CSS Animation Event


Event Description
animationstart CSS 애니메이션이 시작되었을 때
animationend CSS 애니메이션이 끝났을 때
animationiteration CSS 애니메이션이 반복될 때

이외에 다른 이벤트는 MDN에서 확인할 수 있다.

Event Loop(이벤트루프)와 Javascript Concurrency(동시성)

Browser Architecture


Browser Architecture
출처: Browser Architecture

Browser안에는 위와 같이 자바스크립트엔진 뿐만 아니라 다른 것들이 같이 포함되어 있다.

  1. 자바스크립트엔진(크롬: V8)
    • Heap과 Stack으로 구성되어있고, 자바스크립트가 브라우저에서 실행되는 곳이 자바스크립트엔진, 정확히는 Stack이다.
  2. Web APIs
    • 비동기 방식으로 호출되는 것들(Timer 함수/DOM Event/Ajax)이 정의되는 영역이다.
  3. Callback Queue
    • Web APIs으로부터 옮겨와 자바스크립트엔진의 Stack으로 이동하기 위해 기다리는 곳이다.
  4. Event Loop
    • Callback Queue에서 기다리고 있는 비동기 방식으로 호출되는 것들(Timer 함수/DOM Event/Ajax)을 Stack이 완전히 비어있을 때 이동시키는 역할을 한다.


자바스크립트 기본 특징


자바스크립트는 싱글쓰레드(single-threaded), 즉 1개의 쓰레드를 가지고있다. 1개의 쓰레드를 가지고 있다는 말은 한번에 하나일을 처리한다는 것이다. 자바스크립트엔진의 Stack에서 한번에 하나의 일(함수 호출)을 처리한다는 뜻이다. 그런데, 실제로 자바스크립트 기반의 애플리케이션은 여러가지일이 동시에 일어난다.

왜 그럴까? 이걸 전문적으로 말하면 자바스크립트는 동시성(Concurrency)을 지원한다는 것인데, 어떻게 그럴 수 있을까? 여기서 이벤트루프(Event Loop)에 대한 개념이 나온다.

먼저 동기적(한번에 하나의 일을 처리)으로 작동하는 기본적인 자바스크립트 코드가 돌아가는 원리를 알아보자.


(기본) 자바스크립트 동작 원리


다시 한번 Architecture를 보자.

Browser Architecture
출처: Browser Architecture

비동기로 호출되는 것들(Timer 함수/DOM Event/Ajax)이 없는 자바스크립트 코드의 경우, 자바스크립트엔진의 Stack에서만 하나씩 호출되어 코드가 돌아간다. 즉, Web AIPs, Callback Queue, 그리고 Event Loop 등을 사용하지 않는다.

아래 동기적 코드를 보자.

1
2
3
4
5
6
7
8
9
function multiply(a, b) {
return a*b;
}
function square(a) {
const sq = multiply(a, a);

console.log(sq);
}
square(3);

이 코드는 어떤 순서로 호출되어 값이 나오게 될까?

호출되는 순서는 다음과 같다.

  1. square(3) 때문에, square 함수가 먼저 호출된다.
  2. sq에 multiply 함수를 할당하기 위해, multiply 함수가 호출된다.
  3. multiply의 return 값이 나온다.
  4. console.log(sq)의 결과값이 나온다.

이 순서를 Stack에서 확인해보자.

동기적 자바스크립트
출처: 동기적 자바스크립트

위 그림과 같이, Stack에서 push로 하나씩 함수가 쌓이고, pop으로 마지막에 쌓인 것부터 하나씩 호출되어 실행되고, 제거된다. 이런식으로, 한번에 하나씩 순서대로 일이 진행되어, 결과값이 나오게 된다. 이게 동기적 방식이다.


Error: Maximum call stack size exceeded

Stack안에 쌓이는 각 함수를 Stack Frame이라고 한다. 보통, 이런 각 Stack Frame은 ms(1초=1000ms)안에 동작이 끝난다. 그런데, Stack에는 Stack Frame의 수가 정해져 있고, 이 수를 넘게되면 에러가 발생하게 된다.

아래 코드를 보자.

1
2
3
4
function foo() {
return foo();
}
foo();

위 코드를 작성하고 실행하게 되면, 다음과 같은 에러가 발생한다.

1
RangeError: Maximum call stack size exceeded

이 에러의 원인은 Stack안에 정해진 Stack Frame의 수를 초과했다는 뜻이다. 즉, foo 함수가 호출될 때, return 값으로 foo 함수가 호출되기 때문에, 계속해서 호출되게 되고, 그 말은 Stack에 계속해서 foo 함수가 쌓인다는 뜻이다. 그래서 정해진 Stack Frame의 수를 초과하게 되어, 위와 같은 에러가 발생하게 된다. 이런 자바스크립트의 Stack에 대한 개념을 모르게되면, 이 에러가 발생했을 때 해결하기가 어려울 수 있다.

그럼, 자바스크립트에 동시성(Concurrency)을 어떻게 지원하는지 알아보자.


비동기적 자바스크립트 동작 원리


다시 한번 Architecture를 보자.

Browser Architecture
출처: Browser Architecture

비동기로 호출되는 것들(Timer 함수/DOM Event/Ajax)이 있는 자바스크립트 코드의 경우, 자바스크립트엔진의 Stack에서 Web AIPs로 이동하게 되고, 다시 Callback Queue로 이동하게 된다. 그리고 Stack에 있는 모든 함수가 제거되고 난뒤, Event Loop로 인해 Stack으로 이동되어, 함수가 호출되고 제거된다.

아래 비동기적 코드를 보자.

1
2
3
4
5
console.log("Print this 1st");
setTimeout(() => {
console.log("Print this 3rd");
}, 500);
console.log("Print this 2nd");

이 코드는 어떤 순서로 호출되어 값이 나오게 될까?

1
2
3
"Print this 1st"
"Print this 2nd"
"Print this 3rd"

비동기 함수인 setTimeout 함수가 0.5초뒤에 실행되니, 그 전에 마지막 console.log가 먼저 출력되어, 순서가 저렇게 된것일까? 이 과정을 정확하게 위해서는 이벤트루프(Event Loop) 개념을 이해해야 한다.

이 순서를 Architecture에서 확인해보자.
위 코드가 실제로 실행되는 과정은 아래와 같다.


비동기적 자바스크립트
출처: 비동기적 자바스크립트

  1. 먼저, 첫번째 console.log가 호출되고, 제거된다.
  2. 그리고, 비동기 함수인 setTimeout 함수가 호출된뒤, Web APIs로 이동한다.
  3. 이와 동시에, Stack에서 다음 console.log가 쌓인다.
  4. 이동한 setTimeout 함수는 Web APIs에서 0.5초(500ms) 동안 있다가, Callback Queue로 이동한다.
  5. Event Loop는 Stack에 있는 모든 함수가 제거된 것을 확인한 후, Callback Queue에 있는 setTimeout 함수를 Stack으로 보내고 실행한다.
  6. 그리고, 그 setTimeout 함수는 Stack에서 제거된다.

자바스크립트에서의 비동기적 방식은 위와 같이 진행되기 때문에, 비동기 함수보다 다른 일반 함수들이 먼저 실행되고, 그 다음에 비동기 함수가 진행된다. 결국, 자바스크립트엔진 밖에 있는 Web APIs, Callback Queue, 그리고 Event Loop가 비동기 함수를 따로 관리함으로써 자바스크립트에 동시성이 가능하게 된다. 따라서, 자바스크립트 기반의 애플리케이션은 여러가지 일들이 동시에 발생할 수 있는 것이다.


만약, setTimeout 함수의 두번째 인수가 ‘0’초면 어떻게 될까?

아래 코드를 보자.

1
2
3
4
5
console.log("Print this 1st");
setTimeout(() => {
console.log("Print this 3rd");
}, 0);
console.log("Print this 2nd");

이 코드는 어떤 순서로 호출되어 값이 나오게 될까?

1
2
3
"Print this 1st"
"Print this 2nd"
"Print this 3rd"

이 또한 setTimeout 함수의 두번째 인수가 0.5초일때와 동일하게 나온다. 즉, timer 함수의 시간과 상관없이, 이벤트루프는 Stack에 있는 다른 모든 함수가 제거된 뒤, timer 함수를 Stack으로 이동시키기 때문이다. 단지, Wep APIs에서 0.5초 걸리느냐, 0초 걸리느냐에 차이이다.


다른 비동기인 DOM 이벤트의 경우는 어떻게 될까?

아래 코드를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function func1() {
console.log('func1');
func2();
}

function func2() {
// <button id="bar">bar</button>
var elem = document.getElementById('bar');

elem.addEventListener('click', function () {
this.style.backgroundColor = 'blue';
console.log('func2');
});

func3();
}

function func3() {
console.log('func3');
}

func1();

위 코드의 실행순서는 다음과 같다.

  1. 함수 func1()이 호출되면 함수 func1()은 Stack에 쌓인다.
  2. 함수 func1()은 함수 func2를 호출하므로 함수 func2()가 Stack에 쌓이고 addEventListener가 호출된다.
  3. 이 addEventListener는 Wep APIs로 이동한다.
  4. Stack에는 func3()가 쌓인다. 이때, 만약 bar 버튼이 클릭되면, ‘click’ 이벤트가 발생하게 되어, addEventListener는 Callback Queue로 이동하게 된다.
  5. Stack에 있던 모든 함수가 제거되어 완전히 비어지면, 이벤트 루프는 이 addEventListener를 Stack으로 이동시키고, 실행하게 된다.

Ajax란 무엇인가?

Ajax란?


Ajax는 Asynchronous JavaScript And XML의 약자로, XMLHttpRequest 객체를 이용하여 비동기 방식으로 서버와 통신을 하는 것을 말한다. 웹 브라우저의 클라이언트와 서버간 통신은 url를 이용한 http 통신으로 이루어진다. 즉 브라우저가 서버로 request를 날리기 위해서는 해당 브라우저의 url 주소를 변경하여야 하는데 이때는 페이지 이동이 일어나게 된다. 하지만 ajax 의 경우 브라우저의 url 주소의 변경을 이용하지 않고 내부적으로 통신하여 response 를 받아오기 때문에 특정 데이터만 불러오거나 비동기로 데이터를 불러와야하는 경우 사용된다. 이때 Same Origin Policy 정책으로 인해 cross domain 을 허용하지 않기 때문에 외부 도메인을 사용하여야 하는경우 JSONP, XML 등을 이용하여야 한다.

비동기적이란, 서버에 요청을 하고 그냥 기다리는 것이 아닌, 기다림과 동시에 다른 작업을 할 수 있다는 것을 말한다. Ajax가 가지고 있는 중요 특징은 바로 이 비동기성으로, 서버로부터 웹페이지가 반환될 때, 화면 전체를 갱신하지 않고, 페이지 일부만을 갱신하게 해준다. 즉, 페이지 이동이나 새로고침 없이 페이지 일부만을 갱신할 수 있다. 예를 들어, 사용자가 페이지에서 어떤 이벤트를 발생시키면, 페이지 전체가 아닌 페이지 일부분만을 업데이트해서 보여주기 때문에, 페이지 전체가 Refresh 되지 않아, 사용자가 그 일부의 데이터를 기다리면서, 다른 일을 하여도 문제가 없다.

Ajax를 사용하는 대표적인 애플리케이션이 페이스북 타임라인이다. 페이스북 타임라인을 밑으로 내려가면서 보면, 그 페이스북 페이지 자체는 그대로 있는데, 필요한 타임라인 데이터만 받아올 수 있다. 웹 사이트 중 페이지 전환없이 새로운 데이터를 불러오는 사이트는 대부분 Ajax 기술을 사용하고 있다.


JSON이란?


JSON은 JavaScript Object Notation의 약자로, 클라이언트와 서버간에 데이터를 교환하기 위해 필요한 데이터 포맷을 말한다. 예전에는 데이터 교환을 위한 데이터 포맷으로 XML을 사용했으나, 요즘에는 데이터 구조화도 잘 되어있고, 가볍고 가독성이 좋은 JSON을 사용한다. JSON의 형태는 자바스크립트의 객체 리터럴과 비슷하지만, 순수 문자열로 구성된 규칙이 있는 구조화된 데이터 포맷이다.

1
2
3
4
5
{
"id": 1,
"content": "HTML",
"completed": false
}

JSON의 이름(key)는 반드시 큰따옴표(“”)로 둘러싸야 한다.(작은따옴표(‘’)는 사용이 안된다.)


JSON.parse() & JSON.stringify()


클라이언트와 서버간에 통신을 할때는, JSON 형태, 즉 문자열로 데이터를 주고 받는다. 그러나, 서버로부터 응답받은 데이터를 클라이언트(브라우저)에서 사용하기 위해서는 JSON 형태의 문자열을 객체로 바꿔줘야 한다. 이를 역직렬화(Deserializing)이라고 하는데, 이를 위해서는 내장 객체 JSON의 static 메소드인 JSON.parse()를 사용해야 한다.

이와 반대로, 클라이언트(브라우저)에서 서버로 데이터를 보내기 위해서는 객체를 문자열로 바꿔줘야 한다. 이때는 JSON.stringify()를 사용해야 한다.

JSON.stringify()에 대해 자세히 확인해보자.


Ajax Request & Response


Javascript를 이용해서 서버로 보내는 Ajax Request를 만들기 위해서는 XMLHttpRequest 객체를 사용해서 Ajax 요청을 생성하고 전송한다. 서버로부터 응답을 받을때도 XMLHttpRequest 객체를 사용해서 처리한다. 즉, XMLHttpRequest 객체의 프로퍼티 및 메소드를 사용하여 코드를 작성한다.

코드 작성시, 크게 3가지로 나눌 수 있다.

  1. 서버로 요청 보내기
  2. 서버로 요청보낼때, Request Header 보내기
  3. 서버로부터 받은 응답 처리하기


1. Ajax Request 보내기


XMLHttpRequest 객체를 사용해서 Ajax 요청 처리에 대한 코드는 다음과 같다.

1
2
3
var xhr = new XMLHttpRequest();
xhr.open('GET', '/users');
xhr.send();


1-1. XMLHttpRequest 인스턴스 생성


1
2
// XMLHttpRequest 생성자로 xhr 인스턴스를 생성
var xhr = new XMLHttpRequest();

XMLHttpRequest 객체는 다양한 프로퍼티 및 메소드를 가지고 있다.


1-2. XMLHttpRequest.open()으로 요청 준비


1
2
// XMLHttpRequest가 가지고 있는 open 메소드로 요청을 준비
xhr.open('GET', '/users');

XMLHttpRequest.open 메소드를 사용할 때, 인수는 다음과 같다.

  • 첫번째 인수: HTTP Method(GET/POST/PUT/PATCH/DELETE 등)를 사용
  • 두번째 인수: 요청 보낼 URL
  • 세번째 인수(옵션): async로 비동기를 나타낸다.(true면 비동기, false면 동기인데, 아무것도 작성안하면 default로 비동기이다.)


1-3. XMLHttpRequest.send()로 요청 전송


1
2
// XMLHttpRequest가 가지고 있는 send 메소드로 요청을 전송
xhr.send();

서버에 요청을 준비하는 단계를 보자.

1
xhr.open('GET', '/users');

이때 HTTP Method로 ‘GET’을 사용하게 되면, URL의 일부분인 query string(쿼리문자열)로 데이터를 서버로 전송하기 때문에, send 메소드에 인수로 데이터를 보낼 필요가 없다. send 메소드에 인수를 Request Body라고 하는데, 이부분이 null이 되어, 무시된다.

그럼 만약, ‘GET’이 아닌 ‘POST’를 하게되면 어떻게 될까?


2. 서버로 요청보낼때, Request Header 보내기


‘POST’의 경우, 데이터(payload)를 Request Body에 담아 전송한다.

1
2
3
4
xhr.send(({
name: "donald",
country: "United States"
}));

이럴 경우, XMLHttpRequest.setRequestHeader() 메소드를 사용해서, HTTP Request Header의 값을 설정해야 한다. 이때, setRequestHeader 메소드는 open 메소드 다음에, send 메소드 전에 호출해야 한다. 다음과 같이 작성하면 된다.

1
2
3
4
5
6
xhr.open('POST', '/users');
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send({
name: "donald",
country: "United States"
});

setRequestHeader 메소드를 사용할 때, 인수는 다음과 같다.

  • 첫번째 인수: 자주 사용하는 Request Header인 Content-type 또는 Accept을 사용한다.
  • 두번째 인수: MIME 타입

예를 들어, 아래와 같은 코드를 보자.

1
xhr.setRequestHeader('Content-type', 'application/json');


‘Content-type’은 Request Body에 담아 전송할 데이터의 MIME-type을 지정할 때 사용한다.

MIME-type은 아래 테이블에 있는 타입들이며, 사용시에는 아래 서브타입처럼 작성한다.

타입 서브타입
text 타입 text/plain, text/html, text/css, text/javascript
Application 타입 application/json, application/x-www-form-urlencode
File 업로드하기 위한 타입 multipart/formed-date

Request Body에 담아 전송할 데이터의 MIME-type을 지정하는 예제 코드는 다음과 같다.

1
2
3
4
5
6
xhr.open('POST', '/users');
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send(JSON.stringify({
name: "donald",
country: "United States"
});


‘Accept’은 HTTP 클라이언트가 서버에 요청할 때, 서버가 센드백할 데이터의 MIME-type을 지정할 때 사용한다.

예를 들어, 아래와 같이 작성한다.

1
xhr.setRequestHeader('Accept', 'application/json');

만약 ‘Accept’ 헤더를 설정하지 않을 경우, send 메소드가 호출될 때, ‘Accept’ 헤더가 /와 함께 전송된다.
(/은 모든 MIME 타입을 의미한다.)

자세한 ‘Accept’에 대한 개념은 MDN에서 확인해보자.

클라이언트와 서버사이에서의 Request & Response Message는 다음과 같다.

HTTP Request and Resopnse Message
출처: HTTP Request and Resopnse Message


3. 서버로부터 받은 응답 처리하기


XMLHttpRequest 객체를 사용해서 Ajax 응답 처리에 대한 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
xhr.onreadystatechange = function (e) {
if (xhr.readyState === XMLHttpRequest.DONE) {
if(xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.log('Error!');
}
}
};


3-1. XMLHttpRequest.onreadystatechange 호출

XMLHttpRequest가 가지고 있는 readyState 프로퍼티가 변경(사용자로부터 이벤트 발생) 될 때마다, XMLHttpRequest가 가지고 있는 프로퍼티인 onreadystatechange(이벤트 핸들러)를 호출한다.

1
2
3
xhr.onreadystatechange = function (e) {
// readyState 프로퍼티가 변경될 때마다, 이 함수를 호출
}


3-2. XMLHttpRequest.readyState로 서버가 응답했는지 확인

1
2
3
if (xhr.readyState === XMLHttpRequest.DONE) {
// readyState가 완료되면, 이 함수를 호출
}

XMLHttpRequest.readyState의 값은 아래와 같다.

Value State Description
0 UNSENT XMLHttpRequest.open() 메소드 호출 이전
1 OPENED XMLHttpRequest.open() 메소드 호출 완료
2 HEADERS_RECEIVED XMLHttpRequest.send() 메소드 호출 완료
3 LOADING 서버 응답 중(XMLHttpRequest.responseText 미완성 상태)
4 DONE 서버 응답 완료

xhr.readyState의 값이 4(DONE)이면, 서버가 응답을 완료했다는 뜻이다.


3-3. XMLHttpRequest.status로 정상 응답인지 확인

1
2
3
4
5
if(xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.log('Error!');
}

응답코드가 200번 대 숫자면 정상 응답이므로, xhr.status가 정상적인 응답코드이면, 서버로부터 전송되는 데이터가 담겨 있는 xhr.responseText가 클라이언트로 전달된다.

REST API란 무엇인가?

REST API란?


REpresentational State Transfer의 약자로, 서버의 자원을 정의하고, 자원에 대한 주소를 지정하는 방법(표기법)을 말한다. 2000년, 아파치 HTTP 서버 프로젝트의 공동설립자인 Roy fielding(로이 필딩)에 의해 처음 소개가 되었는데, 이 분은 HTTP/1.0,1.1 스펙 작성에 참여하신 분이다.

그는 웹의 장점을 최대한 활용할 수 있는 Architecture로써 REST를 소개하면서, REST API 규칙을 만들었다. 이런 REST API 규칙을 잘 지킨 서비스 디자인을 “RESTful”하다고 표현한다. REST API는 HTPP 프로토콜을 정확히 의도에 맞게 활용하여 디자인하게 유도하기 때문에, 디자인 기준이 명확해지고, 의미적인 범용성을 지닌다. 즉, 서버가 이해하기 쉽게 자원에 대한 주소를 지정하는 표기법이 REST API이다.


REST API 구성 요소


REST API를 구성하는 것은 다음과 같이 3가지가 있다.

  • 자원(Resource)
  • 행위(Verb)
  • 표현(Representation)


자원(Resource)


자원(Resource)이란, 해당 소프트웨어가 관리하는 모든 것이 될 수 있다.
JSON, XML 등의 문서가 될 수 있고, 그림파일이 될 수도 있다.
즉, 어떤 데이터(문서, 파일, 비디오 등)를 말한다.

예를 들어, 서버 데이터베이스에 사용자들에 대한 정보가 들어가 있다면, 이 사용자들의 정보가 데이터이기 때문에, 자원(Resource)이 된다. 이때, 이 사용자들에 대한 데이터를 대표하는 이름을 users라고 해보자. 만약, 이 사용자들 중에서 어떤 한 명의 사용자에 대한 자원을 얻고자 한다면 어떻게 해야할까? 그럴때는, users/id 처럼, 사용자들 중 특정 id로 사용자를 구분해서 사용할 수 있다.

자원(Resource)은 HTTP URI로 표현한다. 예를 들어, http://localhost:4000/users/1 이런식으로 작성하며, 이 URI를 이용하여 원하는 자원(Resource)에 접근할 수 있다.


행위(Verb)


REST API에서 말하는 행위(Verb)는 자원에 대한 행위를 말한다. 즉, HTTP Method를 사용해서 자원을 얻거나, 만들거나, 변경하거나, 삭제하는 등의 행위를 할 수 있다.

HTTP Method 중 대표적으로 자주 사용되는 메서드는 다음과 같다.

  • GET : 서버 자원을 가져오고자 할 때 사용한다.(Retrieve: 모든/특정 자원을 조회)
  • POST : 서버에 자원을 새로 등록하고자 할 때 사용한다.(Create: 자원을 생성)
  • PUT : 서버의 자원을 새로 요청한 자원으로 변경하고자 할 때 사용한다.(Update: 자원을 갱신)
  • PATCH : 서버 자원의 일부만 수정하고자 할 때 사용한다.
  • DELETE : 서버의 자원을 삭제하고자 할 때 사용한다.(Delete: 자원을 삭제)

위 4가지(GET/POST/PUT/DELETE)를 이용해서 CRUD를 구현할 수 있다.


표현(Representation)


표현(Representation)은 자원에 대한 행위의 내용을 말하는데, 이때 내용은 서버에 요청할 때 무엇인가를 새로 생성하거나, 변경할 때 필요한 내용을 말한다. 이때, HTTP Message인 payload를 사용한다.

서버 자원에 무언가 새로운 것을 생성할 때, HTTP Method 중 POST와 함께 payload를 같이 요청한다. 예를 들어, 사용자들에 대한 정보가 있는 users에 새로운 사용자 정보를 생성하고 싶다면, 이 새로운 사용자에 대한 정보를 새로 만들어서 추가해줘야 하는데, 이것을 payload라고 한다.

1
2
3
4
5
6
7
POST http://localhost:4000/users/

{
"id": 1,
"name: "Ro",
"country": "Korea"
}

위 객체를 payload라고 하는데, 위 자원(http://localhost:4000/users/) 에 POST 방식으로 위 payload(객체)와 함께 서버에 요청을 해야한다.


REST API 중심 규칙


위와 같은 내용을 잘 정리한 것이 REST API 중심 규칙이다.
REST한 API를 설계하기 위한 중심 규칙은 대표적으로 2가지이다.


1. URI는 정보의 자원을 표현해야 한다.


URI는 정보의 자원을 표현하는데 중점을 두어야 하기 때문에, 어떤 행위를 나타내는 동사보다는 자원의 의미를 명확히 전달하기 위해 명사를 사용해야 한다.

id가 1인 사용자에 대한 자원을 얻고 싶다면, 다음과 같이 작성해야 한다.

1
GET /users/1

행위를 나타내는 다음과 같은 URI는 잘못된 방법이다.

1
2
GET /getUsers/1
GET /users/show/1


2. 자원에 대한 행위는 HTTP Method로 표현한다.


1
DELETE /users/1


REST API Architecture


REST API는 자원과 메서드만 보고 요청의 내용을 명확하게 알 수 있다는 것이 장점이다.

이런 REST API의 Architecture를 보면 다음과 같다.

REST API Architecture
출처: REST API Architecture

어떤 클라이언트(웹브라우저/안드로이드 앱/ios 앱)에서 서버에 요청을 할 때 HTTP 통신을 하고, HTTP Method를 사용하여 원하는 행위를 하여 서버로부터 응답을 받는다.


REST API 사용 예제


Ajax를 사용하여 REST API를 어떻게 사용하는지 알아보자.

사용자에 대한 정보인 users 데이터는 다음과 같다고 해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"users": [
{
"id": 1,
"name": "Ro",
"country": "Korea"
},
{
"id": 2,
"name": "John",
"country": "Canada"
},
{
"id": 3,
"name": "Doh",
"country": "China"
},
{
"id": 4,
"name": "Hitaro",
"country": "Japan"
}
]
}


1. GET


1-1. users 자원에서 모든 사용자의 정보를 가져온다.(모든 사용자)

1
GET http://localhost:4000/users

위와 같이 users에 대한 자원을 GET하게 되면 다음과 같이 모든 users에 대한 정보를 가져올 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"id": 1,
"name": "Ro",
"country": "Korea"
},
{
"id": 2,
"name": "John",
"country": "Canada"
},
{
"id": 3,
"name": "Doh",
"country": "China"
},
{
"id": 4,
"name": "Hitaro",
"country": "Japan"
}
]

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
var req = new XMLHttpRequest();
req.open('GET', 'http://localhost:4000/users');
req.send();

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 200) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};


1-2. users 자원에서 id가 1인 사용자의 정보를 가져온다.(특정 사용자)

1
GET http://localhost:4000/users/1

위와 같이 users 자원에서 id가 1인 사용자에 대한 자원을 GET하게 되면 다음과 같이 id가 1인 사용자에 대한 정보를 가져올 수 있다.

1
2
3
4
5
{
"id": 1,
"name": "Ro",
"country": "Korea"
}

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
var req = new XMLHttpRequest();
req.open('GET', 'http://localhost:4000/users/1');
req.send();

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 200) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};


2. POST

users 자원에 새로운 사용자의 정보를 생성한다.

1
2
3
POST http://localhost:4000/users
"Content-Type: application/json"
'{"name": "donald", "country": "United States"}'

새로운 사용자의 정보를 생성하기 위해서는 payload가 필요하며, 위와 같이 Content-Type 등을 추가로 작성해야 한다.

1
2
3
4
5
{
"name": "donald",
"country": "United States",
"id": 5
}

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var req = new XMLHttpRequest();
req.open('POST', 'http://localhost:4000/users');
req.setRequestHeader('Content-type', 'application/json');
req.send(JSON.stringify({
name: "donald",
country: "United States"
}));

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 201) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};


3. PUT

users 자원에서 새로 추가된 name을 jack으로 변경한다.

1
2
3
PUT http://localhost:4000/users/5
"Content-Type: application/json"
'{"name": "jack", "country": "United States"}'

PUT은 특정 id에 대한 어떤 정보를 변경할 때, payload에 모든 정보를 포함해서 보내준다.

1
2
3
4
5
{
"name": "jack",
"country": "United States",
"id": 5
}

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var req = new XMLHttpRequest();
req.open('PUT', 'http://localhost:4000/users/5');
req.setRequestHeader('Content-type', 'application/json');
req.send(JSON.stringify({
name: 'jack',
country: "United States"
}));

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 200) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};


4. DELETE

users 자원에서 id가 5인 사용자를 삭제한다.

1
DELETE http://localhost:4000/users/5

사용자의 id까지 포함해서 DELETE 해야한다.

1
{}

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
var req = new XMLHttpRequest();
req.open('DELETE', 'http://localhost:4000/users/5');
req.send();

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 200) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};

트랜스파일링을 위한 typescript 개발환경 구축 방법

Typescript와 트랜스파일링


자바스크립트의 문제점을 보완하기 위해 typescript을 사용한다. 그러나, typescript으로 작성한 파일은 브라우저에서 동작하지 않는다. 따라서, typescript로 작성한 파일을 자바스크립트로 변환해야 하는데, 이를 트랜스파일링 또는 컴파일이라고 한다. 트랜스파일링을 하기 위해서는 typescript 컴파일러를 설치하여 사용하는 typescript 개발환경을 구축해야한다.




typescript 컴파일러 설치 방법


다음과 같이 typescript를 전역에 설치한다.

1
npm install -g typescript


설치가 완료되면, typescript의 버전 체크를 하여, typescript 컴파일러 설치가 제대로 되었는지 확인한다.

1
tsc -v




typescript 컴파일러로 트랜스파일링 하기


typescript로 작성된 파일(.ts)을 자바스크립트 파일로 트랜스파일링 하기 위해서는, 위에서 설치한 typescript 컴파일러(tsc)를 사용한다.


1개의 파일 트랜스파일링 하기


아래의 코드를 작성하고, 확장자를 .ts로 하는 typescript 파일로 만든다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Cafe {
private name: string;

constructor(name: string) {
this.name = name;
}

greeting() {
return "Welcome to" + this.name;
}
}

const cafe = new Cafe('Starbucks');
console.log(cafe.greeting());


위 typescript 파일을 트랜스파일링하여 자바스크립트로 만들기 위해서는 아래의 명령어를 작성하면 된다.

1
tsc cafe

tsc 다음에 위 파일(cafe.ts)의 이름(cafe)을 입력하면 된다.


그러면, 트랜스파일링이 되어, 또 하나의 자바스크립트 파일이 생성된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"use strict";
exports.__esModule = true;
var Cafe = /** @class */ (function () {
function Cafe(name) {
this.name = name;
}
Cafe.prototype.greeting = function () {
return "Welcome to" + this.name;
};
return Cafe;
}());
exports.Cafe = Cafe;
var cafe = new Cafe('Starbucks');
console.log(cafe.greeting());

그런데, 트랜스파일링된 자바스크립트 파일은 ES3 버전으로 생성되는데, 이는 트랜스파일링해서 생성되는 기본 버전이 ES3이기 때문이다.


target 컴파일 옵션을 사용해서 원하는 버전으로 트랜스파일링 하기


만약 원하는 버전으로 트랜스파일링 하고 싶다면, typescript 컴파일 옵션중 –target또는 -t를 사용하면 된다.

1
tsc cafe -t es6


ES6 버전은 아래와 같이 나온다.

1
2
3
4
5
6
7
8
9
10
class Cafe {
constructor(name) {
this.name = name;
}
greeting() {
return "Welcome to" + this.name;
}
}
const cafe = new Cafe('Starbucks');
console.log(cafe.greeting());

그러면, 처음에 생성된 ES3 버전의 자바스크립트 파일이 ES6 버전의 자바스크립트 파일로 코드의 내용이 변경된다.


2개의 파일 트랜스파일링 하기


2개의 typescript 파일을 작성하여, 트랜스파일링을 해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// cafe.ts
export class Cafe {
protected name: string;

constructor(name: string) {
this.name = name;
}

greeting() {
return "Welcome to" + this.name;
}
}

const cafe = new Cafe('Starbucks');
console.log(cafe.greeting());

1
2
3
4
5
6
7
8
9
10
11
12
// bakery.ts
import { Cafe } from './cafe';

class Bakery extends Cafe {
bake(): string {
return `${this.name} is baking bread. Wow!!`;
}
}

const bakery = new Bakery('Starbucks');
console.log(bakery.greeting());
console.log(bakery.bake());


위 두개의 typescript 파일들을 트랜스파일링 하기 위한 명령어를 작성하면 된다.

1
tsc cafe bakery

그러면, 두개의 typescript 파일들이 두개의 자바스크립트 파일로 트랜스파일링 된다.


3개 이상의 파일 트랜스파일링 하기


3개 이상의 모든 typescript 파일들을 한번에 트랜스파일링 하기위해서는 와일드카드(*)를 사용해야 한다.

1
tsc *.ts


자동으로 트랜스파일링 하기


typescript 컴파일 옵션 중 —watch 또는 -w 를 사용하면, 파일의 내용이 변경되었을 때, 이를 감지하여 자동으로 그 파일이 트랜스파일링 된다.

1
tsc bakery —watch

typescript란 무엇인가?

typescript란 무엇인가?


typescript는 자바스크립트에서 좀 더 확장된 언어로, 자바스크립트의 문법을 포함하면서 자바스크립트가 가지고 있는 문제를 보완하기 위한 문법을 가진 언어이다. 2012년에 마이크로소프트에서 발표한 오픈소스로써, C#을 개발한 아네르스 하일스베르가 개발하였다.

Typescript Superset

위 그림과 같이, 타입스크립트는 ES5, ES6를 모두 포함하는 자바스크립트의 상위집합이기 때문에, 타입스크립트에서 기존의 자바스크립트 문법을 그대로 사용할 수 있다.

또한, 타입스크립트는 아직 ECMAScript 표준에 포함되지는 않았지만(2018년 7월 기준), ECMAScript의 업그레이드에 따른 새로운 기능(스펙)을 계속 추가하기 때문에, ECMAScript의 표준을 따라가는 것처럼 보인다.




typescript를 왜 사용할까?


C나 JAVA와 같은 C-family 언어와는 다른 자바스크립트만의 특성이 있다.

  • 프로토타입 기반 객체지향 언어
  • 스코프와 this
  • 동적 타입 언어

이와 같은 특성들은 클래스 기반 객체지향 언어(C, JAVA 등)에 익숙한 개발자에게는 혼란스럽다.
또한, 할당하는 값에 따라 타입이 바뀌는 문제도 있어, 꼭 타입 체크를 해줘야 하는 점도 있다.

이런 문제들을 보완하기 위해, 타입스크립트에는 클래스, 정적 타이핑 등이 포함되어있다.

자바스크립트의 프레임워크인 Angular는 주력 언어로 타입스크립트를 채용했기 때문에, Angular를 사용하는 개발자는 타입스크립트를 이해하는 것이 필수적이다. 즉, Angular는 타입스크립트 뿐만 아니라, 자바스크립트, Dart 등으로도 작성이 가능하지만, Angular 사이트에 나와있는 문서나 커뮤니티 활동에서도 가장 많이 사용되고 있어, Angular를 사용하고 싶다면 타입스크립트를 아는 것이 좋다.

hexo 블로그 포스트 작성 및 배포하는 방법

hexo 블로그에 포스트 작성 및 배포하는 방법



새 포스트 작성을 위한 글제목 명령어를 입력한다.


1
hexo new option 글제목

이 명령어를 작성하게 되면, 글제목 폴더와 글제목.md 파일이 만들어진다.
이미지는 글제목 폴더에서 관리하고, 글의 내용은 글제목.md 파일에서 관리한다.
만약, 글제목 폴더가 만들어지지 않는다면, _config.yml에서 post_asset_folder: true를 추가하면 된다.

이때, option에는 ‘post’ 또는 ‘draft’가 올 수 있다.


만약 작성한 글을 바로 배포하려면 ‘post’라고 쓴다.

1
hexo new post 글제목


바로 배포하지 않고, 초안으로 보관만 하려고 할 때는 ‘draft’라고 쓴다.

1
hexo new draft 글제목




draft 글을 배포하기 위해서 _posts 폴더로 이동시킨다.


‘draft’를 사용하여 명령어를 입력하게 되면, source/_drafts 폴더에 저장된다.
이 폴더에 저장이 되면, 배포 대상에서 제외되기 때문에, 원래 사용하던 ‘hexo server’로는 확인할 수 없고 ‘–draft’라는 옵션을 추가해여 로컬 서버에서 확인이 가능하다.

1
hexo server --draft


초안이 다 완성이 되어 배포를 하고 싶을 경우, 해당 파일과 폴더가 source/_posts 폴더에 있어야 한다.
이때, 아래와 같은 명령어를 입력하면 해당 파일과 폴더과 source/_posts로 이동하게 된다.

1
hexo publish post 글제목




_posts 폴더에 있는 글을 블로그에 배포한다.


최종적으로, source/_posts안에 있는 모든 글들을 배포하기 위해 아래의 명령어를 입력한다.

1
hexo generate --deploy

hexo를 이용해서 블로그를 설치하는 방법

hexo를 이용해서 블로그 설치하기


hexo 설치하기


hexo 설치하기 위해서는 기본적으로 설치해야할 것이 2가지가 있다.


위 2개를 설치했다면, 먼저 npm을 사용해서 hexo를 설치해야 한다.
나같은 경우에는 git을 관리하는 dev 폴더안에서 설치했다.

1
npm install hexo-cli -g


본인이 원하는 이름(나의 경우: myblog)으로 hexo init을 하고, npm을 설치한다.

1
2
3
hexo init myblog
cd myblog
npm install


hexo 서버를 통해 구축된 hexo 기본 사이트를 확인한다.

1
hexo server

위와 같이 따라서 설치하면 기본적인 hexo 블로그를 로컬 호스트로 구축을 할 수 있다.




Github에서 제공하는 github.io로 사이트 구축하기


hexo 블로그를 사용하기 위해서는 깃헙에서 제공하는 블로그용 깃헙사이트가 필요하다.


Github에서 블로그용으로 만들 repo를 생성한다.
repo를 username.github.io 이런식으로 만들면 된다.


내 컴퓨터로 클론한다.
나같은 경우 dev 폴더안에서 클론했다.

1
git clone https://github.com/cheonmro/cheonmro.github.io.git




_config.yml에서 세팅하기


실제 사이트 url로 배포하기 위해 기본적인 세팅이 필요하다.
세팅 관련해서는 항상 _config.yml에서 한다.

앞으로 hexo 블로그를 이용해서 작성할 모든 내용들을, 위에서 생성한 블로그용 깃헙에서 관리를 할 것이기 때문에, 아래와 같이 type에 git으로 하고, repository에 자신의 블로그용 깃헙 주소를 작성한다.

1
2
3
4
deploy:
type: git
repository: https://github.com/cheonmro/cheonmro.github.io
branch: master




구축한 사이트 배포하기


지금까지 구축한 hexo 블로그를 배포(deploy)한다.

1
hexo deploy

위 명령어를 실행하게 되면, 자동으로 commit, push가 되어, 깃헙과 웹사이트(블로그)에 파일들이 generate되어, 기본적인 사이트 구축이 완성되게 된다.(웹사이트 자체를 배포할 때 사용한다.)


위에서 구축한 사이트를 직접 확인한다.

1
https://cheonmro.github.io/




hexo 블로그의 테마를 바꾸는 방법


위와 같이, 기본적인 hexo 블로그 설치는 간단한다.
기본적으로 themes 폴더안에 있는 landscape 테마를 바탕으로한 기본 사이트가 구축된다.

hexo 블로그에서 테마를 바꾸고 싶을 때는, 원하는 테마를 themes 안에 가져오고, _config.yml에서 theme의 이름만 바꿔주면 된다.

원하는 테마를 themes 폴더안으로 git clone 한다.
(나같은 경우는 hexo-theme-hipaper 테마를 사용했다.)

1
git clone https://github.com/iTimeTraveler/hexo-theme-hipaper.git


_config.yml에서 theme 옆에 이름을 새로 변경할 테마의 이름으로 바꾼다.

1
theme: hexo-theme-hipaper


기존 테마를 지우고, 새로 변경할 테마로 바꾸려면, hexo 블로그를 다시 배포(deploy)해야한다.

1
hexo deploy

위와같이 하면, Github의 파일들이 새로 변경할 테마의 내용들로 바뀌고, 사이트 또한 새롭게 변경된다.


만약, “Deployer not found: git” 이라는 에러가 난다면, deployer를 설치하면 된다.

1
npm install hexo-deployer-git --save


그리고, 다시 배포한다.

1
hexo deploy