두개의 화면을 가진 웹 앱

 

SPA = 하나의 어플리케이션이 여러개의 화면을 가지고 화면을 전환하면서 보여주는 방식 (라우팅)

 

const container = document.querySelector('#root');
const ajax = new XMLHttpRequest();
const content = document.createElement('div');
const NEWS_URL = 'https://api.hnpwa.com/v0/news/1.json'
const CONTENT_URL = 'https://api.hnpwa.com/v0/item/@id.json';

ajax.open('GET', NEWS_URL, false); // method, Url, async
ajax.send();

const newsFeed = JSON.parse(ajax.response);
const ul = document.createElement('ul');

window.addEventListener('hashchange', function(){
    const id = location.hash.substring(1);
    
    ajax.open('GET', CONTENT_URL.replace('@id', id), false);
    ajax.send();

    const newsContent = JSON.parse(ajax.response);
    const title = document.createElement('h1');

    title.innerHTML = newsContent.title;

    content.appendChild(title);    
});

for(let i=0; i<newsFeed.length; i++){
    const li = document.createElement('li');
    const a = document.createElement('a');
    
    a.href = `#${newsFeed[i].id}`;
    a.innerHTML = `${newsFeed[i].title} (${newsFeed[i].comments_count})`;
    
    li.appendChild(a);
    ul.appendChild(li);
}

container.appendChild(ul);
container.appendChild(content);

만든 해커뉴스 화면에서 해당 타이틀의 글을 클릭하면 ajax를 통해 각 해커뉴스 id에 관한 정보를 가져오는 상세 기능을 구현했다. 앵커 태그를 클릭할 때, 해시 값이 바뀌는 이벤트를 통해 해당 글의 id 값으로 라우팅 처리하는 식의 기능을 구현할 수 있다.

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 9일차  (0) 2022.02.01
패스트캠퍼스 챌린지 8일차  (0) 2022.01.31
패스트캠퍼스 챌린지 6일차  (0) 2022.01.29
패스트캠퍼스 챌린지 5일차  (0) 2022.01.28
패스트캠퍼스 챌린지 4일차  (0) 2022.01.27

parcel 번들러를 이용한다.

npm install parcel 

 

- 기본 html 구조

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HN client</title>
</head>
<body>
    <noscript>
        You need to enable JavaScript to run this app.
    </noscript>
    <div id="root">
    </div>
    <script src="app.js" type="module"></script> <!-- js파일을 module로 사용 -->
</body>
</html>

번들링 작업을 하게되면 dist 폴더안에 app.xxxx.js 형태로 파일이 생성된다

 

 

>parcel index.html

parcel 번들러를 이용해서 번들링 작업을 한다.

 

 

 

서버에서 데이터를 가져오는 도구 = ajax

 

const ajax = new XMLHttpRequest(); // ajax
const NEWS_URL = 'https://api.hnpwa.com/v0/news/1.json'

ajax.open('GET', NEWS_URL, false); // method, Url, async
ajax.send();

const newsFeed = JSON.parse(ajax.response); // JSON을 Object로 파싱작업
const ul = document.createElement('ul'); // 태그 생성 

for(let i=0; i<newsFeed.length; i++){
    const li = document.createElement('li');
    li.innerHTML = newsFeed[i].title;
    ul.appendChild(li);
}

document.querySelector('#root').appendChild(ul);

해커뉴스 사이트에서 입력데이터를 가져온다(ajax)

가장 기본적인 입력 - 처리 - 출력의 형태

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 8일차  (0) 2022.01.31
패스트캠퍼스 챌린지 7일차  (0) 2022.01.30
패스트캠퍼스 챌린지 5일차  (0) 2022.01.28
패스트캠퍼스 챌린지 4일차  (0) 2022.01.27
패스트캠퍼스 챌린지 3일차  (0) 2022.01.26

Node.js & npm

 

node.js = V8엔진 (JavaScript를 브라우저 외에 다른 환경에서 실행 시킬 수 있다)

 

npm = 어떤 기능을 하는 소프트웨어를 설치하고 사용할 수 있게 해준다

 

https://www.npmjs.com/

 

npm

Bring the best of open source to you, your team, and your company Relied upon by more than 11 million developers worldwide, npm is committed to making JavaScript development elegant, productive, and safe. The free npm Registry has become the center of Java

www.npmjs.com

 

npmjs.com에 들어가면 node.js 환경에서 사용할 수 있는 라이브러리를 설치하거나 또 그러한 소프트웨어를 만든다면 npm에 등록할 수 있다.

 

npm에서 colors라는 라이브러리를 설치했다.

 

콘솔의 색깔을 바꿀 수 있음

 


 

클라이언트 앱

 

어플리케이션의 본질: 입력 데이터를 가지고 출력 데이터로 변환하는 과정

 

입력 - 처리 - 출력

 

입력: 서버(해커뉴스 API)

처리: 어플리케이션

출력: UI화면(tailwindCss 라이브러리)

 


 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 7일차  (0) 2022.01.30
패스트캠퍼스 챌린지 6일차  (0) 2022.01.29
패스트캠퍼스 챌린지 4일차  (0) 2022.01.27
패스트캠퍼스 챌린지 3일차  (0) 2022.01.26
패스트캠퍼스 챌린지 2일차  (0) 2022.01.25

