avatar
Published on

Nextjs 10 릴리즈 및 적용 후기

Author
  • avatar
    Name
    yceffort

nextjs 10.0.0이 릴리즈 되었다. 내가 좋아하는 오픈소스 중 하나 이기 때문에, 릴리즈 노트를 읽어보면서 당장 내 블로그에 적용해보았다. 그리고 적용하면서 어떤게 바뀌었는지 하나씩 확인해보려고 한다.

빌트인 이미지 컴포넌트, 그리고 자동 이미지 최적화

이미지는 마크업과 함께 웹에서 큰 트래픽을 유발하는 범인중 하나다. 이러한 이미지를 최적화 하기 위해, next/image 라는 전용 이미지 컴포넌트를 적용하였다. 브라우저에서 Webp가 사용 가능하다면, 해당 이미지를 변환해서 적은 용량으로 내려주고, 동시에 lazy loading도 해준다고 한다.

대상 이미지

blog profile

적용전

const AuthorPhoto = styled.image`
  display: inline-block;
  margin-bottom: 0;
  border-radius: 50%;
  background-clip: padding-box;
  width: 75px;
  height: 75px;
  cursor: pointer;
`

return <AuthorPhoto alt={name} src={photo} />
<img
  alt="yceffort"
  src="/profile.png"
  class="Author__AuthorPhoto-sc-1ywmx02-0 fMrwt"
/>
accept-ranges: bytes
access-control-allow-origin: *
age: 1331855
cache-control: public, max-age=0, must-revalidate
content-disposition: inline; filename="profile.png"
content-length: 30710
content-type: image/png
date: Wed, 28 Oct 2020 02:05:42 GMT
etag: W/"078a2ad86a1350e007d801e7f74b073ed415e5bdd60a60e5b65b9fafe972af03"
server: Vercel
status: 200
strict-transport-security: max-age=63072000w
x-content-type-options: nosniff
x-frame-options: DENY
x-vercel-cache: HIT
x-vercel-id: icn1::chhv4-1603850742953-91ba1434fc9c
x-xss-protection: 1; mode=block

적용후

그리고 이를 next/image로 아래와 같이 바꿨다.

import Image from 'next/image'

const AuthorPhoto = styled(Image)`
  display: inline-block;
  margin-bottom: 0;
  border-radius: 50%;
  background-clip: padding-box;
  width: 75px;
  height: 75px;
  cursor: pointer;
`

// width와 height를 지정해줘야 한다.
return <AuthorPhoto alt={name} src={photo} width={75} height={75} />
<img
  alt="yceffort"
  data-src="/_next/image?url=%2Fprofile.png&amp;w=320&amp;q=75"
  data-srcset="/_next/image?url=%2Fprofile.png&amp;w=320&amp;q=75 320w"
  class="Author__AuthorPhoto-sc-1ywmx02-0 fMrwt"
  style="visibility: visible; height: 100%; left: 0px; position: absolute; top: 0px; width: 100%;"
  src="/_next/image?url=%2Fprofile.png&amp;w=320&amp;q=75"
  srcset="/_next/image?url=%2Fprofile.png&amp;w=320&amp;q=75 320w"
/>
accept-ranges: bytes
access-control-allow-origin: *
age: 276
cache-control: public, max-age=0, must-revalidate
content-disposition: inline; filename="profile.png"
content-length: 18898
content-type: image/webp
date: Wed, 28 Oct 2020 02:06:37 GMT
server: Vercel
status: 200
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: DENY
x-robots-tag: noindex
x-vercel-cache: HIT
x-vercel-id: icn1::q6js7-1603850797310-7e6bd3beb3f0
x-xss-protection: 1; mode=block

일단 이미지가 눈에 띄게 lazy loading이 되었고 (나중에 떴고) 이미지 사이즈도 webp를 사용하면서 눈에 띄게 줄어든 모습이다. 구글 크롬팀에서 이미지 성능을 향상 시킬 수 있는 리액트 컴포넌트를 만들 수 있도록 도와주었다고 하는데, 나중에 소스 코드를 보는 것도 재밌을 것 같다.

국제화 라우팅

당장 내가 쓸 일이 있을지는 모르겠지만, 언어별 라우팅을 지원한다. 그리고 최신 브라우저가 지원하는 Accept-language헤더를 기반으로 언어 감지를 할 수 있는 기능도 추가되었다고 한다.

// next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'nl'],
    domains: [
      {
        domain: 'example.com',
        defaultLocale: 'en',
      },
      {
        domain: 'example.nl',
        defaultLocale: 'nl',
      },
    ],
  },
}

성능 분석

nextjs를 사용하는 웹 어플리케이션의 성능을 분석할 수 있는 도구를 지원한다.

https://nextjs.org/analytics

당장은 vercel만 지원하는 것 같은데(?) 운좋게도(?) 블로그가 vercel로 서빙되고 있기 때문에 당장 시도해보러 갔다.

analytics
analytics

(점수가 깎이는 것은 아마도 메인페이지의 페이지 전환 버튼 때문인 것 같다. 현재 타이틀 제목 길이에 따라서 페이징 버튼이 위아래로 일관되지 못하게 움직이는 버그가 있다.)

