react는 가장 인기 있는 자바스크립트 라이브러리이며 수백만 개 이상의 웹 사이트에서 다양한 목적으로 사용되고 있다. 단, 리액트는 기본적으로 클라이언트 사이드에서만 작동한다는 큰 문제점을 가지고 있다. 사용자의 웹 브라우저에서만 실행되기 때문에 리액트를 사용한 웹 애플리케이션은 검색 엔진 최적화search engine optimization(SEO)의 효과를 거의 볼 수 없으며, 첫 화면에 웹 애플리케이션을 제대로 표시하기 위해 애플리케이션 실행 초기에 성능 부담이 생긴다. 웹 앱을 완전히 표시하려면 브라우저가 전체 웹 애플리케이션 번들을 다운로드한 다음 그 내용을 분석하고 코드를 실행해서 결과를 얻어야 하기 때문입니다. 그래서 아주 큰 웹 애플리케이션에서는 첫 화면을 표시하기까지 수 초가 소요되기도 한다.
이 문제를 해결하기 위해 많은 개발자들이 웹 애플리케이션을 서버에서 미리 렌더링해두는 방법을 연구하기 시작했고 서버 사이드 렌더링을 사용할 수 있다면 리액트 앱을 순수한 HTML페이지로 미리 렌더링해둔 다음 브라우저가 이를 다운로드하여 즉각 화면에 표시하고 클라이언트에서 자바스크립트 번들을 다 받으면 사용자가 웹앱과 상호 작용할 수 있게된다. 이러한 배경에서 개발된 것이 NextJs다.
Next.js는 리액트에서 제공하지 않는 여러 기능을 지원하며 컴포넌트뿐만 아니라 설정이나 개발 옵션 등 다양한 부분에서도 유용한 기능들을 제공한다.
✨ 요약
왜 NextJs를 사용하는가
1. 클라이언트 렌더링의 경우 모든 js 파일을 로드하고 사용자는 웹을 보게되어서 이러한 과정동안 사용자는 많은 시간을 대기해야한다. 하지만 NextJs의 경우 서버사이드 렌더링 즉, 서버에서 자바스크립트를 로딩함으로 클라이언트 측에서 자바스크립트를 로딩하는 시간이 줄어들게 된다.
2. 클라이언트 사이드의 경우 자바스크립트가 로드 되지 않은 경우 아무런 정보를 보이지 않는다. 구글의 검색엔진으로 스캔함으로 결론적으로 검색에 아무 페이지도 걸리지 않게 된다. 이러한 문제를 NextJs에서는 서버측에서 자바스크립트, html,css를 만들어 컨텐츠를 직접 업로드 함으로 검색엔진에 게시글이 걸리게 된다.
가장 큰 차이점은 리액트는 자바스크립트 라이브러리이고 NextJs는 프레임워크
라는 점이다. Next.js는 클라이언트와 서버에서 실행할 수 있는 코드에 풍부하고 다양한 기능을 제공하여 웹 애플리케이션을 만들 수 있게 해준다.
서버 사이드 렌더링 페이지나 정적으로 생성된 페이지 모두 Node.js에서 실행되기 때문에 fetch, window, document와 같이 웹 브라우저에서 제공하는 전역 객체나 canvas 같은 HTML 요소에는 접근할 수 없다.
> npx create-next-app <app-name>
개발환경에 NodeJs와 npm만 설치하면 된다. 위와같은 명령어를 터미널에 입력하면 필요한 의존성 패키지들이 설치되고 몇개의 기본 페이지가 생성된다. 이후 npm run dev 혹은 yarn패키지가 설치되어 있는 경우 Next.js는 yarn 패키지 관리자를 사용해서 프로젝트를 초기화 하는데 이때도 npm을 기본적으로 사용하고 싶다면
> npx create-next-app <app-name> --use-npm
이 명령어를 통해 덮어쓸수있다. Next.js GitHub 저장소에서 원하는 보일러플레이트 코드를 다운로드해서 새 Next.js 프로젝트를 시작할 수도 있다. Next.js 저장소에는 example 디렉터리가 있는데 이곳에는 다양한 기술이 사용된 훌륭한 예제 코드가 있다.
만약 Next.js 앱을 도커 환경에서 실행하는 예시를 보고 싶다면 다음과 같이 --example 옵션으로 어떤 보일러플레이트 코드를 사용할 것인지 알려주면 된다.
> npx create-next-app <app-name> --example with-docker
> npx create-next-app nextjs-blog --use-npm --example "깃클론주소"
- README.md
next.config.js
node_modules/
package-lock.json
package.json
pages/
_app.js
api/
index.js
public/
favicon.ico
vercel.svg
styles/
Home.module.css
globals.css
hot reloading
개발중 저장되는 코드는 자동으로 새로고침이 된다.
automatic routing
pages폴더에 있는 파일은 해당 파일 이름으로 라우팅된다.
예로 pages/page1.tsx -> localhost:3000/page1
public 폴더도 pages의 폴더와 동일하게 라우팅할 수 있다. 그러나 모든 사람이 페이지에 접근할 수 있으므로 지양해야한다.
single file components
style jsx를 사용함으로 컴포넌트 내부에 해당 컴포넌트 스코프를 가지는 css를 만들 수 있다.
(pages/index.js)
글로벌 스타일 정의 가능
_app.tsx에만 정의 가능하다. 다른 컴포넌트에 정의한 경우 다른 클래스와 겹쳐 오류를 발생할 수 있음으로 _app에서만 허용한다. 다른 컴포넌트에 정의시 아래와 같은 오류를 낸다.
ㅇ에러메시지
Global CSS cannot be imported from files other than your Custom . Please move all global CSS imports to pages/_app.tsx. Or convert the import to Component-Level CSS (CSS Modules).
code splitting
dynamic import를 이용하면 손쉽게 코드 스플리팅이 가능하다.
코드 스플리팅은 내가 원하는 페이지에서 원하는 자바스크립트와 라이브러리를 렌더링 하는 것이다. 모든 번들(chunk.js)이 하나로 묶이지 않고, 각각 나뉘어 좀 더 효율적으로 자바스크립트 로딩 시간을 개선할 수 있다.
typescript
타입스크립트 활용을 위해 웹팩이나 바벨을 만질 필요가 없다. 타입스크립트를 설치하고 (yarn add typescript @types/node @types/react) 명령어 (yarn run dev)만 하면 자동으로 tsconfig, next-end.d.ts가 생성되어 타입스크립트로 코딩이 가능해진다.
react의 react-router-dom과 사용 방법은 거의 유사하다. link에 있는 preferch 기능도 사용 가능하다.
prefetching
백그라운드에서 페이지를 미리 가져온다. 기본값은 true. 뷰포트에있는 모든 항목 (초기 또는 스크롤을 통해)이 미리 로드된다. 정적 생성을 사용하는 JSON페이지는 더 빠른 페이지 전환을 위해 데이터가 포함 된 파일을 미리 로드한다.
이건 Link 컴포넌트를 사용해서 이뤄지며, 링크 컴포넌트를 렌더링할때 형식으로 prefetch 값을 전달해주면 데이터를 먼저 불러온다음에 라우팅을 시작한다.
프로덕션 레벨에서만 이루어진다.
<script>
import { useEffect } from "react";
import { useRouter } from "next/router";
import posts from "../posts.json";
export default () => {
const router = useRouter();
const post = posts[router.query.id as string];
if (!post) return <p>noting</p>;
useEffect(() => {
router.prefetch("/test");
}, []);
return (
<>
<h1>{post.title}</h1>
<h1>{post.content}</h1>
<button onClick={() => router.push("test")}>go to Test</button>
</>
);
};
</script>
따로 config파일을 정의하지 않고 이 css파일을 scss로 바꾸고 yarn add sass --dev를 해주면 next에서 알아서 설정 해준다.
보통 페이지간 이동은 a태그를 사용하지만 next에서는 a태그를 사용하지 않는다. a태그를 사용하면 처음 페이지에 진입시 번들 파일을 받고, a태그에 의해 라우팅 되면 다시 번들 파일을 받기 때문이다. 또한 redux을 쓰는 경우 store의 state값이 증발되는 현상도 일어난다. 그렇기 때문에 a태그는 전혀 다른 사이트로 페이지를 이동시켜 다시 돌아오지 않는 경우만 사용하고 이외에는 모두 Link태그를 사용한다.
<script>
import Head from "next/head";
export default function Home() {
return(
<div>
<Head>
<title>Create Next App</title>
</Head>
<div>...</div>
</div>
);}
</script>
next/head로 부터 Head컴포넌트를 받아 모든 컴포넌트에서 사용할 수 있다.
next.js가 해당 컴포넌트가 mount할때, Head내 태그들을 페이지의 HTML의 Head에 포함 시킨다. 마찬가지로 unMount할때, 해당 태그를 제거한다.
참고
next.js 기본 개념 알아보기
리액트에서 Next.js로, 넥스트JS의 특장점과 빠르게 시작하는 법 알아보기