신입 웹프론트엔드 개발자 2개월 차 후기
0. 들어가며
안녕하세요. 비브로스 웹프론트엔드팀 신입 개발자 박서영입니다. 😀 5월 9일에서 7월 14일까지 약 두 달여 간의 온보딩 과정이 마무리되었습니다. 장장 10차에 걸친 온보딩을 진행하면서 새롭게 학습한 내용, 그리고 좋았던 점과 아쉬웠던 점을 공유해보고자 합니다.
1. 새롭게 학습한 내용
Next.js
pre-rendering
Next.js에서는 클라이언트 사이드가 아니라 서버 사이드에서 HTML을 pre-rendering 합니다. pre-rendering에는 SSG (static generation), SSR(server-side rendering) 두 가지 방식이 있으며 페이지 단위로 적용할 수 있습니다.
- SSG - HTML이 빌드 타임에 생성된다.
- SSR - HTML이 유저 요청 시에 생성된다.
fallback
동적 라우팅 페이지가 외부 데이터에 의존할 경우, getStaticPaths를 사용하여 빌드 타임에 필요한 path들을
pre-rendering할 수 있습니다. 이때, fallback
옵션을 통해 사전에 생 성하지 않은 route들에 대해서 유저 요청 시
생성하거나 커스텀한 에러 페이지로 핸들링할 수 있습니다.
export async function getStaticPaths() {
return {
paths: [
{ params: { ... } }
],
fallback: false // true or 'blocking'
};
}
-
fallback: false
- status code 404 반환(
_error
next custom error 페이지로 핸들링)
- status code 404 반환(
-
fallback: true
- 유저 요청이 들어오면 getStaticProps를 호출해 페이지 생성
- 페이지를 생성하는 동안 fallback HTML을 브라우저에 전달
- 페이지 생성이 완료되면, 페이지를 다시 렌더링
- path 리스트에 추가되어 이후 요청부터 static한 페이지 제공
import { useRouter } from 'next/router'
function Post({ post }) {
const router = useRouter()
// If the page is not yet generated, this will be displayed
// initially until getStaticProps() finishes running
// fallback:true 시 페이지를 생성하는 동안 보여주는 페이지
if (router.isFallback) {
return <div>Loading...</div>
}
}
export async function getStaticPaths() {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
fallback: true,
}
}
// This also gets called at build time
export async function getStaticProps({ params }) {
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
return {
props: { post },
}
}
export default Post -
fallback: blocking
- 유저 요청이 들어오면 getStaticProps를 호출해 페이지 생성
- 페이지 생성이 완료되면, 페이지를 다시 렌더링
- 빌드된 path 리스트에 추가되어 이후 요청부터 static한 페이지 제공
-
주의사항: SSG는 production 모드의 build 타임에 가동된다.
- In development:
(npm run dev or yarn dev) getStaticProps runs on every request.
- In production: getStaticProps runs at build time.development 모드에서는 요청이 올 때마다 getStaticProps가 실행됩니다. getStaticProps도 SSR처럼 동작하기 때문에 build한 뒤에 start 스크립트를 통해 production 서버를 켜서 확인해야 합니다.
revalidate
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
// Next.js will attempt to re-generate the page:
// - When a request comes in
// - At most once every 10 seconds
revalidate: 10, // In seconds
}
}
Next.js 공식문서에서 SSG 사용 예시로 Marketing pages, Blog posts, E-commerce
product listings, Help and documentation를 들고 있습니다. ‘빌드 타임에 생성되는데 유저가 blog post를 업데이트하면 어떻게 반영을 한다는 거지?’ 궁금증이 생겼습니다. 찾아보니 SSG도 빌드타임 이후에 DB의 업데이트 상황을 점진적으로 반영할 수 있는 revalidate
옵션이 있었습니다. 페이지에 접속해있으면 n초마다 갱신되는 방식은 아니고 build time/ re-generate time을 기준으로 n초 뒤에 요청이 들어오면 페이지 갱신을 시도합니다. 갱신이 trigger되는 방식이 헷갈릴 수 있는데, Next.js에서 이를 테스트할 수 있는 사이트가 있습니다.
- 예를 들어 A,B,C라는 유저들이 페이지에 접속했습니다. 이 페이지의 좋아요(👍)는 2,743개입니다.
- 유저 A가 좋아요를 눌러 좋아요는 2,744개가 됐습니다.
- 유저 B가 페이지를 새로고침합니다. 이때 regeneration이 trigger 되지만 캐시된 페이지를 그대로 받아옵니다. 페이지의 좋아요는 2,743개, 달라진 게 없으므로 status code는 304(Not Modefied)입니다.
- 유저 C가 페이지를 새로고침합니다. regeneration이 trigger된 이후에 페이지를 요청했기 때문에 업데이트된 페이지를 받아옵니다. 페이지의 좋아요는 2,744개, 서버가 요청을 성공적으로 응답했기 때문에 status code 200입니다.
모노레포
모노레포(Monorepo)란, 하나의 레파지토리에 두 개 이상의 프로젝트를 관리하는 소프트웨어 개발 전략입니다. 10차까지 되는 온보딩을 진행하면서 정말 많은 레파지토리를 생성했는데요. 기존의 멀티레포(Multirepo) 방식으로는 새로운 프로젝트를 시작할 때마다 레파지토리를 생성하고 개발환경을 구축하는 등 번거로운 과정을 반복해야 합니다. 그리고 여러 레파지토리에 서 사용하는 패키지에서 변화가 있을 때 일일이 반영해줘야 한다는 단점도 있습니다. 모노레포 방식을 적용하면 기존 환경을 활용하므로 개발 환경 구축 작업을 반복하지 않아도 됩니다. 그리고 공통 모듈은 단일화하여 효율적으로 의존성을 관리할 수 있습니다.
Dependency Module Hoisting
(yarn workspace를 사용한다는 가정하에) yarn
명령어를 실행하면 루트의 package.json
과 각
패키지의 package.json
에 명시되어있는 dependency가 최대한 중복을 줄인 상태로 루트의 node_modules
안에 호이스팅됩니다. 이때 루트 경로의 node_modules
에는 각 workspace들이 참조할 수 있는 symbolic link
가 생성됩니다.
https://classic.yarnpkg.com/blog/2018/02/15/nohoist/
https://classic.yarnpkg.com/blog/2018/02/15/nohoist/
예를 들어 package-1는 A와 ‘A를 의존성 모듈로 이용하는’ C를 의존성 모듈로 이용하고 있습니다. 동일한 의존성을
지니는 모듈은 중복 설치할 필요가 없으므로 함께 쓸 수 있도록 루트의 node_modules