96일차 TIL : Next.js

변시윤·2023년 2월 3일
0

내일배움캠프 4기

목록 보기
106/131

학습내용

  • _document.js
  • Web Vitals
  • Middleware

_document.js

특징

  • 서버 사이드에서만 렌더링
  • HTML 구조 커스텀시 사용
  • 초기 HTML 렌더링시 스타일이 적용되도록 도와주는 역할

Next.js 프로젝트의 실행 순서

_app.js ➡️ _document.js ➡️ _app.js

import { Html, Head, Main, NextScript } from "next/document";

const Document = () => {
  return (
    <Html lang="en">
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
};

export default Document;

_document.js의 <Main /> 컴포넌트가 _app.js에 해당된다.

styled-components 초기화 이슈

Next.js 프로젝트에 styled-components를 적용하면 새로고침시 적용했던 스타일이 사라지고 초기화 된다. 스타일이 적용되기도 전에 렌더링이 완료됐기 때문이다. 아래와 같이 _document.js에서 ServerStyleSheet를 사용하면 초기 렌더링시 스타일을 포함해서 렌더링 한다.

import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet()
    const originalRenderPage = ctx.renderPage

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: App => props => sheet.collectStyles(<App {...props} />)
        })

      const initialProps = await Document.getInitialProps(ctx)
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        )
      }
    } finally {
      sheet.seal()
    }
  }
}

export default MyDocument

babel-plugin-styled-components를 사용하는 방법도 있지만 나의 경우엔 babel 뭐시기로는 해결이 되지 않았고, 이 방법을 사용하자 바로 해결되었다.



Web Vitals 개선하기

Web Vitals란?

웹사이트 품질을 결정하는 지표로 LCP, FID, CLS 등이 있다.

-LCPFIDCLS
의미Largest Contentful PaintFirst Input DelayCumulative Layout Shift
측정 항목페이지 로딩 성능(화면에 보이는 부분 중 최대 크기의 element가 렌더링 되는 속도)페이지 응답성(특정 버튼을 눌렀을 때 상호작용 속도)시각적 안정성
개선 방안priority(이미지 컴포넌트 우선 렌더링)Link의 prefetch(Link를 적용한 컴포넌트가 화면에 보이면 해당 페이지의 데이터를 미리 다운)스켈레톤 UI, next/image

측정 방법

크롬 개발자도구의 Lighthouse 항목에서 Analyze page load 실행

캡쳐 아래 항목으로 내려보면 개선 사항이 적혀있는데 해당 항목을 참조해서 Web Vitals를 개선할 수 있다.



Middleware

redux와 마찬가지로 요청과 응답 사이에서 수행하는 작업을 의미한다.
yarn add next@latest

middleware.js

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/about-2', request.url))
}

// See "Matching Paths" below to learn more
export const config = {
  matcher: '/about/:path*',
}

middleware를 설치하면 위 파일이 자동으로 생성된다. 이 중 맨 아래 matcher에 경로가 설정되면 해당 경로에서만 middleware가 실행되고, 아무 경로도 없을시엔 모든 경로에서 실행된다.

예시

비로그인 유저 제한

export function middleware(request: NextRequest) {

  const { cookies } = request;

  if(!cookies["firebaseSomething"]{
      return NextResponse.redirect("/login);
  }
}

특정 쿠기가 없다면 로그인 불가

redirect

export function middleware(request: NextRequest) {

  const url = request.nextUrl.clone();
  const { pathname } = request.nextUrl;

  if(pathname === "/jamescameron"){
      url.pathname = "/titanic";
      
      return NextResponse.redirect(url);
  }
}

/jamescameron으로 접속하면 경로가 /titanic으로 재설정 된다. 이 밖에도 에러 페이지나 랜딩 페이지로 redirect 할 수도 있다.

rewrite

export function middleware(request: NextRequest) {

  const url = request.nextUrl.clone();
  const { pathname } = request.nextUrl;

  if(pathname === "/jamescameron"){
      url.pathname = "/titanic";
      
      return NextResponse.rewrite(url);
  }
}

redirect와 같지만 경로가 유지된다는 차이점이 있다. 즉, /jamescameron으로 접속하면 해당 경로는 유지하되 /titanic 경로에 해당하는 내용이 렌더링 된다.

  if(pathname === "/jamescameron"){
      url.pathname = "/titanic";
      url.pathname = "/avartar";
  }

이것을 응용하면 같은 경로에서 조건에 따라서 다른 내용을 렌더링 할 수도 있다.

profile
개그우먼(개발을 그은성으로 하는 우먼)

0개의 댓글