일단 모양새와 제공데이터는 구글 라이트 하우스와 비슷한데, 차이가 있다면 page 별로 데이터도 지원한다는 것이다. 다만 서두에도 말한 것 처럼 vercel을 써야만 누릴 수 있는 기능이라 🤔 근데 라이트 하우스에 비해 크게 차별점도 없다면...

커머스 키트 제공

https://nextjs.org/commerce

Next.js가 본격적으로 돈을 벌 만한 비즈니스를 시작하는 것 같다. 간단하게 말헤 next.js로 커머스 사이트를 만들 수 있는 도구를 제공한다고 한다.

리액트 17 지원

react 17을 지원한다. breaking change가 없으므로 바로 적용 가능하며 react를 import 하지 않아도 사용할 수 있는 jsx transform 기능도 사용할 수 있게 되었다.

https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

getStaticProps, getServerSideProps 빠른 새로고침

이제 해당 두 함수에서 코드 변화가 일어나면, 자동으로 새로고침을 지원한다고 한다. 이게 안되었다는 걸 이제 알았는데(??????) 해보니까 잘된다.

써드 파티 리액트 컴포넌트에서 css 임포트 가능

import DatePicker from 'react-datepicker'
import 'react-datepicker/dist/react-datepicker.css'

이를 바탕으로, 단일 컴포넌트 레벨에서 CSS 코드 스플리팅이 가능해졌다. 자세한 내용은 https://nextjs.org/docs/basic-features/built-in-css-support

href 자동화

이전까지, 다이나믹 라우팅을 사용하기 위해서 next/link에서 href as를 넣어 주어야 했다.

<link href="/categories/[slug]" as="/categories/books" />

여기서 as는 실제 브라우저 URL 바에서 보이는 주소인데, 이전까지는 hrefas를 아래와 같이 따로 넣어주어야 했다.

const pids = ['id1', 'id2', 'id3']
{
  pids.map((pid) => (
    <Link href="/post/[pid]" as={`/post/${pid}`}>
      <a>Post {pid}</a>
    </Link>
  ))
}

그러나 나를 비롯해서 많은 개발자들이 as의 사용에 대해서 혼란이 있었던 것 같다. (as를 넣어야 하는데 까먹는 다든지) 그래서 as가 더 이상 필요없어졌다고 한다. 이제는 기존에 as에 넣었던 값을 href에 넣어주면 된다. 그게 훨씬 더 이전의 리액트나 HTML경험에서도 자연스러워 보인다.

@next/codemod cli

nextjs 에서 기능이 deprecated 되는 등의 대규모 코드 베이스 변경이 필요한 경우에 사용할 수 있는 툴이다. codemode는 소스 코드 업데이트를 위해 프로젝트에서 실행할 수 있는 자동화 코드 변경 툴이다.

https://nextjs.org/docs/advanced-features/codemods

getStaticPaths에 블로킹 fallback 추가

getStaticPropsgetStaticPathsfallback 속성이 추가되어 있었다. 이 속성은 최초에는 정적 페이지 (fallback 페이지)를 제공하고, 이후 요청 시에는 완전히 렌더링된 콘텐츠를 제공할 수 있도록 도와주는 기능이었다. 그러나 몇몇 개발자들이, 사용자가 페이지를 처음 요청할때는 사전 렌더링을 차단할 수 있는 옵션을 요구했었나 보다. (나또한 fallback 페이지를 보여주는 것이 사용자들에게 안좋은 사용자 경험을 제공한다고 생각했다. ) 그래서 blocking옵션이 추가되었다.

export function getStaticPaths() {
  return {
    fallback: 'blocking',
  }
}

이 옵션을 추가하면, fallback 페이지를 보여주는 대신에, 그냥 최초 렌더링이 서버에서 내려올 때 까지 기다린다.

결론

여러가지로 nextjs는 정말로 잘 관리되고 있는 리액트 SSR 프레임워크다. 단순히 nextjs 뿐만 아니라 여러가지로 nextjs를 중심으로 다양한 생태계를 만들어 가려는 것이 보인다.

모질라나 webpack 등 순수하게 기부로 운영되고 있는 대규모 오픈소스 프로젝트들이 코로나 시국이 닥치면서 생존 문제에 직면한 것을 보고 마음이 안타까웠다. 이러한 문제를 vercel도 알고 있는 듯, 여러가지로 수익화를 하려는 노력이 보였다. vercel, next commerce 등의 비즈니스를 통해서, 단순히 기부에 의존하는 것이 아니라 다각도로 생존에 대해 고민하고 있는 것이 보인다. 개인적으로 다 잘되었으면 하는 바람이다.

회사를 옮기면서 nextjs는 업무에서는 더 이상 쓰지 못하고 있지만 (ㅠㅠ) 블로그나 개인 프로젝트에서는 나름 적극적으로 사용하고 있었다. 심지어 지금 하고있는 nextjs conf 도 꼬박 꼬박 잘챙겨보고 있다. (미리 신청해서 티켓도 받아놨었는데 어디간지 모르겠네)

전 회사 사람들은 next github에 issue 도 올려서 contribute도 했는데 아직도 나는 가져다 쓰고 구글링 하기에 바쁘다 😇

같은, 그리고 연차도 더 많은 개발자로서 부끄럽지 않을 수가 없는 일이다. 조만간 오픈소스에 기여할 날도 오기를 바라며 열심히 공부를 해야겠다.