JavaScript & TypeScript

 

JavaScript는 초기 HTML을 조작하는 언어로써 처음엔 보잘것 없었지만 웹이 빠르게 발전하고 변화함에 따라 같이 유명해지고 변화에 발 맞춰 살아남았다고 볼 수도 있다. 결론적으로 지금은 여러방면으로 사용하는 언어가 되었는데 TypeScript는 왜 나왔을까 ?

 

TypeScript는 JavaScript의 슈퍼셋이다. TypeScript는 JavaScript가 지원하는 모든 기능을 지원하기 때문인데 왜 그런 방향으로 갔을까 ? 프로그래밍 언어의 좋고 나쁨을 떠나서 현재 웹에서 JavaScript는 유일한 언어이고 그렇기 때문에 JavaScript를 대신한다라는 개념보다 공생하는 개념이 훨씬 전략적으로 좋을 것이라 생각한다. 

 

TypeScript가 JavaScript라는 언어와 공생하는 방법은 JavaScript가 가지고 있지 않은 부분(타입, 형)을 메꾸는 방식이다 JavaScript는 언어의 특성 상 Type(형)이라는 것이 없기 때문에 TypeScript는 JavaScript가 가진 모든 기능을 지원하면서 Type을 명시적으로 지정할 수 있는 언어인것이다.


예를 들어

type Centimeter = number;
type RainbowColor = 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'indigo' | purple

let age = 10;
let weight:number = 80;
let height:Centimeter = 176;
let color:RainbowColor = 'orange';

color = 'black' // error

타입을 지정하게되면

1) 해당하는 데이터가 어떤 용도나 타입으로 사용되는지 알 수 있다.

2) 타입과 맞지 않은 데이터가 있을 시 오류가 발생한다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 6일차  (0) 2022.01.29
패스트캠퍼스 챌린지 5일차  (0) 2022.01.28
패스트캠퍼스 챌린지 3일차  (0) 2022.01.26
패스트캠퍼스 챌린지 2일차  (0) 2022.01.25
패스트캠퍼스 챌린지 1일차  (0) 2022.01.24

모던 자바스크립트와 개발 환경

 

Node.js와 NPM의 등장으로 인해 FE의 개발환경은 급변했다.

 

프론트엔드 개발 환경이 복잡할 수 밖에 없는 이유 ? :웹 앱의 규모가 굉장히 커지고 복잡해짐

 

JavaScript의 디자인은 단순히 HTML을 조작하기 위한 언어였지만 ES2015부터 모듈 스펙을 지원하기 시작한다. 모듈 스펙은 파일과 파일간의 어떤 기능을 사용하기 위해 어떤 파일의 기능을 해당 파일로 불러들여서 사용하는 것을 말한다. (import export)

 

모듈 스펙을 사용하는 경우는 예를들어 JavaScript를 사용하기 위해선 HTML 파일의 <script> 태그를 사용하여 로딩하는데 js파일의 갯수가 대량이 되어버리면 스크립트 태그를 그 만큼 작성해야 한다. 때문에 운영하는데도 불편하고 또 문제점이 생길수 있다.

 

그렇기 때문에 HTML의 <script>가 아닌 import, export를 사용하면 되는데 이러한 문법은 현실적으로 2가지 문제가 있다.

 

첫 번째는 브라우저 호환성 문제이다. 사용자들이 어떤 브라우저의 어떤 버전을 사용할지 모르기 때문에 브라우저의 호환성을 최대한 넓게 가져가야 한다. 두 번째는 최신 문법을 사용하려 하는 경향이다. 프로그래밍 언어의 문법은 차차 발전하고 이전 문법의 좋지 않은 관습이나 불편한 것들은 사라지거나 변경되어 더 좋은 문법으로 나타나는데 이 또한 브라우저 호환성 문제가 더욱 생기기 마련이다.

 

따라서 이런 문제들을 해결하기 위해 엔지니어링이 시도가 된다. 엔지니어링이란 예를 들어 node.js를 보면 브라우저 뿐만 아니라 일반 데스크탑, PC 서버 등에서 JavaScript를 실행할 수 있도록 해주는 환경이다. JavaScript 개발자들이 JavaScript로 다양한 툴들을 만들고 그것들을 배포하기 시작했다. 그 배포된 툴들은 npm을 통해서 그것을 사용하고자 하는 프로젝트에 불러다가 쓰기 수월해졌다.

 

번들러는 시작되는 자바스크립트 파일을 하나 지정하면 그 파일을 통해 다른 자바스크립트 파일을 불러와서 그렇게 불러진 자바스크립트 파일을 하나로 만들어 주는 것을 의미한다. 브라우저는 그렇게 하나로 만들어진 파일만을 읽어와서 수 많은 파일들을 실행한 결과를 가져올 수 있다.

 

결국 여러개의 파일을 하나로 만들어주는 번들러라는 프로그램이 나왔고 그 번들링이라는 작업으로 인해 모듈을 부르는 스펙을 못 쓰던 상황에서 모듈 스펙을 쓸 수 있게 되었고 파일을 하나로 관리할 수 있어 HTML을 운영하기도 현실적으로 쉬워졌다. 

 

