260112 - Re:zero부터 시작하는 express

LIHA·4일 전
post-thumbnail

Node.js 기본 사용 문법도 있다 - 복잡하고 번거로워 그렇지

const server = http.createServer((req, res) => {
  console.log("req.url: ", req.url);

  if (req.url == "/hello") {
    const helloHTML = fs.readFileSync("static/hello.html", "utf-8");

    res.writeHead(200, { "content-type": "text/html" });
    res.write(helloHTML);
    res.end();
  } else if (req.url == "/") {
    const homeHTML = fs.readFileSync("static/home.html", "utf-8");

    res.writeHead(200, { "content-type": "text/html" });
    res.write(homeHTML);
    res.end();
  } else {
    serveStatic("static", req, res);
  }
});

이게 Node.js 기본 문법이다. express나 Nest.js 같은 서버 프레임워크를 쓰지 않고 쌩 Node.js도 이렇게 쓸 수는 있다. 그러나 보통 Node.js가 기술스택이라고 하면 express, Nest를 떠올린다.(가끔 예외로 net 모듈 같은 것도 있긴 하지만)

const express = require("express")
const app = express()
const PORT = 3000;

app.use(express.static("public"))

app.get("/", (req, res) => {
    res.send("<h1> This is root directory! Hello! </h1>")
})

express를 사용하면 이렇게 깔끔해진다.

미들웨어라는 비밀병기를 가진 서버 프레임워크, express

미들웨어는 기본적으로 이런 식으로 next() 메서드를 통해 다음 미들웨어로 점프한다. 이 간결한 구조가 Node 기본 문법에 비해 편의성이 높아 애용되는 편.

app.use로 정적 파일을 읽어올땐 - 그냥 경로만 변경해서 접근하면 된다!

이런 식으로 products 폴더에 정적 리소스를 포함하고 app.use를 통해 읽어들이기까지 완료했다. 그러면 루트경로 하에 추가되었을텐데, 어떻게 접근하면 좋을까?
-> 그냥 /image.png 이런 식으로 접근하면 된다!

express.json()을 쓰는 이유? JSON의 이점 때문

  • 가독성: 사람이 읽고 이해하기 쉬움
  • 표준화: 대부분의 프로그래밍 언어와 호환, 데이터 교환의 표준 포맷
  • 경량성: 텍스트 기반 구조로 적은 오버헤드, 네트워크 대역폭의 효율적 사용

이런 장점을 가지는 JSON을 좀더 편하게 사용하려면, app.js나 index.js에서 app.use(express.json()) 을 선언해주어야 한다. 이게 있어야 JSON으로 송수신 하는 데이터에서 파싱을 쉽게 할 수 있기 때문.

express.urlencoded()를 이용해 데이터를 안전하게 주고받자

app.use(express.urlencoded({extended:true}))

express.urlencoded()를 app.use()로 등록해주면 요청 객체를 req.body에 저장한다. 그러면 서버 코드에서 사용자가 전송한 데이터를 쉽게 사용할 수 있다.

가끔 안에 {extended:true} 이렇게 쓰는 경우가 있는데, 이는 중첩객체 허용여부. true로 놓으면 {user:{name:'John', age:'30'}, hobbies:['reading', 'gaming']} 이렇게 복잡하거나 중첩된 객체도 쓸 수 있다. false로 해놓으면 못 쓰니 이런 구조를 쓰려면 반드시 true로 놓도록 하자.

express는 한 키에 여러 값이 전달되면 배열로 처리한다

이렇게 생긴 라우터에 tags라는 키에 여러 값을 준다고 생각해보자 (해시태그 처럼)

이렇게 배열로 처리되어 표시해준다.

CSR과 SSR은 뭐가 다를까?

CSR의 특징

동적 생성
초기 로딩 성능
서버 부하 감소
SEO 문제 - 웹 크롤러가 JS를 실행하지 않고 HTML만을 분석, 동적 컨텐츠만을 인식하기 때문
편의성 - React, Vue의 톡톡한 역할

  • 사용자 상호작용이 많고 동적 컨텐츠 변경이 빈번한 싱글 페이지에서는 유용!

