-
Notifications
You must be signed in to change notification settings - Fork 0
[실습] JS ES6를 활용하여 Blog Keep 목록 만들기
HYUNSANG HAN edited this page Sep 2, 2019
·
3 revisions
-
npm init
: package.json 만들어주는 역할 -
npm install webpack --save-dev
: 웹팩 설치하는 역할.--save-dev
를 붙이면 package.json에 심어지게 된다. 개발모드일 땐-dev
를 붙여야 하고, 아니면 생략가능하다. - package.json의 scripts 내부에
"build": "webpack"
라고 넣기 : 원래는 node_modules에서 직접 찾아 webpack을 실행해줘야 하는데, package.json의 scripts에 정의해서 실행하기 편하도록 명령어를 만들 수 있는 것임 -
vi webpack.config.js
: webpack.config.js 작성하기. 그러고나서 wq로 닫으면 IDE에서도 이 파일을 가시적으로 확인 가능
var path = require('path');
module.exports = {
entry: './src/index.js', // bundle로 묶일 대상의 js파일명들
output : {
filename: 'bundle.js', // bundle의 결과로 만들어질 js파일명
path: path.resolve(__dirname, 'dist') // bundle의 결과로 만들어질 js파일이 생성될 경로
},
module: {
rules: [{ // 추후 여기에 규칙을 추가하는 것도 가능
}]
}
}
- npm run build : 웹팩을 실행시키기 => 그 결과로 bundle.js가 만들어진다!
- src 디렉토리를 만든 후 index.js를 그 안에 만들어주기. 테스트를 위해 간단하게나마 js 코드를 작성해둠.
- index.html(보여질 화면을 위한 html파일)을 만들고, 아래와 같이 script를 파일 후반부에 추가하여 bundle.js 불러오기
<script src="./list/bundle.js"></script>
- html파일을 브라우저에서 열기 => html파일의 내용과 더불어 console창에 "성공이다"가 찍히게 됨 (= 셋팅 완료)
-
npm install babel-preset-env --save-dev
: 바벨 설치 -
npm install babel-loader @babel/core --save-dev
: 강좌에서는 이에 대한 설치를 언급하지 않았지만, 1만 설치할 경우 build가 제대로 되지 않는 현상이 있어서 구글링했고 이를 추가로 설치하여 오류를 해결했음 - 아래와 같이 babel 관련하여 webpack.config.js에 설정 추가 (참고로, rules 내부에 추가되었음. 그 외에는 변동 없음)
var path = require('path');
module.exports = {
entry: './src/index.js',
output : {
filename : 'bundle.js',
path : path.resolve(__dirname, 'dist')
},
module : {
rules : [{
test : /\.js$/, // 파일이름 정규표현식
include : path.resolve(__dirname, 'src'), // src디렉토리에 있는 파일들을 대상으로 번들링하겠다는 뜻
use : {
loader : 'babel-loader',
options : {
presets : [
['@babel/preset-env', { // 원래 강의에서는 'env'를 넣으라고 했으나, 모듈 import가 인식되지 않길래 구글링하여 '@babel/preset-env'로 대체함으로써 문제해결함
'targets' : {
'browsers' : ["last 2 versions", "ie 9"] // 브라우저별 최근 2개버전, 그리고 명시적으로 ie 9도 타겟으로 트랜스파일링을 해달라는 뜻. 이에 따라, 필요한 플러그인들을 알아서 설치해줌.
},
'debug' : true // 참고로, 이건 없어도 상관없음. 다만, 이게 있으면 debug 결과가 콘솔에 찍힘
}]
]
}
}
}]
}
}
- index.js에 ES6문법의 코드를 작성(테스트해보기 위함)
-
npm run build
: webpack 실행. => build가 되어 bundle.js가 생성됨. 들어가보면 ES6를 활용해서 작성했던 코드가 ES5로 변환되어 있는 것을 볼 수 있음.
- package.json의 scripts안에
"devserver": "webpack-dev-server --inline"
추가 : 참고로 여기서 --inline은 전체 화면을 새로고침해주는 옵션(사실은, 디폴트가 inline이라서 사실 굳이 써줄 필요는 없음) - webpack.config.js의 output안에
publicPath : '/dist'
를 설정해줌.(참고로 여기서 dist는 bundle이 담기는 디렉토리명임) devserver는 public path를 중요하게 보기 때문이라고 하며, 여기까지 설정하고나면 js파일을 수정하자마자 업데이트되어 브라우저에 반영되게 됨. - src디렉토리에 안에 css디렉토리를 만들고 index.css만들기
- index.html에
<link rel="stylesheet" href="./src/css/index.css">
를 추가하여 css파일 불러오기 (참고로, 웹팩로더에 css로더를 설치하면 css파일을 위와같은 방식이 아니라 js에서 import형태로 불러올 수도 있음) - src 아래에 대략 이런 식으로 main.js를 만들기 (import가 잘 되는지 테스트용)
class Blog {
constructor() {
console.log('Blog is stated!');
}
}
export default Blog;
- index.js에서 이걸 main.js의 이 class를 import해오기 (참고로 export default는 ES6에 추가된 것인데, 웹팩설정을 해두면 디폴트로 제공되는 기능이라 쓸 수 있음)
import blog from './main.js';
const myBlog = new blog();
-
npm run devserver
: localhost:8080에서 코드가 실시간으로 실행되는 것을 확인 가능
index.html 파일은 아래와 같다. main.js에서 querySelector를 이용하므로, 혹시라도 이거 읽는 분 main.js 읽을 때 참고하시라고 올려둔다.
<!--index.html-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mini-pjt</title>
<link rel="stylesheet" href="./src/css/index.css">
</head>
<body>
<section class="controller">
<button class="load-btn">Load</button>
</section>
<section class="blog-list">
<h3>Total List</h3>
<ul>
</ul>
</section>
<section class="keep-list">
<h4>Keep List</h4>
<ul>
</ul>
</section>
</body>
<script src="./dist/bundle.js"></script>
</html>
이제, main.js를 보자. 참고로 index.js에서는 main.js를 import해오기만 했고, 실질적인 js코드는 main.js에 있다고 보면 된다.
// main.js
class Blog {
constructor() {
this.setInitVariables(); // 변수를 정의해주는 것임. 정확히는, blog-list라는 class의 section 하위 ul은 두번 이상 쓰이므로 재활용할 수 있도록 이걸 첫 load 시에 변수로 set해주려는 것임.
this.registerEvents(); // 클릭이벤트들을 정의해주는 것임.
this.keptSet = new Set(); // Keep이 눌린 블로그를 모아둘 곳임. 중복을 불허하기 위해 Set 자료형을 사용.
}
setInitVariables() {
this.blogList = document.querySelector(".blog-list > ul"); // blog-list라는 class의 section 하위 ul을 선택해줌.
}
registerEvents() {
const startBtn = document.querySelector(".load-btn"); // load 버튼을 선택해줌.
const dataURL = "/data/data.json"; // 원래는 외부API의 response를 받아오는 걸로 강의에는 나오지만, API URL이 바뀌어 이와 같이 local의 data를 가져오는 걸로 코드가 추후 변경되었음
startBtn.addEventListener("click", () => {
this.setInitData(dataURL); // dataURL에 있는 data를 가져오는 것
});
this.blogList.addEventListener("click", ({target}) => { // 여기서 Destructuring이 쓰였다. (event객체를 받아도 됐었지만, 다 받는 것은 불필요하므로 {target}만 받은 것.)
const targetClassName = target.className;
if(targetClassName !== "keep" && targetClassName !=="unkeep") return; // 사실 논리상 안써줘도 그만인 코드지만, 이를 써주지 않으면 '킵해두기'보다 상위 노드를 클릭한 경우에도 EventListener가 작동하는 불편한 점이 있을 수 있음
const postTitle = target.previousElementSibling.textContent; // 참고로 textContent 대신 innerText라고 써줘도 무방
if(targetClassName === "unkeep") { // 킵취소를 누르는 경우
target.className = "keep";
target.innerText = "킵해두기";
this.keptSet.delete(postTitle);
} else { // 킵해두기를 누르는 경우
target.className = "unkeep";
target.innerText = "킵취소";
this.keptSet.add(postTitle);
}
this.updateKeptList(); //내 Keep 목록 뷰에 추가.
//dispatcher.emit("CHANGE_LIKE_LIST", {'title' : this.keptSet}) // <= 만약 이렇게 redux스럽게 코드를 작성한다면 윗줄 대비 의존성이 줄어들기 때문에 더 좋은 코드가 될 여지가 있다는 설명의 예시 코드
});
}
updateKeptList() {
const ul = document.querySelector(".keep-list > ul");
let KeptTotal = ""; // Keep리스트를 모아둘 곳
this.keptSet.forEach ( (contentTitle) => {
KeptTotal+= `<li> ${contentTitle} </li>`;
})
ul.innerHTML = KeptTotal; // forEach를 통해 차곡차곡 모아둔 Keep 리스트를 한번에 innerHTML에 넣음
}
setInitData(dataURL) {
this.getData(dataURL, this.insertPosts.bind(this)); // bind(this)를 써주지 않으면 this가 다르게 인식됨
}
getData(dataURL, fn) { // load했을 때 data를 가져오는 것
const oReq = new XMLHttpRequest();
oReq.addEventListener("load", () => {
const list = JSON.parse(oReq.responseText).body;
fn(list); // 여기서 fn은 사실 insertPosts였던 것.
});
oReq.open('GET', dataURL);
oReq.send();
}
insertPosts(list) { // load하여 가져온 data를 .blog-list > ul 내에 그려주는 것
list.forEach((content) => {
this.blogList.innerHTML += `
<li>
<a href=${content.link}> ${content.title} </a>
<div class="keep">킵해두기</div>
</li>
`;
})
}
}
export default Blog;
- 참고로, debugger라는 것을 코드 내에 끼워놓고 devserver를 run하여 브라우저를 띄우면 그 시점에서 이것저것 console에서 디버깅해볼 수 있다. this가 달라진 것 같다면 debugger를 통해 확인해보자!