또한, 번들러는 자바스크립트 파일 뿐만 아니라 번들링을 하는 과정에 있어 파일 용량을 위한 주석제거나 이미지 파일의 용량이 일정 이상이되면 압축을 통한 이미지 최적화, 소스 파일의 어글리파이 작업등을 수행할 수 있다.

 

이러한 기능들을 추가하다보니 번들러는 점점 커지고 웹 앱의 규모가 커짐으로 이어졌다.

 

트랜스파일링이란 내가 작업한 프로그래밍 언어를 브라우저가 이해할 수 있는 자바스크립트 언어로 변환 하는것. 개발자는 JavaScript의 최신 버전으로 개발하고 그러면서 발생할 수 있는 브라우저의 호환성 문제는 트랜스 파일러를 통해 해결할 수 있다. (ex. Babel, TypeScript)

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 6일차  (0) 2022.01.29
패스트캠퍼스 챌린지 5일차  (0) 2022.01.28
패스트캠퍼스 챌린지 4일차  (0) 2022.01.27
패스트캠퍼스 챌린지 2일차  (0) 2022.01.25
패스트캠퍼스 챌린지 1일차  (0) 2022.01.24

JavaScript의 변천사

 

netscape(firefox의 전신)에서 LiveScript 탄생: html을 조작하기 위한 언어

공식명칭: EcmaScript

 

JavaScript는 Adobe의 전성기 시절에는 별 다를것 없이 있다가 Adobe가 점점 사장되는 시기에 2015년에 버전 5.0, ES2015가 나오면서 현대의 모던 자바스크립트가 되었다.

 

ES5가 모던 자바스크립트의 가장 주도적인 버전이라고 칭하는데, 그 이유는 ES6, ES7, ES8 등으로 버전이 업그레이드 되었지만 해당 버전을 지원하지 않는 브라우저도 많기 때문에 최신 버전으로 개발하였을 때, 모든 사용자들에게 동작하는 웹앱을 만들기 어렵다.

 

그리하여 트랜스파일러(Babel, typescript 등)를 사용하면 높은 버전으로 개발하고 5.0 버전으로 변환한 후에 브라우저에서 동작시킨다.

 

typescript는 JavaScript의 슈퍼셋으로 모든 JavaScript의 기능을 지원한다.

 

 


 

웹 앱의 구성요소: HTML, CSS, JavaScript

브라우저(런타임 환경): 웹앱을 실행시킴

node.js(런타임 환경): 웹앱을 실행시킴

 

웹 서버에서 HTML 파일을 브라우저에 전송시키고 브라우저는 해당 HTML을 해석해서 화면에 UI를 그리고 난 후 JavaScript가 실행된다. JavaScript는 HTML을 조작할 수 있는데 그렇다는건 브라우저에서 HTML 파일에 작성된 UI를 화면에 그리고 난 후에도 추가적으로 JavaScript로 HTML을 또 그릴 수 있다.

 

최초의 HTML에 내용이 거의 없고 상황에 따라 JavaScript로 필요한 UI를 만들어 내는 방식을 CSR(Client Side Rendering)이라고 하고 웹서버에서 HTML이 만들어져서 브라우저로 전송되는 방식을 SSR(Server Side Rendering)이라고 한다.

 

어떤 웹 앱이던 CSR과 SSR 형식으로 개발 할 수 있다. 해당하는 앱의 성격에 맞게 렌더링을 하도록 개발하는 것이 개발자의 역할이다. 

 

다른 구성요소: HTML, CSS를 제외한 그래픽 시스템 (canvas 등) 미디어파일, 웹 워커, 웹 어셈블리

 

 

 

 

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 6일차  (0) 2022.01.29
패스트캠퍼스 챌린지 5일차  (0) 2022.01.28
패스트캠퍼스 챌린지 4일차  (0) 2022.01.27
패스트캠퍼스 챌린지 3일차  (0) 2022.01.26
패스트캠퍼스 챌린지 1일차  (0) 2022.01.24

방대한 사전지식 => html, css, js를 배웠다고 웹앱을 만들기는 버거움

 

javascript 기초 ? 책 => (자바스크립트 완벽가이드, 모던 자바스크립트 Deep Dive 등)

 

unicode, 비트, ASCII, encoding, 문자 집합

 

방향성: (일단 만들면서 학습 or 잘 정리된 순서대로 학습) 혼용 !

 


빠르게 배워야할 것: 빠르게 변하는 기술 (프레임워크, 라이브러리, UI, UX, 디자인 패턴)

반복해 배워야할 것: 느리게 변하는 기술 (프로그래밍 언어, 프로그래밍 패러다임, 자료구조, 보안, 알고리즘)

나중에 배워야할 것: 변하지 않는 기술 (네트워크, 운영체제, 컴퓨터 시스템, 논리학, 대수학)

 

빠르게 배우는 것 => 피로감이 높아짐

 

변하지 않는 지식을 알고 있으면 상대적으로 느린 변화를 가진 지식들을 알기 쉽고 빠르게 변하는 지식들을 배우는데 수월하다.

 

장기전 !

 

* 프로그래밍 역량

 - 일관성

 - 유연성

 - 확장성 

 - 독립성 

 


 

환경세팅

vscode 설치 (tool)

 

(deprecated) debugger for chrome (extention)

javascript debugger (extention)

node.js (server)

parcel.js (bundler)

typescript (programming language)

 