SSR의 특징

HTML을 서버가 미리 생성해서 클라이언트에게 전달. 이 과정에서 템플릿 엔진 등이 사용된다.

빠른 초기 로딩 성능
SEO
서버 부하 증가
개발 복잡성 증가

뷰 엔진과 템플릿 엔진

뷰 엔진: SSR의 핵심. 서버에서 HTML을 동적으로 생성하여 클라이언트에 전달하는 역할.

템플릿 엔진: 서버에서 처리된 데이터를 웹페이지에 동적으로 삽입하여 사용자에게 보여질 컨텐츠를 생성하는데 사용됨. pug, handlebars, ejs 등이 있음.

app.set("view engine", "ejs")
app.set("views", "./views")

이런 식으로 app.set으로 사용 설정을 할 수 있는데, 이때 views 폴더의 경로는 상대경로와 절대경로 모두 설정할 수 있다.

app.set("views", "./src/views") //상대경로
app.set("views", path.join(__dirname, "src", "views")) // 절대경로

app.get() 과 router.get() 은 뭐가 다를까?

app.~은 애플리케이션 전체의 라우터와 미들웨어 관리에 사용되고, express 라우터인 router.~은 작은 애플리케이션처럼 동작하면서 app객체와 동일한 메서드를 사용하여 라우터를 정의할 수 있다.

express 라우터의 장점

  • 모듈화 및 구조화
  • 관리의 용이성
  • 성능 및 보안 강화

express가 제공하는 응답 처리 방법들

res.send() - 다양한 유형의 응답을 보낼때 쓰는 가장 기본적 응답 유형
res.json() - JSON으로 응답할 때 사용
res.sendFile() - 파일 경로를 인자로 받음. 클라이언트에게 파일 전송
res.status() - http상태코드 반환용
res.setHeader() - http 헤더 설정 시 사용
res.download() - 클라이언트가 파일 다운로드 하도록 함
res.redirect() - 클라이언트를 다른 url로 리다이렉트

비동기 작업의 오류는 자동으로 catch되지 않는다

굳이 try-catch 블록을 씌워주는 이유이다. setTimeout이나 async-await 구문 등에서는 자동으로 잡아주지 않기 때문에 직접 잡아 다음으로 보내줘야 한다.

하나 더 팁. 에러처리 미들웨어는 특별한 조건이 없다면 가장 가까운 것을 호출한다.

uuid를 require 하려고 했는데 왜 안되지? 대 import의 시대

역시나 나와 같은 수많은 오류들을 거쳐온 스택 오버플로우 웨건이 답을 주었다. 결론은 No longer support for require() 인것. "type" : "module" 을 package.json에 써넣고 import()를 사용하라는 것이다.

그렇다면 import와 require를 같이 사용할 수는 없을까?

참고 블로그를 보고 함께 사용하는 방법을 알 수 있었다. 골자는 다음과 같다.

  1. package.json에 "type":"module" 추가하고 저장해서 모듈시스템 사용
  2. 아래 import문과 const문 상단에 추가하기
    import {createRequire} from "module"
    const require = createRequire(import.meta.url)

아니 근데 왜 저걸 해도 터지지? 결론은 import

-> 결론은 대 import의 시대와 같다. index.js에 require로 불러온 js파일이 있었는데 더이상 require를 지원하지 않으니 import로 불러오기 하라는 것이다. type : module을 쓰는 대신 require도 혼용할 수 있도록 import 하고 const로 선언했는데도 이런 오류가 뜬다.

유데미 강의를 들으며 따라하고 있는데 아마 촬영시기와 내가 학습하는 시기의 시차로 인해 강의는 require를 쓰는데 더이상 require를 지원하지 않는 디펜던시가 있어 그런 것 같다.

