Udemy <The Web Developer 부트캠프 2024>
- Express는 Node 런타임을 이용해 서버 구축을 좀 더 수월하게 할 수 있도록 도와주는 프레임워크다.
- Node 환경에서
require('express')로express함수를 불러오고,express()로 함수를 호출해주면 프레임워크에 해당하는 객체가 반환된다. 보통은app이라는 이름으로 값을 받아서 사용한다(아래에선const app = express()로 값을 받아왔다는 전제로, Express 객체를app이라고 지칭하겠다). express함수(app)가 반환하는 객체에는 서버의 처리를 위한 다양한 값과 메서드들이 있다. 해당 프로퍼티들을 사용해서 원하는 서버 로직을 처리할 수 있다.app.listen을 사용하면 서버를 실행하고, 원하는 포트를 열 수 있다. 로컬에서 서버를 띄울 땐 보통 포트 번호를3000번으로 많이 설정하는데,app.listen(3000, {콜백 함수})형태로 사용한다.app.listen의 두 번째 인자로 오는 콜백 함수에는 처음 서버가 열릴 때 실행될 로직을 전달할 수 있다.- 라우트 경로에 상관 없이, 서버 접근에 대한 동일한 응답을 뱉어주고 싶다면
app.use()메서드를 사용하면 된다. 매개 변수로는 하나의 콜백 함수를 받고, 콜백 함수에는 자동으로 매개 변수(req, res)가 들어온다.req는 클라이언트에서 온 요청 관련 정보를 담고 있는 객체고,res는 클라이언트로 돌려 보낼 응답 관련 여러 처리를 해줄 수 있는 객체다. 매개 변수의 순서가 중요하지, 이름은 개발자의 편의에 따라 커스텀할 수 있다. - 원하는 라우팅 경로에 따라 다른 로직 처리를 해서 값을 반환해주고 싶다면
app의getpostpatchputdelete등의 메서드를 사용하면 된다. 이름에서 알 수 있듯이, HTTP 메서드 종류는app객체의 메서드로 구분해서 요청을 받는다. - 각 메서드들의 첫 번째 인자로는 원하는 라우팅 경로를 작성한다. 예를 들어,
app.get('/home', {콜백 함수})형태로 사용하면 서버 경로의/homepath로 요청이 올 경우에 대해 대응한다.app.post('/home', {콜백 함수})는home경로로 온 POST 요청에 대응한다. - 라우팅 경로에
*를 사용하면 모든 경로를 의미한다. Node는 파일에 작성한 라우팅 처리 로직을 위에서부터 순서대로 실행하기 때문에,*경로에 대한 라우팅 처리 로직을 파일의 가장 앞쪽에 작성했다면 모든 접근에 대해서 해당 콜백 함수로 처리가 되니 주의하자. - 라우팅 경로의 요청을 받았으면, 콜백 함수로 필요한 로직 처리를 해줄 수 있다.
getpostpatchputdelete등 메서드는app.use메서드의 콜백과 마찬가지로 각각 요청 정보와 응답을 위한req,res객체를 매개 변수로 받는다. res.send메서드를 사용하면 매개 변수로 넘긴 값을 클라이언트에 반환할 수 있다. 반환할 수 있는 값은 문자열, 객체, HTMLElement 등 다양하며, 종류에 따라 http 요청 headers에 있는Content-type의 값이 달라진다. 예를 들어서,res.send('WELCOME')이라고 하면 헤더에"Content-type": "html/tex"가 박혀서 응답되고,WELCOME이란 문자열은 DOM의body태그에 바로 박히게 된다.res.send({ styles: { color: 'red' }})이런 식으로 객체를 응답하면"Content-type": "application/json"이 헤더에 박혀서 응답이 날아간다.- 응답의 형태에 따라 클라이언트에서 받아서 사용할 수 있는 값의 형태가 달라지기 때문에, 타입의 정의나 형식을 잘 신경써야겠다.
req.params와req.query는 각각 URL에 있는 path 정보와 query 정보를 캐치하는 데 사용된다. 둘 다 객체를 반환한다.app.get('/article/:id', (req, res) => res.send(req.params.id))라고 작성하면/article/path뒤에 오는 값들이id라는 변수에 할당되며,req.params는{ id: ${입력된 값} }형태로 값을 갖게 된다. 그래서req.params.id를res.send`로 클라이언트로 값을 내려주면 URL의 params 값에 따라 다른 응답을 처리해줄 수 있다.req.query는 사용자가 URL에?{key}={value}형태로 보내준 쿼리 메시지를{ key: value}형태의 객체로 받아준다. 쿼리를 잘 사용하면 클라이언트에서 보낸 요청을 캐치해서 데이터베이스에 값을 저장하거나, 정렬 기준을 잡거나, 기타 등등 필요한 정보를 받아오는 데 유용하다.- 기본적으로 Express 서버를 실행할 땐 터미널로 실행할 모듈의 경로에서
node index.js처럼 파일을 실행해주면 된다. 그런데, 한 번 서버를 실행하면 코드에 수정이 있더라도 수정 사항이 곧바로 반영되지 않고, 반영하려면 서버를 껐다가(터미널에서 ctrl+c 입력) 다시 띄워줘야 한다. - nodemon 패키지를 사용하면 수정 사항을 반영하기 위해 서버를 껐다 킬 필요 없이 수정 사항이 자동으로 반영되게 할 수 있다.
npm i -g nodemon으로 nodemon 설치 후nodemon {실행할 파일}로 서버를 띄워주면 된다. - 서버에서 HTML 템플릿 파일을 내려줘야 할 때 ejs 패키지를 사용할 수 있다. ejs는 HTML Document 문서에 일부 필요한 자바스크립트 코드를 작성할 수 있도록 해주는 문법으로, 서버에서 HTML 템플릿을 생성한 후 자바스크립트 코드로 동적인 일부 처리를 해주고 싶을 때 사용한다.
- ejs를 사용하려면 먼저
npm i ejs로 ejs 패키지를 설치해줘야 한다. - ejs를 사용하기 위해선
app.set('view engine', 'ejs')로 HTML 템플릿 시 ejs 패키지를 사용한다는 것을 명시해줘야 한다. - 그리고, ejs는 프로젝트 디렉터리에 있는
views디렉터리에서{파일명}.ejs확장자로 된 파일의 뷰를 참조한다. 따라서, ejs를 사용하려면 프로젝트의 루트에views디렉토리를 별도로 생성해줘야 한다. views에home.ejs와 같이 템플릿을 만들고, 필요한 HTML 코드를 넣어준 다음에, 상위에 있는index.js모듈의 라우팅 요청 처리 콜백 함수에서res.render('home')형태로 사용하면 사전에 서버에서 정의한 템플릿을 클라이언트에 그대로 내려줄 수 있다.- ejs는 기본 설정 상 프로젝트 루트 디렉토리에 있는
views디렉토리를 바라보고 있기 때문에,app.render에는 경로 전체가 아니라views디렉토리에서 참조하고 싶은ejs모듈 이름을 작성하면 된다.app.set('view engine', 'ejs')로 사전에 설정해줬기 때문에 확장자도 생략 가능하다. - 어떤 경로에서 nodemon을 실행하더라도
index.js가 있는 폴더에서views디렉토리를 바라볼 수 있도록 설정하려면app.set('views', path.join(__dirname, '/views'))형태로 사용하면 된다. 이렇게 설정해두면 어디서 서버가 실행됐든 상관 없이views디렉토리를 참조하는 경로를 고정할 수 있다. - 자바스크립트의 템플릿 문자열을 사용하면 문자열 안에서 자바스크립트 표현식을 사용할 수 있는 것처럼, ejs도 HTML 구문 내에 자바스크립트 코드를 작성할 수 있도록 한 태그가 있다.
<%= %>처럼 사용하면 원하는 자바스크립트 표현식을 넣어서 평가된 값을 템플릿에 같이 포함시켜줄 수 있다. res.render('random')처럼 특정 경로를 설정해서views/ejs를 가져올 때, 두번째 인자로 객체를 전달하면 ejs 템플릿에 변수를 내려줄 수 있다. 예를 들어 ,res.render('random', { rand: num })이라고index.js모듈에 정의해주면random.ejs모듈에서rand라는 변수를 참조할 수 있게 된다.<%= %>를 사용하면 감싸진 자바스크립트 표현식이 평가돼서 템플릿에 표현되지만,<% %>형태로=를 빼고 사용해주면 실제 view에 표시되진 않지만 자바스크립트 표현식을 평가해서 실행할 순 있다. 조건문, 반복문 등의 자바스크립트 구문은 실제 view로 표현하고 싶진 않지만, 로직 처리를 위해 사용이 필요한 경우가 있다. 이런 경우<% %>형태로 태그를 사용한다.- 템플릿에 ejs 태그를 잘 사용하면 데이터 베이스나 별도 JSON에 저장된 데이터를 잘 활용해서 하나의 웹 페이지를 잘 구축할 수 있다.
- 템플릿에 필요한 static 파일들(e.g. CSS 파일, 이미지 등)은
express의 정적 메서드인express.static을 통해 참조할 수 있다. 모든 라우트 경로에서 동일한 로직을 실행할 때 쓰는app.use에app.use(express.static('public')같은 식으로 공개하고 싶은 정적 파일들이 있는 디렉토리(예시 경우에는public)를 참조해주면 모든 페이지에서 참조한 디렉토리에 있는 정적 파일들을 활용할 수 있다. express.static의 인자도 서버를 실행한 위치에 상관 없이index.js가 있는 경로를 기준으로 정적 파일의 경로를 잡아주고 싶다면app.use(express.static(path.join(__dirname, '/public')))과 같은 형식으로 사용해주면 된다.<%- %>를 사용하면 이스케이핑하지 않고 태그 내부에 있는 값을 그대로 화면에 출력한다. 대표적으로 태그 내에 HTML 구문을 넣어주고 싶을 때 사용한다.<%- include({템플릿 파일 경로}) %>형식으로 경로를 넣어주면 경로에 있는 템플릿 파일을 불러와서 넣어줄 수 있다. 마치 리액트에서 컴포넌트를 나눠놓고, 컴포넌트들을 필요한 곳에서 불러와 합치는 것과 유사하다.- 다만,
<%- include() %>구문이 리액트의 컴포넌트와 다른 건, 템플릿에 박혀있는 HTML 구문을 정말 그대로 떼고 붙이고 한다는 것이다. 예를 들어서 페이지 상단에 있는head태그 내부 메타 데이터의 HTML 코드를 별도 템플릿에 정의해놓고, 다른 템플릿에서head위치에 해당 템플릿을 불러오면 마치head를 변수에 저장했다 값을 가져오는 것처럼 치환된다.
React
render함수 구현하기- 리액트에서 Virtual DOM 객체를 실제 DOM에 반영해주는
render함수를 직접 구현해봤다. render함수는 Virtual DOM 객체를 깊이에 따라 순회하면서 DOM 요소를 만들어주고, props들을 attribute로 등록해주고, children을 재귀적으로 탐색하면서 실제 DOM Tree를 만들어준다. 그리고 root 노드가 되는div#root에 연결해준다.props의 종류에 따라 예외 처리가 필요한 것들이 있다. 예를 들어key는 실제 DOM에는 반영하지 않는 속성이고,styles는 값을 객체로 받아 인라인 스타일로 실제 스타일을 먹여줘야 한다.props에 이벤트 핸들러 함수가 들어오면addEventHandler등을 사용해서 이벤트 핸들러로 부착해줘야 한다.- Fragment도 별도로 처리해서, 등장 시
children요소들을 DOM에 순차적으로 추가할 수 있게 구현해준다. - 구현한 내용에 대해선 별도 블로그 포스팅으로 정리해서 남길 예정이다.
- 리액트에서 Virtual DOM 객체를 실제 DOM에 반영해주는
'TIL' 카테고리의 다른 글
| 241221 TIL (0) | 2024.12.21 |
|---|---|
| 241220 TIL (1) | 2024.12.21 |
| 241217 TIL (0) | 2024.12.19 |
| 241216 TIL (0) | 2024.12.17 |
| 241212 TIL (1) | 2024.12.13 |