--save-dev: 특정한 프로젝트에서만 설치하는 방식

-g: 글로벌하게 설치하는 방식

 

 

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 6일차  (0) 2022.01.29
패스트캠퍼스 챌린지 5일차  (0) 2022.01.28
패스트캠퍼스 챌린지 4일차  (0) 2022.01.27
패스트캠퍼스 챌린지 3일차  (0) 2022.01.26
패스트캠퍼스 챌린지 2일차  (0) 2022.01.25

[Node.js] chap.3

 

 

 

method-override

GET, POST, PUT, DELETE 중에서 나머지 사용할 수 있게 해줌

npm install method-override // REST API => 

 

- 세팅

// (server.js)
const methodOverride = require('method-override')
app.use(methodOverride('_method'))

 

<!-- (edit.ejs) -->

<form action="/add?_method=PUT" method="POST">
  <input 어쩌구>
</form>

해당 형식으로 작성하면 PUT 요청을 할 수 있다.

 

(server.js) 

app.put('/edit', function(요청, 결과){ 
  db.collection('post').updateOne( {_id : parseInt(요청.body.id) }, {$set : { 제목 : 요청.body.title , 날짜 : 요청.body.date }}, 
    function(){ 
    
    console.log('수정완료') 
    응답.redirect('/list') 
  }); 
});

 

 

** 서버의 요청(GET, POST, PUT, PATCH, DELETE)이 완료되고 난 후에, 응답이 없으면 브라우저가 멈출 수 있기 때문에 꼭 응답처리가 필요하다.

 

 

 

회원인증

1. Session-based Authentication

 - 사용자의 세션정보를 저장해서 로그인 기능을 구현

 

2. JWT (JSON Web Token)

 - 세션데이터를 서버에 저장하지않고 토큰을 사용자에게 주는 방식

 

3. OAuth (Open Authentication)

 - 소셜로그인

 

 

* Session-based Authentication

npm install passport passport-local express-session

실제 서비스시 express-session 말고 MongoDB에 세션데이터를 저장해주는 라이브러리를 이용하면 좋다.(ex. connect-mongo)

 

// (server.js)
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');

app.use(session({secret : '비밀코드', resave : true, saveUninitialized: false}));
app.use(passport.initialize());
app.use(passport.session());

:라이브러리에 나와있는 사용법 그대로

 

 

- 미들웨어

app.use()와 같은 부분을 미들웨어라고 하는데 요청과 응답 사이에 뭔가를 실행시키는 코드라고 생각하면 된다. 예를 들어 요청이 적법한지 검사하는 것이다. (passport.intialize(), passport.session() 등)

 

 

- 로그인 검사

app.post('/login', passport.authenticate('local', {failureRedirect : '/fail'}), function(요청, 응답){
  응답.redirect('/')
});

post() 함수의 두번째 파라미터로 passport 라이브러리가 제공하는 인증하는 코드이다. (failureRedirect 부분은 로그인 실패시 이동시켜줄 경로이다.)

 

 

* passport