GPT에게 물어보니 답변은 다음과 같았다.

  • import와 require의 혼용은 권장하지 않는다. (실제로 혼용해보려고 애쓰다가 에러남)
  • require 쓰려고 모듈의 버전을 억지로 낮춰 사용하는 것도 권장하지 않는다
  • 현업에서 require를 쓰는건 맞지만 import로 바꾸기엔 규모가 너무 커서 그냥 쓰는 것이고, 신규 프로젝트는 import를 많이 쓴다
  • 지금 니 프로젝트 구조는 이미 ESM이니까 이왕이면 import로 바꾸는게 낫다
  • 강의때문에 require를 유지하고 싶으면 uuid만 import해서 우회하는 방법도 있다

라고 한다. 해서 uuid만 import하는 방식으로 바꿔봤지만, 그랬더니 js파일 require 부분도 걸려있다. require와 import를 병용해볼까도 고민했지만 권장하는 방법이 아니라고 하니 import로 바꿔 정리하고 있다.

require에서는 :, import에서는 as

named import 시 별칭을 쓰는 방법이 다르다. require로 불러올때는 콜론으로 구분하는데 import로 불러올때는 as를 써줘야 별칭을 쓸수있다.

내 yarn이 왜 고장났지? yarn 4.2.2를 쓰는 방법

패키지 매니저로 yarn을 사용하려면 단순히 npm install -g yarn을 쓰고 넘어갈 수도 있다. (이러면 1.22.22) 그러나 yarn은 사실 4.2.2 버전까지 나와있다. 남들은 에러메시지가 떠서 yarn을 업그레이드 하면 해결된다는데, 나는 yarn을 업그레이드 했더니 에러메시지가 떠서 굉장히 고생을 했다.
(원인은 아마 Node를 22에서 24로 업그레이드 한 탓인 것 같다.)

문제상황: 나는 yarn 4.2.2(yarn berry)를 깔았는데 yarn -v 하면 자꾸 1.22.22가 뜨고, 이 프로젝트의 yarn 버전은 4.2.2인데 너는 1.22.22를 쓰고있다는 에러메시지와 함께 아무것도 할 수 없었다.

error This project's package.json defines "packageManager": "yarn@4.2.2". However the current global version of Yarn is 1.22.22.

Presence of the "packageManager" field indicates that the project is meant to be used with Corepack, a tool included by default with all official Node.js distributions starting from 16.9 and 14.19.     
Corepack must currently be enabled by running corepack enable in your terminal. For more information, check out https://yarnpkg.com/corepack.
Installing yarn@4.2.2 in the project...

아니! 환장할 노릇이네 분명히 corepack enable도 하고 corepack use yarn@4.4.2도 했는데 자꾸 1.22.22가 잡히는 것이었다. where yarn 하면 아무 경로도 잡히지 않고...

GPT가 알려준 현 상황과 해결책은 대강 이렇다.

  • corepack yarn -v 했을때 4.2.2면 제대로 깔린 건 맞다
  • 다만 yarn -v에서 1.22.22로 나오는건 그 버전이 제대로 지워지지 않았기 때문인 것 같다
  • Get-Command yarn -All 해서 C:\Users\LIHA\AppData\Roaming\npm\yarn.cmd가 있으면 1.22.22가 환경변수로 여기 남아있을 가능성이 크다
  • C:\Users\LIHA\AppData\Local\Yarn\bin\ 이것도 뜬다면 옛날 yarn 설치 흔적이 있으니 거의 확정
  • 그러니 위 경로에 가서 쟤네를 지우는 것이 가장 깔끔하다

하여 환경변수 경로 가서 yarn 관련 파일들을 모두 날려주니 정상적으로 4.2.2가 출력되었다.

HTML 5 기본뼈대를 자동 입력하려면 html:5를 입력후 엔터하자

왜 나는 그간 !DOCTYPE 부터 타이핑하고 있었던걸까. 흑흑. 이걸... 이걸 치면 되는 것이었어!

profile
갑자기 왜 춤춰?

0개의 댓글