NextJS 란?
React의 SSR(Server Side Rendering)을 쉽게 구현할 수 있게 도와 주는 간단한 프레임워크입니다.
React로 개발할 때는 SPA(Single Page Application)을 이용하여 CSR(Client Side Rendering)을 이용하기 때문에 좋은 점도 있지만 단점으로는 검색엔진 최적화(SEO : Search Engine Optimization) 부분입니다.
CSR을 하면 첫페이지에서 빈 html을 가져와서 JS파일을 해석하여 화면을 구성하기 때문에 포털 검색에 노출되기가 쉽지않습니다.
(물론 구글검색엔진은 똑똑해서 괜찮)
하지만 NextJS에서는 Pre-Rendering 또는 SSR을 통해서 페이지를 미리 렌더링 하여 완성된 HTML으 가져오기 때문에
사용자와 검색 엔진 크롤러에게 바로 렌더링 된 페이지를 전달하 수 있게 됩니다.
Server Side Rendering(SSR)
- 클라이언트 대신 서버에서 페이지를 준비하는 원리입니다.
- 원래 리액트에서는 기본적으로 CSR을 하기 때문에 서버에 영향을 미치지 않고, 서버에서 클라이언트로 응답해서 보낸 html도 거의 비어 있습니다. => 이 방식은 서버에서 데이터를 가져올 때 지연 시간 발생으로 UX 측면에서 좋지 않을 수 있습니다.
- 이는 검색 엔진에 검색 시 웹크롤링이 동작할 때 내용을 제대로 가져와 읽을 수 없기에 검색엔진 최적화에 문제가 된다.
- NextJS는 SSR을 이용하므로 사용자와 검색엔진 크롤러에게 바로 렌더링 된 페이지를 전달할 수 있어 검색엔진 최적화에 좋은 영향을 준다.
-- NextJS + typescript 프로젝트 생성방법
npx create-next-app@latest [프로젝트명] --typescript
//or
yarn create next-app [프로젝트명] --typescript
NextJS 기본 폴더구조
pages
- 이 폴더 안에 페이지들을 생성합니다.
- index.tsx가 처음 "/" 페이지로 됩니다.
- _app.tsx는 공통되는 레이아웃을 작성합니다. 모든 페이지에 공통으로 들어가는 걸 넣어주려면 여기에 넣어주시면 됩니다.(url을 통해 특정 페이지에 진입하기 전 통과하는 인터셉터 페이지입니다.)
- 만약 about이라는 페이지르 만드시려면 pages 폴더 안에 about.tsx를 생성해주면 됩니다.
public
- 이미지 같은 정적(static) 파일들을 보관합니다.
styles
-말 그대로 스타일링을 처리해주는 폴더입니다.
- module.css는 컴포넌트 종속적으로 스타일링하기 위한 것이며, 확장자 앞에 module을 붙여줘야 합니다.
next.config.js
-NextJS는 Webpack을 기본 번들러로 사용합니다.
- 그래서 Webpack에 관한 설정들을 이 파일에서 해줄 수 있습니다.
tsconfig.json
- typescript로 짜여진 코드를 JavaScript로 컴파일하는 옵션을 설정하는 파일입니다.
- typescript 컴파일은 tsc 라는 명령어를 사용합니다.
- 커맨드로 생성하려면 npx tsc --init
Pre-rendering
NextJS는
모든 페이지를 pre-render 합니다. 이 pre-render한다는 의미는 모든 페이지를 위한 HTML을 Client side에서 JS로 처리하기 전, "사전에" 생성한다는 것입니다. 이렇게 하기 때문에 SEO 검색엔진 최적화에 도움이 됩니다.
NextJS Data Fetching
NextJS에서 데이터를 가져오는 방법은 여러가지가 있습니다.
그래서 애플리케이션의 사용 용도에 따라서 다른 방법을 해주시면 됩니다.
보통 리액트에서는 데이터를 가져올 때 useEffect안에서 가져옵니다. 하지만 NextJS에서는 다른 방법을 사용해 가져오는데 하나씩 간단히 살펴보도록 합시다.
getStaticProps
- getStaticProps 함수를 async로 export하면, getStaticProps에서 리턴되는 props를 가지고 페이지를 pre-render합니다.
- build time에 페이지를 렌더링 합니다.
function Blog({ posts }) {
return (
<ul>
{posts.map((post, i) => (
<li key={i}>{post.title}</li>
))}
</ul>
);
}
export async function getStaticProps(context) {
const resp = await fetch("https://.../posts");
const posts = await resp.json();
return {
props: { posts },
};
}
getStaticProps를 사용해야 할 때
- 페이지를 렌더링하는 데 필요한 데이터는 사용자의 요청보다 먼저 build 시간에 필요한 데이터를 가져올 때
- 데이터는 Headless CMS에서 데이터를 가져올 때
- 데이터를 공개적으로 캐쉬할 수 있을 때(사용자별 아님)
- 페이지는 미리 렌더링되어야 하고(SEO의 경우)매우 빨리할 때(getStaticProps는 성능을 위해 CDN에서 캐쉬할 수 있는 HTML 및 JSON 파일을 생성합니다)
getStaticPaths
- 동적 라우팅이 필요할 때 getStaticPaths로 경로 리스트를 정의하고, HTML에 build 시간에 렌더 됩니다.
// 기본 syntax
export async function getStaticPaths() {
return {
paths: [{ params: { ... } }],
fallback: true, //or false
};
}
paths
- 어떠한 경로가 pre-render될지를 결정합니다.
- 만약 pages/posts/[id].js라는 이름의 동적 라우팅을 사용하는 페이지가 있다면 아래와 같이 됩니다.
export async function getStaticPaths() {
return {
paths: [{ params: { id: "1" } }, { params: { id: "2" } }],
fallback: ...
};
}
- 빌드하는 동안 /posts/1과 /posts/2를 생성하게 됩니다.
params
- 페이지 이름이 pages/posts/[postId]/[commentId]라면, params는 postId와 commentId입니다.
- 만약 페이지 이름이 pages/[...slug]와 같이 모든 경로를 사용한다면, params는 slug가 담긴 배열이여야 합니다. ['postId','commentId']
fallback
- false라면 getStaticPaths로 리턴되지 않는 것은 모두 404페이지가 뜹니다.
- true라면 getStaticPaths로 리턴되지 않는 것은 404로 뜨지 않고, fallback 페이지가 뜨게 됩니다.
function Post({post}) {
return (
//Render post..
);
}
export async function getStaticPaths() {
const resp = await fetch("https://.../posts");
const posts = await resp.json();
const paths = posts.map((post: any) => {
params: {
id: post.id;
}
});
return {
paths,
fallback: true, //or false
};
}
export async function getStaticProps({ params }) {
const resp = await fetch(`https://.../posts/${params.id}`);
const post = await resp.json();
return {
props: { post },
};
}
export default Post;
getServerSideProps
- getServerSideProps 함수를 async로 export 하면 Nextsms 각 요청마다 리턴되는 데이터를 getServerSideProps로 pre-render합니다.
function Page() {
return (
//Render page..
);
}
export async function getServerSideProps() {
const resp = await fetch("https://.../data");
const data = await resp.json();
return {
props: { data },
};
}
export default Page;
getServerSideProps를 사용해야 할 때
- 요청할 때 데이터를 가져와야하는 페이지를 미리 렌더해야 할 때 사용합니다. 서버가 모든 요청에 대한 결과를 계산하고, 추가 구성없이 CDN에 의해 결과를 캐시할 수 없기 때문에 첫번째 바이트까지의 시간은 getStaticProps보다 느립니다.
NextJS official Docs에 있는 blog 만들어보기 중 .md를 데이터화 하는 법(with gray-matter)
import fs from "fs";
import path from "path";
import matter from "gray-matter";
const postsDirectory = path.join(process.cwd(), "posts");
console.log("postDirectory : ", postsDirectory);
export function getSortedPostsData() {
//posts 파일이름 잡아주기
const fileNames = fs.readdirSync(postsDirectory);
//[pre-rendering.md...]
console.log("fileNames : ", fileNames);
const allPostData = fileNames.map((fileName) => {
const id = fileName.replace(/\.md$/, "");
const fullPath = path.join(postsDirectory, fileName);
console.log("fullPath : ", fullPath);
const fileContents = fs.readFileSync(fullPath, "utf-8");
const matterResult = matter(fileContents);
return {
id,
...(matterResult.data as { date: string; title: string }),
};
});
return allPostData.sort((a, b) => {
if (a.date < b.date) {
return 1;
} else {
return -1;
}
});
}
'NextJS' 카테고리의 다른 글
[NextJS] Github 로그인 연결해보기 (0) | 2023.12.09 |
---|---|
NextJS 정리(v13 이전) (0) | 2023.01.30 |