passport.use( new LocalStrategy({ 
    usernameField: 'id', // (요기는 사용자가 제출한 아이디가 어디 적혔는지) 
    passwordField: 'pw', // (요기는 사용자가 제출한 비번이 어디 적혔는지) 
    session: true, // (요기는 세션을 만들건지) 
    passReqToCallback: false, // (요기는 아이디/비번말고 다른 정보검사가 필요한지) 
});

 

- passport 라이브러리 설정코드

// (server.js 하단에 복붙)

passport.use(new LocalStrategy({
  usernameField: 'id',
  passwordField: 'pw',
  session: true,
  passReqToCallback: false,
}, function (입력한아이디, 입력한비번, done) {
  //console.log(입력한아이디, 입력한비번);
  db.collection('login').findOne({ id: 입력한아이디 }, function (에러, 결과) {
    if (에러) return done(에러)

    if (!결과) return done(null, false, { message: '존재하지않는 아이디요' })
    if (입력한비번 == 결과.pw) {
      return done(null, 결과)
    } else {
      return done(null, false, { message: '비번틀렸어요' })
    }
  })
}));

: LocalStrategy( { 설정 }, function(){ 아이디비번 검사하는 코드 } )

 

 

- 세션 생성 및 세션 아이디 쿠키로 보내기

passport.serializeUser(function (user, done) {
  done(null, user.id)
});

passport.deserializeUser(function (아이디, done) {
  done(null, {}) // 추후 수정
});

serializeUser(): 유저의 id 데이터를 바탕으로 세션데이터를 만듦. 그 세션데이터의 아이디를 쿠키로 만들어서 사용자의 브라우저로 보냄.

deserializeUser(): 세션아이디를 바탕으로 이 유저의 정보를 DB에서 찾는역할을 한다.

 

 

// (server.js) 

app.get('/mypage', loginCheck, function (req, res) { 
  console.log(req.user); 
  res.render('mypage.ejs', {}) // 추후 수정 
}) 

function loginCheck(req, res, next) { 
  if (req.user) { 
    next() 
  } 
  else { 
    res.send('로그인안하셨는데요?') 
  } 
}

1. get() 함수에 미들웨어 loginCheck()를 넣으면 /mypage 요청과 mypage.ejs 응답 사이에 loginCheck라는 코드를 실행시켜준다.

2. loginCheck()는 req.user가 있으면 next()로 통과시키고, 없으면 에러메세지를 res.send() 해달라는 뜻이다.

 

 

passport.deserializeUser(function (아이디, done) {
  db.collection('login').findOne({ id: 아이디 }, function (error, result) {
    done(null, result)
  })
});

{id : 세션아이디에 숨겨져있던 유저의 아이디} 인 게시물을 찾아서 그 데이터의 결과를 done(null, result)를 실행한다. 그러면 결과가 req.user 부분에 들어간다. (로그인한 유저의 DB 데이터를 볼 수 있다.) 로그아웃은 req.logout()으로 실행할 수 있다.

 

 

app.get('/mypage', loginCheck, function (req, res) {
  console.log(req.user);
  res.render('mypage.ejs', { 사용자: req.user })
})

deserializeUser()를 통해서 req.user 부분에 로그인한 사용자의 id를 통한 DB의 정보를 가져올 수 있기 때문에 mypage.ejs에서 로그인한 사용자의 정보를 화면에 출력할 수 있다.

 

 

 

.env (environment variable) 파일

- 환경에 따라 가변적인 변수 데이터를 모아 놓은 파일

npm install dotenv

- 라이브러리 설치

 

 

// (server.js)

require('dotenv').config()

- 설치한 라이브러리 등록

 

 

* .env 파일을 server.js 파일과 동일한 경로에 생성한다. *

// (.env 파일)

PORT=8080
DB_URL="mongodb+srv://test@test"

- .env 파일 작성법

 

 

// (기존 server.js 코드)

var db;
MongoClient.connect('mongodb+srv://test:test@test', function(err, client){
  if (err) return console.log(err)
  db = client.db('Example1');
  app.listen(8080, function() {
    console.log('listening on 8080')
  })
}) 


// (env 파일을 적용하는 server.js 코드)

var db;
  MongoClient.connect(process.env.DB_URL, function(err, client){
  if (err) return console.log(err)
  db = client.db('Example1');
  app.listen(process.env.PORT, function() {
    console.log('listening on 8080')
  })
})

.env 파일에 작성된 변수들은 process.env.변수명 의 형식으로 사용한다.

 

 

 

URL query string

url 입력하는 곳에 /example?key=value 형식으로 요청을 보내면 GET 요청으로 데이터를 보낼 수 있다.

 

 

<div class="container input-group mb-2">
  <input class="form-control" id="search-input">
  <button class="input-group-append btn btn-danger" id="search">검색</button>
</div>

<script>
  $('#search').click(function(){
    var 입력한값 = $('#search-input').val();
    window.location.replace('/search?value=' + 입력한값)
  });

</script>

window.location: 현재 해당하는 페이지의 URL을 뜻한다.

 

 

app.get('/search', (req, res)=>{
  console.log(req.query);
  db.collection('post').find({제목 : req.query.value}).toArray((error, result)=>{
    console.log(result)
  })
})

req.query: 요청받은 URL query string 값을 가져올 수 있다.

 

 

 

 

 

 

 

 

 

indexing

검색할 때, 해당 검색어를 포함한 여러 데이터를 가져오는 방식은

 

 

1. 정규식 사용

db.collection('post').find({제목 : /글쓰기/})

- 데이터가 대용량이면 성능 안나옴

 

 

2. 인덱싱 사용

Binary Search: (숫자가 정렬되어 있다는 전제하에 => indexing) 정해진 숫자의 처음 중간의 값을 선택하여 그 값과 찾는 값의 크고 작음을 비교하면서 탐색한다.

 

 

- query string 찾는 다른 방법

// jQuery

var 자료 = { 이름1 : '값1', 이름2 : '값2' }
$param(자료) //이름1=값1&이름2=값2 이거가 남음

$('form').serialize() // input에 name있는 모든 값

 

 

- MongoDB indexing

(해당)collection - indexes - create index

문자열: 'text'

숫자: 1 or -1

 

해당 작업을 하면 collection의 정렬된 사본을 만들어준다.

app.get('/search', (요청, 응답)=>{
  console.log(요청.query);
  db.collection('post').find( { $text : { $search: 요청.query.value }} ).toArray((에러, 결과)=>{
    console.log(결과)
    응답.render('search.ejs', {posts : 결과})
  })
})

 

 

이 방법으로 간단한 검색엔진처럼 검색이 가능하다. (ex. 단어 -단어, "단어 단어" 등)

단점: 띄어쓰기를 기준으로 검색이 안된다 (영어에 특화된 검색)

 

 

- 해결방법

1. 검색할 양을 제한한다.

 - 날짜별로 검색하거나, skip(), limit() 함수를 이용해서 페이징 처리를 한다.

 

2. text Search를 사용한다.

 - MongoDB Atlas말고 직접 설치한다. 띄어쓰기 단위 indexing이 아닌 글자 단위의 indexing 알고리즘을 사용할 수 있다. (nGram)

 

3. Search index를 사용한다.

 - MongoDB Atlas에서 Search index를 생성할 수 있다. text index랑 비슷하지만 lucene.korean으로 변경하면 한국어에 쓰기 좋게 조사 등을 제거하고 검색을 할 수 있다.

 

 

- Search index

app.get('/search', (req, res) => {
    var 검색조건 = [
        {
            $search: {
              index: 'titleSearch', // Search index에서 설정한 name
              text: {
                query: req.query.value,
                path: '제목'  // 제목날짜 둘다 찾고 싶으면 ['제목', '날짜']
              }
            }
        },
        // { $sort: { _id: 1 } }, // 오름차순 1, 내림차순 -1
        // { $limit: 10 } // 갯수 설정
        // { $project : { 제목: 1, _id: 1, score: { $meta: "searchScore" } } } // meta 부분은 검색되는 빈도 등의 점수를 기준으로 검색
    ]
    db.collection('post').aggregate(검색조건).toArray(function(error, result){ // find() 대체
        console.log(result);
        res.render('search.ejs', {posts: result});
    })
})

 

 

 

router

서버에 요청하는 수 많은 경로들을 분류하여 관리할 수 있다.

root/routes/파일.js

server.js와 나란한 경로에 routes라는 폴더를 생성하고 그 안에 js 파일을 생성한다.

 

 

// 라우팅하는 .js 파일
var router = require('express').Router(); // express의 Router기능

router.get('/shop/shirts', function(req, res){
   res.send('셔츠 파는 페이지입니다.');
});

router.get('/shop/pants', function(req, res){
   res.send('바지 파는 페이지입니다.');
}); 

module.exports = router; // import/export 대체 가능
app.use('/', require('./routes/shop.js') ); // 미들웨어 형식으로 라우터를 적용

 

 

- URL 단축

app.use('/shop', require('./routes/shop.js') );

/////////////////////////////////////////////

var router = require('express').Router();

router.get('/shop/shirts', function(req, res){
   res.send('셔츠 파는 페이지입니다.');
});

router.get('/shop/pants', function(req, res){
   res.send('바지 파는 페이지입니다.');
}); 

module.exports = router;

 

 

- 라우터에 미들웨어 적용

var router = require('express').Router();

// router.use(loginCheck); // 전역적으로 loginCheck라는 미들웨어 사용 가능
router.use('/shop/shirts', loginCheck); // '/shop/shirts'의 경로에 loginCheck라는 미들웨어 사용 가능

function loginCheck(req, res, next) {
  if (req.user) { next() }
  else { res.send('로그인 안하셨는데요?') }
}
router.get('/shop/shirts', function(req, res){
   res.send('셔츠 파는 페이지입니다.');
});

router.get('/shop/pants', function(req, res){
   res.send('바지 파는 페이지입니다.');
}); 

module.exports = router;

 

 

 

Google Cloud Platform 배포

1. app.yaml 파일 생성

runtime: nodejs 
env: flex

/////////////// 밑으로는 안적어도 자동 생성
manual_scaling:
  instances: 1
resources:
  cpu: 1
  memory_gb: 0.5
  disk_size_gb: 10

 

 

2. server.js 포트 확인

app.listen(8080, function() {
    console.log('listening on 8080')
})

- 구글클라우드 기본 포트가 8080. (.env 파일 세팅있다면 확인)

 

 

3. MongoDB Atlas Network Access 모든 아이피 허용 확인

- 모든 아이피 (0.0.0.0) 접속허용 (Allow Access from Anywhere 로 체크)

 

 

4. Google Cloud Platform 시작

 - 회원가입 및 카드등록 및 프로젝트 생성

 - 프로젝트 생성 후 App Engine에서 배포 진행

 - SDK 설치 진행

 

5. 배포

 

** 프로젝트가 설치되어 있는 경로로 이동한다.**

gcloud init

Google Cloud Platform 개설한 구글 아이디 로그인 및 프로젝트 선택

 

gcloud app deploy

작업이 끝나면 배포할 소스파일, 이름, url 등을 알려주고 배포 완료.

 

 

 

이미지 처리

이미지 업로드 및 이미지 서버를 만들 수 있다.

 

<form method="POST" action="/upload" enctype="multipart/form-data" > // multipart => 인코딩을 하지 않아 상대적으로 파일 용량 적게 가져옴
    <input type="file" name="profile">
    <button type="submit">전송</button>
</form>

: ejs

 

 

npm install multer // multipart

multipart/form-data 라이브러리 설치

 

 

let multer = require('multer');
// var storage = multer.memoryStorage({}) // memory 상에 저장 (휘발성)
var storage = multer.diskStorage({

  destination : function(req, file, cb){ // 이미지 저장 경로
    cb(null, './public/image')
  },
  filename : function(req, file, cb){ // 이미지 이름 설정
    cb(null, file.originalname )
  },
  fileFilter: function (req, file, callback) { // 이미지 저장 시 필터처리
        var ext = path.extname(file.originalname);
        if(ext !== '.png' && ext !== '.jpg' && ext !== '.jpeg') {
            return callback(new Error('PNG, JPG만 업로드하세요'))
        }
        callback(null, true)
    },
    limits:{
        fileSize: 1024 * 1024 // 이미지 사이즈 제한
    }
});

var upload = multer({storage : storage});

: (server.js) multer 세팅

 

 

// 이미지 저장 페이지
app.get('/upload', function(req, res){
  res.render('upload.ejs')
}); 

// 이미지 저장처리
app.post('/upload', upload.single('profile'), function(req, res){ // input태그의 name속성 'profile'
  res.send('업로드완료')
}); // upload 미들웨어처럼 실행

// 저장된 이미지 불러오기
app.get('/image/:imageName', function(req, res){
    res.sendFile(__dirname + '/public/image/' + req.params.imageName); // __dirname => 현재root경로
})

: server.js

 

 

 

서버와의 실시간 소통 (SSE)

1) 1초마다 서버에게 메세지를 요청한다.

