[Next.js] Next.js 12 변경사항
🤔 서론
작년 10월, Next.js 12버전이 빠르게 릴리즈되었고 컴파일러를 기존 Babel에서 Rust 기반의 SWC로 바꾸면서 빌드 속도가 대폭 상향됬다는 걸 알게되었다.
좀 더 알아보니, 이 뿐만 아니라 최근에 릴리즈된 React 18의 기능들을 지원하기 위한 업데이트도 포함된 것을 확인했다.
이번 기회에, 최근 Next가 12버전으로 업데이트 되면서 어떠한 변화들이 있었는지 한 번 정리해보려고 한다.
🤍 Next.js 12 업데이트
2021년 10월, 11버전이 업데이트된지 약 3달만에 Vercel(Next 개발사)은 다시 12버전을 발표하게 된다.
이번 배포는 개발자 경험(DX, Developer Experience)을 향상시키는 기능, React 18 업데이트 등에 초점이 맞춰져있다고 한다.
- Rust Compiler: 로컬에서 refresh 속도 3배, 프로덕션에서 build 속도 5배 증가
- Middleware(beta): 미들웨어를 통해 서버 단에서 페이지 이동 등을 조건부로 제어
- React 18 Support: Suspense 등 18버전 지원
- <Image /> AVIF Support: webP보다 20% 압출률이 더 좋은 AVIF 포맷 지원
- Bot-aware ISR(Incremental Static Regeneration) Fallback: 정적 사이트 재생성. 웹 크롤러에 최적화된 SEO 지원
- Native ES Module Support: 표준화된 모듈 시스템
- URL Imports(alpha): 모든 url에서 패키지 가져오기. 직접 모듈 설치가 불필요.
- Server Component(alpha): 컴포넌트 레벨에서 SSR 로직까지 처리 가능
위 리스트들을 하나씩 상세하게 알아보도록 하자!
1. Rust Compiler
네이티브 컴파일을 기반으로 하는 SWC(Rust 컴파일러)로 변경되어서,
로컬에서 3배 더 빠른 새로고침과 프로덕션에서 5배 더 빠른 빌드로 번들링과 컴파일에 최적화되었다.
또한, SWC는 Babel보다 17배 빠르기에 Next.js 12에서 Javascript, Typescript 컴파일링(파일 변환)을 대체한다.
* Rust 언어가 병렬작업 등 장점이 있어 Babel, Teaser 등에 의한 빌드보다 빠른 것이다. (참조링크)
SWC는 이전 버전과 호환되기 위해 Next 설정파일에서 옵셔널하게 설정 가능하며,
styled-components, emotion, relay 등 인기 라이브러리에 대한 구문 분석도 곧 이식될 예정이라고 한다.
// next.config.js
module.exports = {
swcMinify: true
}
2. Middleware 기능 추가
미들웨어를 통해 페이지 요청이 완료되기 전에 응답 수정, redirection, 헤더 추가, HTML 스트리밍 등이 가능하다.
이를 통한 안정성 향상(Bot으로부터 보호), A/B 테스트, 서버사이드 분석, 로깅 등이 가능해진다.
* 사용법
// pages/_middleware.js
export function middleware(req, ev) {
return new Response('Hello, world!')
}
Next.js 에서 pages 디렉토리 내 폴더 구조가 routing 구조로 이루어지는 것을 알 것이다.
위처럼 미들웨어를 설정하면, pages 폴더 아래의 모든 페이지에 대해 미들웨어가 동작하게 된다.
- package.json
- /pages
index.tsx
- /about
_middleware.ts # Will run first
about.tsx
- /teams
_middleware.ts # Will run second
teams.tsx
위처럼 각 라우팅별로 다른 미들웨어를 동작시킬수도 있다. 이 때, 상위 라우팅의 미들웨어부터 실행되게 된다.
3. React 18 지원 준비
React 18의 Automatic Batching, Suspense, startTransition 등의 API와 React.lazy 서버 컴포넌트 지원을 위한 streaming API 같은 기능들이 추가된다고 한다.
* React 18 주요 변경사항(포스팅) : https://abangpa1ace.tistory.com/252?category=905014
4. <Image/> 태그의 AVIF 포맷 지원
<Image/> 태그(Image Optimization API)는 압축률이 가장 높은 AVIF 포맷을 지원하게 된다. (WebP에 비해 20% 압축됨)
// next.config.js
module.exports = {
images: {
formats: ['image/avif', 'image/webp'],
},
}
AVIF는 WebP에 비해 최적화하는데 시간이 오래 걸리므로 위처럼 config에 설정하여 사용한다.
AVIF, WebP 포멧을 순차적으로 적용하며, 브라우저가 둘 모두를 지원하지 않는 경우 원본 이미지 포맷으로 제공된다.
5. 크롤링 봇(Bot) 인식을 위한 ISR Fallback
ISR(Incremental Static Regeneration, 증분 정적 재생성)의 개념은 공식문서에서 아래처럼 설명한다.
Next.js allows you to create or update static pages after you’ve built your site.
Incremental Static Regeneration (ISR) enables you to use static-generation on a per-page basis, without needing to rebuild the entire site.
With ISR, you can retain the benefits of static while scaling to millions of pages.
즉, SSG(Static Generation)로 만들어놓은 사이트도 필요하다면 업데이트가 가능하다는 것이다.
getStaticProps()로 정적 생성하는 페이지에 옵션 설정을 추가해주면 된다.
// /pages/post/[id].jsx
function Page({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// the path has not been generated.
export async function getStaticPaths() {
const res = await fetch('https://.../posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: blocking } will server-render pages
// on-demand if the path doesn't exist.
return { paths, fallback: 'blocking' }
}
// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
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
}
}
export default Page
- 우선, build 시 정적생성할 경로들을 getStaticPaths로 전달받는데, 여기서 fallback: 'blocking' 옵션을 설정한다.
fallback은 getStaticPaths에서 반환하지 않은 경로로 접근할 때 처리하는 옵션이다.
- false: 모두 404 페이지로 연결
- true: fallback 페이지 -> 서버에서 페이지 생성 -> 페이지 노출 순. 이후, 해당 경로는 이 페이지를 바로 보여줌
- 'blocking': 서버에서 페이지 생성 -> 페이지 노출 순. fallback 페이지를 노출하지 않음
- getStatipcProps에서 revalidate 옵션이 추가되었다.
해당 경로로 어느 사용자가 진입하면, 옵션으로 설정한 시간 이후에 정적 페이지를 갱신한다는 것이다.
이 때 Next.js 12에선 User-Agent를 확인해서, 일반유저는 ISR 동작을 진행하나 크롤러라면 server-render된 ISR 페이지를 제공하여 로드중인 상태가 크롤링되는 것을 방지한다.
6. ES Modules 지원
ES모듈은 기존 Node.js에서 사용하돈 모듈 시스템인 CommonJS와 달리 비동기 환경에서 모듈로더를 실행하므로 클라이언트 환경에 최적화되어있다.
Next.js 11.1부터 CommonJS보다 우선순위가 높은 ES모듈에 대한 실험지원을 추가했고, Next.js 12에선 기본값으로 제공한다.
7. URL Imports(URL 가져오기)
URL을 통해 ES모듈을 가져오는 실험적 기능이 포함된다. (별도의 설치 혹은 빌드단계 불필요)
이를 통해, URL로 패키지를 사용(CDN 등)하며, 원격 리소스(http, https)를 로컬 종속성과 똑같이 처리가 가능하다.
URL Imports는 config로 설정하며, 이것이 감지되면 Next는 next.lock 파일을 생성하여 로컬에 캐싱하여 오프라인 작업도 가능도록 해준다.
// next.config.js
module.exports = {
experimental: {
urlImports: ['https://cdn.skypack.dev'],
},
}
위 설정만 하면, 이후 직접적으로 URL에서 모듈을 가져올 수 있다.
// import 구문
import confetti from 'https://cdn.skypack.dev/canvas-confetti'
8. Server-Side Streaming & Server Component
Next.js 12의 주요한 변화 중 하나이다.
React 18의 Concurrent(동시성) 을 위한 <Suspense>과, startTransition API, React.lazy SSR 스트리밍 API 등을 제공하며,
Next.js 12 역시 React 18의 HTTP 스트리밍에 최적화된 설정을 제공하고자 하는 것이다.
이를 사용하려면 config 설정을 하면 된다.
// next.config.js
module.exports = {
experimental: {
concurrentFeatures: true
}
}
* Server Component
서버사이드 렌더링과 서버 컴포넌트는 근본적으로 다르다.
서버사이드 렌더링은 웹서버에서 HTML을 받은 클라이언트가 JS를 Hydration하면서 페이지가 활성화된다.
반면, 서버 컴포넌트는 리렌더링이나 데이터 갱신이 서버쪽에서 실행되므로 클라이언트 코드가 많이 경량화된다.
Component.server.js로 적용하며, 이를 통해 SSR을 컴포넌트 단위로 나누어 React Hooks Model에 더욱 부합하게 된다.
* getServerSideProps, getStaticProps와 같은 페이지 컴포넌트 세팅이 불필요해질지도?
config에 concurrentFeatures, serverComponents 2가지 옵션을 세팅해서 적용하며,
현재 Next.js에서 서버 Suspense, 선택적 Hydration 및 Streaming 작업 이후에 추진할 계획이라고 한다.
// next.config.js
module.exports = {
experimental: {
concurrentFeatures: true,
serverComponents: true,
},
}
- 기타 개선사항
- 이제 애플리케이션에 pages/_app.js 또는 pages/_document.js를 추가하면 Next.js CLI를 재부팅 할 필요 없이 기본 제공 버전이 자동으로 변경
- ESLint 통합은 이제 --file 플래그를 사용하여 단일 파일 린트를 지원
- 사용자 지정 tsconfig.json 경로 설정을 지원
- next.config.mjs는 이제 구성을 ES 모듈로 작성하는 데 지원
- getStaticProps에 대해 진행 중인 요청이 중복 제거
- 빠른 새로고침이 EventSource 연결 대신 WebSocket 사용
- 수정사항
- Next.js 11에서 webpack 5를 기본으로 설정한 후 공식적으로 webpack 4를 제거
- next.config.js에서 이제 target 옵션은 불필요
- next/image는 이제 래핑 요소로 div 대신 span
- ES 모듈을 지원하는 최소 Node.js 버전은 12.0.0에서 12.22.0으로 상향
Next 11버전도 작년 초에 출시된걸로 보았는데, 5개월만에 다양한 기능이 추가된 12버전이 릴리즈된게 대단하다.
이전 동료 개발자분이 말씀해주신 대로, Babel 대신 SWC를 쓰는 것이 컴파일링 시장의 지각변동을 예고하는 것만 같다.
Nuxt에서도 페이지 진입검사 등으로 유용하게 사용한 Middleware가 추가된 점, React 18과의 싱크 등 바람직한 변경들이 많다는 느낌이다.
📎 출처
- [Next 공식문서] Next 12 : https://nextjs.org/blog/next-12
- [Next 공식문서(번역)] kimsangyeon 님의 블로그 : https://kimsangyeon-github-io.vercel.app/blog/2022-03-16-nextjs-12.md
- [Next 12 변경내용] lucid 님의 블로그 : https://velog.io/@lucid/Next.js-12-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8-%EB%82%B4%EC%9A%A9
- [SSG와 ISR] seungchan__y 님의 블로그 : https://velog.io/@seungchan__y/NextJS%EC%99%80-ISR