2) 서버랑 유저간 지속적인 소통채널을 연다. 

 

2)의 경우가 서버의 부하가 덜 하고 get이나 post 등의 요청은 1회 요청이지만 지속적으로 서버에 응답을 하려할 때 사용한다.

// (server.js)
app.get('/message/:parentid', loginCheck, function(req, res){

  res.writeHead(200, {
    "Connection": "keep-alive",
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
  });

  res.write('event: test\n');
  res.write(`data: ${JSON.stringify(결과)}\n\n`);

});

1. 지속적 소통채널 개설을 하려면 서버는 res.writeHead() 처럼 쓴다.

2. 유저에게 계속 메세지를 보내고 싶을 때마다 res.write() 한다.

3. event: 이벤트명을 잘 작성하고 data: 전달할내용을 쓰면 된다.

 

 

// chat.ejs
var 지금누른채팅방id;
var eventSource;   //일단변수 

$('.list-group-item').click(function(){
  지금누른채팅방id = this.dataset.id;

  //프론트엔드에서 실시간 소통채널 여는법 
  eventSource = new EventSource('/message/' + 지금누른채팅방id);
  eventSource.addEventListener('test', function (e){
    console.log(JSON.parse(e.data));
  });

});

1. GET 요청 대신 new EventSource('/message/' + 지금누른채팅방id); 형태의 코드를 실행하면 서버에서 만들어놓은 실시간 채널에 입장 가능하다.

2. eventSource.addEventListener('서버에서작명한이벤트명') 이런 코드를 쓰면 서버가 보낸 데이터를 수신할 수 있다. 서버가 res.write() 할 때마다 내부 코드를 실행해줍니다.

3. e.data 안에는 서버가 보낸 데이터가 들어있다.

 

 

 

DB 변동사항 실시간 업데이트

* MongoDB change stream

- 데이터 베이스의 변동을 감지하여 서버에게 업데이트 사항을 알려준다.

// ejs
var 지금누른채팅방id;
var eventSource; 

$('.list-group-item').click(function(){
  지금누른채팅방id = this.dataset.id;
  $('.chat-content').html('') //일단 메세지들 전부 비우기

  eventSource = new EventSource('/message/' + 지금누른채팅방id);
  eventSource.addEventListener('test', function (e){
    console.log(e.data);

    var 가져온거 = JSON.parse(e.data);
    가져온거.forEach((a) => {
        $('.chat-content').append(`<li><span class="chat-box">${a.content}</span></li>`)
    });
  });

});

1. 가져온 데이터를 JSON -> Object 형태로 변환

2. Array로 되어있는 object 안에 하나하나 메세지 document 들을 반복문을 통해 하나씩 분리

3. 그거 안에 있던 메세지들을 <li></li> 태그로 만들어서 원하는 곳에 출력

 

 

// server
const 찾을문서 = [
	{ $match: { 'fullDocument.parent': 요청.params.parentid } } // collection의 변경 감지 부분
];

const changeStream = db.collection('message').watch(찾을문서);
	changeStream.on('change', result => {
		console.log(result.fullDocument);
		var 추가된문서 = [result.fullDocument]; // 화면에 반영할 부분
        응답.write('event: test\n');
		응답.write(`data: ${JSON.stringify(추가된문서)}\n\n`);
});

change stream을 이용해서 DB 감시 한다.

- 우선 { parent : 요청.params.parentid } 인 게시물들만 감시

- 그런 게시물들에 변동사항이 생기면 [result.fullDocument] 이걸 유저에게 보내줌

- 물론 [], {} 이런 자료들은 JSON으로 바꿔서 보내야한다.

 

 

 

 

 

 

 

 

 

socket.io

SSE(서버에서 일방적으로 실시간 응답) 말고도 서버와 유저간에 Web Socket을 통해 양방향 실시간 통신이 가능하다.

 

npm install socket.io

라이브러리 설치

 

// (server.js)
const http = require('http').createServer(app);
const { Server } = require("socket.io");
const io = new Server(http);

- const app = express()보다 하단에 적용

 

// 기존
app.listen(process.env.PORT, function(){
  console.log('listening on 8080')
}); 

// 변경
http.listen(process.env.PORT, function(){
  console.log('listening on 8080')
});

app: express를 이용해서 서버를 띄움

http: 기본 nodejs 라이브러리 + socket.io를 이용해서 서버를 띄움

 

 

- 웹소켓 연결

// (server.js)
app.get('/socket', function(요청,응답){
  응답.render('socket.ejs')
});

io.on('connection', function(){ // 웹소켓으로 서버에 connection했을 때
  console.log('연결되었어요');
  
  socket.on('user-send', function(data){ // user-send라는 이벤트 발생 시 data 실행
    console.log(data) // '안녕하세요'
  });
});

연결 됐을 때 할 작업

 

// ejs
<body>
<script src="https://cdn.socket.io/4.4.0/socket.io.min.js" integrity="sha384-1fOn6VtTq3PWwfsOrk45LnYcGosJwzMHv+Xh/Jx5303FVOXzEnw0EpLv30mtjmlj" crossorigin="anonymous"></script>

<div>채팅방</div>
<button id="send">서버에 메세지 보내기</button>

<script>
  var socket = io(); // 웹소켓을 이용해 서버와 실시간 소통채널 개설
  $('#send').click(function(){
    socket.emit('user-send', '안녕하세요') // (이벤트 명, 전달할 데이터)
})
</script>
</body>

- package.json에 있는 버전 맞춰서 cdn 설치

- emit: 'user-send'라는 이벤트 명으로 보낸 '안녕하세요'라는 데이터 수신

 

 

- 서버에서 클라이언트로 데이터 보내기

io.emit('작명', '보낼메세지');

모든 유저에게 메세지를 보낸다 (broadcast 한다)

 

// (server.js)
io.on('connection', function (socket) {
  socket.on('user-send', function (data) { // user-send 이벤트가 일어나면
    io.emit('broadcast', data)  //모든사람에게 데이터 전송
  });
});
// (chat.ejs) 
<script>
  var socket = io();
  $('#send').click(function(){
    socket.emit('user-send', '안녕하쇼')
  });
  socket.on('broadcast', function(data) {
      $('#content').append('<div>' + data + '</div>')
  });
</script>

 

- 내가 원하는 사람에게만 메세지보내기

io.on('connection', function(socket){
  console.log(socket); // header, id 등이 출력 됌
  io.to(socket.id).emit("broadcast", '서버응답임'); 원하는 소켓id를 가진 사람에게만 메세지 보냄
});

 

 

- 하위 채팅방 만들기

<!-- (socket.ejs) -->
<button id="room1">채팅방1 입장</button>
<button id="room1-send">채팅방1에 메세지 전송</button>

<script>
  $('#room1').click(function(){
    socket.emit('joinroom', '제발');
  });

  $('#room1-send').click(function(){
    socket.emit('room1-send', '어쩌구저쩌구' )
  });
  
</script>

- joinroom 이라는 이벤트를 발생시킨다.

- room1-send라는 이벤트를 발생시킨다.

 

// (server.js)
io.on('connection', function(socket){

  socket.on('joinroom', function(data){
    socket.join("room1"); // room1이라는 방에 유저를 넣을 수 있다.
  });

  socket.on('room1-send', function(data){
    io.to("room1").emit('broadcast', data);
  });
});

- joinroom이라는 이벤트가 발생되면 room1이라는 방을 만들고 유저를 넣는다.

- room1-send라는 이벤트가 발생되면 room1에 있는 사람들에게만 broadcast 해준다.

 

 

 

Node+Express & React 연동

1) npm init

2) npm install express

3) server.js 파일 생성

// (server.js)
const express = require('express');
const path = require('path');
const app = express();

const http = require('http').createServer(app);
http.listen(8080, function () {
  console.log('listening on 8080')
});

4. (node or nodemon) server.js

 

 

- react 연동

1) react 프로젝트 생성(npx create-react-app 프로젝트명)

2) react 프로젝트 경로로 들어가서 작업 후 npm run build 명령어로 build 파일 생성

// (server.js에 추가)
app.use(express.static(path.join(__dirname, 'react-project/build'))); // 특정 폴더안의 파일을 static 파일로 보내기 위함

app.get('/', function (요청, 응답) {
  응답.sendFile(path.join(__dirname, '/react-project/build/index.html'));
});

// 라우팅을 하기 위함
app.get('*', function (요청, 응답) {
  응답.sendFile(path.join(__dirname, '/react-project/build/index.html'));
});

 

 

- node.js와 react간 ajax요청 시 (여러 const 하단에 추가)

npm install cors --save // 에러날 시에
app.use(express.json());
var cors = require('cors');
app.use(cors());

 

 

- 서브디렉토리에 리액트앱 발행하는 경우

// (server.js)
app.use( '/', express.static( path.join(__dirname, 'public') ))
app.use( '/react', express.static( path.join(__dirname, 'react-project/build') ))

app.get('/', function(요청,응답){
  응답.sendFile( path.join(__dirname, 'public/main.html') )
}) 
app.get('/react', function(요청,응답){
  응답.sendFile( path.join(__dirname, 'react-project/build/index.html') )
})
// (리액트프로젝트 내의 package.json)
{
  "homepage": "/react", // 이 부분 설정
  "version": "0.1.0",
  ... 등
}

 

 

- 서버와 리액트 동시에 띄워서 개발

리액트의 localhost와 node.js서버의 localhost의 미리보기를 띄어놓고 개발을 진행하기 위함.

// (리액트프로젝트 내의 package.json)
{
  ...
  "proxy": "http://localhost:8080"
  ...
}

- 리액트의 package.json에서 proxy부분을 추가

https://create-react-app.dev/docs/proxying-api-requests-in-development/

 

Proxying API Requests in Development | Create React App

Note: this feature is available with react-scripts@0.2.3 and higher.

create-react-app.dev

 

** socket이 들어가면 추가적으로 수정 필요 **

 

 

 

 

 

'NodeJs' 카테고리의 다른 글

[Node.js] chap.2  (0) 2021.12.21
[Node.js] chap.1  (0) 2021.12.20

+ Recent posts