티스토리 뷰

😉 2022 11 02 기준, 최근 Next 13버전이 대규모 업데이트를 했습니다. 저는 공식 홈페이지의 튜토리얼을 참고하고 있기 때문에 create-next-app으로 자동 설치됐던 next 13버전을 12버전으로 다운그레이드하여 사용했습니다.

 

yarn 을 통한 패키지 다운그레이드 방법

yarn upgrade 패키지명@버전
yarn upgrade next@12.2.2 // upgrade 대신 add도 된다.

 

Next.js 는 React로 SSR이 가능하게 도와주는 프레임워크입니다. 

Next에서는 퓨어한 React에 비해 많은 기능을 내부에 포함(폴더기반 라우팅 기능, Express.js 코드 스플리팅, 이미지 최적화 등)하고 있습니다. 세팅하고 시작하는 방법에 대해서는 언급하지 않겠습니다.

Next.js의 공식 홈페이지를 참고하면 쉽게 따라할 수 있습니다.

 React의 create-react-app처럼 Next역시 create-next-app이 존재하여 따로 세팅하지 않고도 쉽게 시작해볼 수 있습니다. 

 

CSS 스타일링

파일 구조를 보면 styles 폴더가 이미 존재하고 그 안에 두 개의 CSS  파일이 존재합니다.

  • globals.css(전역 스타일시트)
  • Home.module.css (CSS 모듈)

CSS 모듈을 사용하면 고유한 클래스 이름을 자동으로 생성하여 구성 요소 수준에서 CSS 범위를 로컬로 지정할 수 있습니다. 이는 React에서도 사용하고 있기 때문에 친숙하실 겁니다. 클래스 이름에 대한 충돌을 피할 수 있고 다른 파일에서 같은 클래스명을 사용할 수 있습니다. CSS 모듈 외에도 Next.js 어플리케이션의 스타일을 지정할 수 있습니다.

  • 파일.css 을 가져올 수 있는 Sass  scss
  • Tailwind CSS 와 같은 PostCSS 라이브러리
  • styled-jsx, styled-components 및 emotion 과 같은 CSS-in-JS 라이브러리

레이아웃 컴포넌트 만들기

-전역 페이지에 공유될 레이아웃 컴포넌트를 만들어봅시다. 

  1. 우선 "가장 상위 경로"에 components 라는 폴더를 만들어줍니다.
  2. components 폴더에 layout.js 라는 파일을 만들어 레이아웃 컴포넌트를 작성해줍니다. 
  3. layout 파일의 css 작업은 CSS 모듈시스템에 따라 작성해봅시다.
🔥Important🔥 CSS 모듈을 사용한다면 CSS file의 이름은 무조건 파일명.module.css 로 끝나야 합니다. 

현재 파일 구조

컴포넌트의 파일명은 소문자로 작성되어있지만 내부에서 반환하는 것은 컴포넌트이므로 대문자로 export 해주어야 합니다. 

CSS 모듈 시스템을 이용할 때에는 사용할 해당 컴포넌트에 import 해와서 사용하면 됩니다. 

//경로🐈components/layout.js
import style from "./layout.module.css";

export default function Layout({ children }) {
  return <div className={style.container}>{children}</div>;
}

//경로🐈components/layout.module.css

.container {
  max-width: 36rem;
  padding: 0 1rem;
  margin: 3rem auto 6rem;
}
  • CSS 모듈 시스템은 자동으로 유니크한 클래스명을 생성해주기 때문에 다른 파일과의 충돌을 피할 수 있습니다. 
  • CSS 모듈은 컴포넌트 레벨의 스타일에 유용합니다. 
또한, Next.js의 코드 스플리팅 기능은 CSS 모듈에서도 적용됩니다. 그렇기 때문에 각 페이지에 CSS가 로드될 때 최소한의 상태만이 로드된다는 걸 보장할 수 있죠. 즉, 결과적으로 번들 사이즈가 작아지게 됩니다. 

☕빌트인으로 제공하는 스타일링 메소드로는 CSS 모듈, Sass, styled-jsx 가 있습니다. 

 

Global Styles 

글로벌 CSS 를 모든 페이지에 로드하고 싶다면 넥스트가 제공하는 아래의 방법을 따라해봅시다.

 create-next-app을 통해 프로젝트를 만들었다면 해당 내용은 이미 적용되어 있을 것입니다. 주의사항이나 어떻게 동작하는 지 알고싶다면 따라하시는 것을 추천드립니다. 

global CSS 파일을 로드하고 싶다면 pages/_app.js 에 아래의 내용을 넣어줍니다. 

- App 컴포넌트는 가장 상위의 컴포넌트로 모든 페이지에 적용됩니다. 다른 페이지로 이동한다해도 state를 유지할 수 있습니다. global css는 이 App 컴포넌트에 적용시켜줘야 합니다. 다른 곳에서 글로벌 CSS 를 import 하여 사용하면 안됩니다.

이유는 global CSS가 pages/_app.js 외에 다른 곳에서 임포트되어 사용된다면 다른 페이지에서 의도치 않게 스타일이 영향을 끼칠 수 있기 때문입니다. 

pages/_app.js

import '../styles/globals.css' //App컴포넌트에 적용되는 global.css

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

글로벌 CSS를 만드는 법

- styles 폴더의 최상단에 global.css를 만들어줍니다.

styles/global.css 

html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
  line-height: 1.6;
  font-size: 18px;
}

* {
  box-sizing: border-box;
}

a {
  color: #0070f3;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

img {
  max-width: 100%;
  display: block;
}
🕵️‍♀️만일 코드가 제대로 적용되지 않는다면 dev 서버를 다시 끄고 재실행하여 pages/_app.js를 업데이트해줍니다. 

다른 부분은 크게 어려운 부분이 없이 공식 문서를 따라 만들어보시면 쉽게 따라할 수 있습니다. 

 

❗ TIP 이미지 소스는 public/images/파일명.jpg 폴더에 두고 Image에서 불러와서 사용할 때에는 images/cat/jpg로 경로를 지정해주시면 됩니다.

import Image from "next/image"; 
 
  // 컴포넌트 내용 생략 // 
 <Image
                  priority
                  src="/images/cat.jpg"
                  className={utilStyles.borderCircle}
                  height={108}
                  width={108}
                  alt=""
                />

▶경로를 해당 컴포넌트 기준으로 ../public/images/profile.jpg 이런식으로 사용하게 되면 해당 이미지를 추적하지 못합니다. 이미지를 불러오지 못하게되면 Next는 에러 메세지를 던지므로 해당 내용을 참고하시면 되겠습니다. 

 

결과물

Sass 사용하기

Next에서 Sass를 사용할 수 있습니다. .scss 와 .sass 더하여 컴포넌트 레벨에서 CSS 모듈로 만든 .module.scss 혹은 .module.sass extension을 사용하고 싶다면 sass를 설치해야합니다. 

npm install -D sass 를 통해 설치할 수 있습니다. 

npm install -D sass

npm i sass
# or
yarn add sass

⭐Pre-redering 

데이터 펫칭에 대해서 얘기하기 전에, Next.js의 Pre-rendering에 대해서 알아봅시다.

기본적으로 넥스트는 모든 페이지를 "프리렌더"합니다. 

-> 이 말은 넥스트가 클라이언트 측에서 JS로 모든 과정을 수행하는 대신 미리 각 페이지에 대한 HTML 파일을 만들어준다는 의미입니다.  사전 렌더링을 통해서 더 나은 성능과 SEO를 제공할 수 있습니다. 

 

생성된 각각의 HTML은 해당  페이지에 필요한 최소한의 JavaScript 코드와 연결됩니다. 브라우저에서 페이지를 로드하면 해당 JS코드가 실행되어 페이지를 interactive하게 만들어줍니다. 이 과정을 hydration이라고 부릅니다.

 

프리렌더링 장점

  • SEO 개선
  • 어플리케이션이 JS코드 없이도 동작하게 함

프리렌더링이 일어나고 있는 지 확인하는 방법(with 크롬 개발자도구)

(here’s how in Chrome)

개발자 도구를 열고(F12) 윈도우의 경우 ctrl + shift + p / 맥의 경우 command + shift + p 를 눌러서 개발자도구의 "커멘드 메뉴"를 열어줍니다. 그 다음, javascript 를 치면 Disable JavaScript 라는 기능이 있습니다. 이를 눌러서 실행시키면 자바스크립트가 웹프로젝트에서 작동하지 않는 모습을 확인할 수 있습니다(설정을 적용하고 리로드해주세요). 다시 JS를 재가동하려면 똑같이 커멘드 메뉴에 해당 기능을 눌러주면 됩니다.  

로컬호스트(개발자모드)에서도 확인할 수 있습니다. 하지만, JS를 disable 하면 CSS가 로드되지 않습니다. 
퓨어한 React.js에서는 프리렌더링을 확인할 수 없습니다. 오직 Next를 통한 어플리케이션에서만 확인할 수 있습니다.

Next.js&nbsp; 프리렌더링 O
React.js 프리렌더링X

 

두 가지 형태의 프리렌더링

  1. Static Generation(SG 혹은 SSG, 정적 생성) -> 이 프리렌더링 메소드는 HTML을 빌드 타임에 생성합니다. 프리 렌더된 HTML파일은 각 요청에 재사용됩니다. -> 미리 어플리케이션을 빌드할 때 만들어둔 HTML을 가지고 있다가 요청이 오면 해당 HTML을 사용자에게 요청이 왔을 때 주는 겁니다.
  2. Server-side Rendering(SSR) -> 이 프리렌더링 메소드는 HTML을 각각의 요청(each request)마다 생성하게 됩니다. 넥스트가 사용자로부터 page request를 받으면 그 때, HTML을 생성하여 주게됩니다. 

넥스트에서는 각 페이지마다 내가 원하는 프리렌더링 형태를 선택할 수 있습니다. 대부분의 페이지에는 SG를 사용하고 다른 페이지에서는 SSR(서버사이드 렌더링)을 통해 "하이브리드" Next.js 앱을 만들 수 있습니다.

 

정적 생성 예시 

- 공통적으로 내부 데이터가 변동될 일이 거의 없거나 고정인 경우의 페이지입니다. 

  • 마케팅 페이지
  • 블로그 게시물
  • 전자상거래 제품 목록
  • 도움말 및 문서 

페이지에 자주 업데이트되는 데이터가 표시되고 모든 요청에 따라 페이지 콘텐츠가 변경될 경우는 SSG를 사용해줍니다. 속도는 SG보다 느려지지만 미리 렌더링된 페이지는 항상 최신 상태로 유지됩니다. 또는 프리렌더링을 건너뛰고 클라이언트 측 JS를 사용하여 자주 업데이트되는 데이터를 채울 수 있습니다. 

 

두 종류의 Static Generation

하나는 그냥 보통의 SG이고 나머지는 외부 API에서 데이터를 가져와야 빌드타임에 생성될 수 있는 SG with data 입니다. 

외부 API로부터 데이터를 페칭하지않으면 SG만들기 불가

 

정적 페이지(SG)를 만드는데 도움을 주는 정적 함수 2가지

🌚getStaticProps()

  • getStaticProps 프로덕션에서 빌드 시간에 실행되며, 
  • 함수 내에서 외부 데이터를 가져와 페이지에 props 로 보낼 수 있습니다. 
  • 페이지 콘텐츠가 외부 데이터에 연동 -> page에서 외부 데이터를 가져올 때 사용. 
  • 해당 훅은 "이 페이지는 빌드 시 패치(fetch)해올 외부 데이터가 있으니 얘를 먼저 실행하렴" 라고 넥스트에게 말해줍니다.
  • getStaticProps는 서버 사이드에서 실행됩니다. -> 내부에 작성된 코드가 클라이언트 코드가 아니라는 소리입니다. 즉,  window.alert()를 할 때 window객체를 인식하지 못합니다. 
🕵️‍♀️ dev 모드에서 getStaticProps는 getStaticProps가 각 요청에 대해 대신 실행됩니다. 

 

getStaticProps는 외부 API를 페칭할 때나 Query 데이터베이스를 사용할 때도 사용할 수 있습니다. 

export async function getStaticProps(){
//API함수

//fetch 는 넥스트에서 폴리필을 제공하기 때문에 임포트하지 않아도 됩니다.
const res = await fetch('http~~ /posts')
const posts = await res.json(); 

객체를 반환합니다.
return {
	props: {
     posts,
    },
}

}
// Blog컴포넌트가 posts라는 props를 빌드 때 얻게됩니다. 
function Blog({ posts }){
//렌더링될 함수 ~ 
}

아래는 jsonplaceholder(오픈소스API)를 코드에 적용시켜 봤습니다. 

export async function getStaticProps() {
  const allPostsData = getSortedPostsData();
  const jsonPlaceHolderData = await axios.get(
    "https://jsonplaceholder.typicode.com/posts"
  );
  const result = jsonPlaceHolderData.data;
  return {
    props: { result },
  };
}
👾 getStaticProps은 page에서만 export될 수 있습니다. non-page 파일에서는 export 될 수 없습니다. 

이 말은 페이지에 해당하는 index.js파일이 아닌 경우 사용할 수 없다는 의미입니다.

❗이런 제약이 있는 이유는  리액트가 페이지가 렌더되기 전에 필요한 사전 데이터들을 가지고 있어야 하기 때문입니다.

pages/index.js 

import Head from "next/head";
import Layout, { siteTitle } from "../components/layout";
import utilStyles from "../styles/utils.module.css";
import { getSortedPostsData } from "../lib/posts";
import axios from "axios";

export async function getStaticProps() {
  const allPostsData = getSortedPostsData();
  const jsonPlaceHolderData = await axios.get(
    "https://jsonplaceholder.typicode.com/posts"
  );
  const result = jsonPlaceHolderData.data;
  return {
    props: { result },
  };
}

export default function Home({ result }) {
  return (
    <Layout home>
      <Head>
        <title>{siteTitle}</title>
      </Head>
      <section className={utilStyles.headingMd}>
        <p>안녕하세요. 감자나라 왕자 감자입니다.</p>
        <p>
          넥스트 js를 통해 더 많은 지식을 알고 싶으시다면 링크를 클릭해주세요!
          <a href="https://nextjs.org/learn"> Here is Next.js tutorial</a>.
        </p>
      </section>
      <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
        <h2 className={utilStyles.headingLg}>▼Blog Contents▼</h2>
        <ul className={utilStyles.list}>
          {result.map(({ id, title, body }) => (
            <li className={utilStyles.listItem} key={id}>
              Title : <b>{title}</b>
              <br />
              <i>{body}</i>
              <br />
            </li>
          ))}
        </ul>
      </section>
    </Layout>
  );
}

dev 모드와 production 모드 에서의 동작 방식 차이

  • dev 모드에서는 getStaticPorps가 모든 request(요청)마다 실행됩니다. 
  • production 모드에서는 빌드타임에서만 실행됩니다. 이 동작은 getStaticPaths가 리턴하는 fallback key에 의해 더욱 강력하게 사용할 수 있습니다.

🌚getStaticPath()

페이지 경로가 외부데이터에 연동됨 -> Next에서는 동적라우팅을 쉽게 만들 수 있습니다. 

 

/pages/posts/[id].js 다음과 같은 폴더구조를 만들면 넥스트가 알아서 pages를 찾아 라우트를 구성합니다. id부분에 원하는 index와 string을 넣어 구성이 가능합니다.  paths만 사용한다면 아래와 같이 써도 상관없지만 보통은 데이터도 같이 받아와야 합니다. 그럴때는 getStaticProps를 같이 사용해줍니다.

export async function getStaticPaths(){
  const res = await fetch('주소');
  const posts = await res.json();

  //원하는 posts로 구성된 paths를 pre-render한다. 
  const paths = posts.map((post) => {
    params: {id: post.id}
  })

  // fallback: false 이외의 다른 경로는 404페이지로 보낸다는 것을 의미
  return {paths, fallback: false}
}

위의 코드에서 return 한 params 를 활용해서 data를 가져옴 

export async function getStaticProps({params}){
  const res = await fetch(`https ~ posts/${params.id}`);
  const post = await res.json();

  return {props: {post}}
}

function Post({post}) {
//렌더링될 애
}

미리 생성된 paths는 캐싱되기 때문에 라우터로 페이지를 이동할 때 매우 빠른 렌더링 속도를 보여줍니다. 

 

Q. 만일 리퀘스트 타임마다 데이터를 패칭할 필요가 있다면 어떻게 하면 될까요? 

  • Static Generation은 빌드 타임에서만 한 번 발생한다고 했습니다. 자주 변경되는 데이터나 유저의 요청에 따라 변동되는 데이터에는 적합하지 않죠. 이럴 경우엔 SSR를 사용하면 됩니다(e.g. 저는 "리액트 쿼리" 라이브러리를 통해서 리액트에서 SSR을 해봤습니다.  

Request 타임에 데이터 페칭하기

빌드  타임 대신에 요청 타임에 데이터를 fetch해와야 한다면 Server-side Rendering을 사용하면 됩니다. 

-> 각 요청에 데이터가 펫치되면서 HTML이 이때 만들어지게 됩니다(서버에서). 

SSR을 하려면, 내 페이지에 getStaticProps대신에 export getServerSideProps를 해주면됩니다. 

 

🤸‍♀️ getServerSideProps()

  • request 타임마다 데이터를 펫치해와서 프리 렌더해야하는 페이지에만 사용합니다.
  • TTFB(Time to fisrt byte)는 getStaticProps보다 느립니다. -> 서버가 매 요청마다 결과를 계산해야하기 때문입니다 또한 이 결과는 CDN(Content Delivery Network)에 추가적인 설정이 없다면 캐시되지 않습니다. 
export async function getServerSideProps(context) {
  return {
    props: {
      // props for your component
    },
  };
}

🤸‍♀️ Client-side Rendering ( SG without Data + fetch Data on Client-Side )

  • 만약 데이터를 프리 렌더 해야할 필요가 없다면 CSR을 사용하면 됩니다. 
  • SG without Data + Fetch Data on Clinet-Side 이 두가지 결합 방식으로 진행하면 됩니다. -> fetch()는 클라이언트측과 서버측에서 둘 다 제공하므로 fetch메소드를 통해 클라이언트에서 자바스크립트를 통해 외부 데이터를 가져옵니다. 
  • 사용 페이지 예시로는 유저 대시보드 페이지를 들 수 있습니다. 유저 대시보드는 유저의 사적인 정보가 담겨있기 때문입니다.  즉, SEO가 필요없는 페이지를 말하는 겁니다. 또한, CSR에 적합한 페이지는 해당 페이지는 요청(Request) 타임마다 데이터를 펫치해와서 데이터의 업데이트가 빈번한 유저 인터랙션이 활발한 페이지입니다. 

🤸‍♀️ SWR( CSR에서 데이터 fetch를 위한 React hook )

import useSWR from 'swr';

function Profile() {
  const { data, error } = useSWR('/api/user', fetch);

  if (error) return <div>failed to load</div>;
  if (!data) return <div>loading...</div>;
  return <div>hello {data.name}!</div>;
}

Vercel 팀은 클라이언트 사이드 데이터 fetch를 위한 React hook을 만들었습니다. 그게 바로 SWR 입니다.

  •  캐싱
  • 재검증(revalidation)
  • focus tracking
  • 일정 간격마다 리패칭하기(refetching on interval) 등등 

많은 기능을 제공하고 있습니다. 더 많은 내용은 SWR documentation 에서 다루고 있으니 참고바랍니다. 


Dynamic Routes (동적 라우팅)

넥스트.js에서는 동적 URLs 가 가능합니다. 아래와 같이 동작합니다.

 

넥스트에서 [ ] 표시는 동적 경로를 의미합니다.

e.g.) pages/posts/[id].js

 

lib/posts.js

import fs from "fs";
import path from "path";
import matter from "gray-matter";

//✅2022 11 07 이슈 발생 fs 모듈은 node 모듈이라 서버 사이드 메소드 내부에서
//모듈을 임포트해서 사용하는 것이 아니라면, 해당 모듈을 쓸 수 없다는 에러 메세지를 보낸다.

const postsDirectory = path.join(process.cwd(), "posts");

export function getPostData(id) {
  const fullPath = path.join(postsDirectory, `${id}.md`);
  const fileContents = fs.readFileSync(fullPath, "utf8");

  // Use gray-matter to parse the post metadata section
  const matterResult = matter(fileContents);

  // Combine the data with the id
  return {
    id,
    ...matterResult.data,
  };
}

export function getAllPostIds() {
  const fileNames = fs.readdirSync(postsDirectory);

  //파일 이름들을 리스트로 반환(.md 제외)
  //반환된 목록은 단순한 문자열 배열이 아니라 아래와 같은 모양의 객체 배열이어야 합니다.
  //각 객체에는 키가 있어야 하고 params 키가 있는 객체를 포함해야 합니다.
  // [id]를 사용하기 때문입니다. 그렇지 않으면 getStaticPaths는 실패합니다.

  // Returns an array that looks like this:
  // [
  //   {
  //     params: {
  //       id: 'ssg-ssr'
  //     }
  //   },
  //   {
  //     params: {
  //       id: 'pre-rendering'
  //     }
  //   }
  // ]
  return fileNames.map((fileName) => {
    return {
      params: {
        id: fileName.replace(/\.md$/, ""),
      },
    };
  });
}

pages/posts/[id].js

import Layout from "../../components/layout";
import { getAllPostIds, getPostData } from "../../lib/posts";

export async function getStaticPaths() {
  const paths = getAllPostIds();
  //paths는 getAllPostIds의 결과값으로 배열을 받습니다.
  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params }) {
  const postData = getPostData(params.id);
  return {
    props: {
      postData,
    },
  };
}

export default function Post({ postData }) {
  return (
    <Layout>
      {postData.title}
      <br />
      {postData.id}
      <br />
      {postData.date}
    </Layout>
  );
}

결과적으로 동적인 라우팅과 함께 어떻게 정적인 페이지를 만들어 낼 수 있는 지에 대해서 알아봤습니다. 

lib/posts.js 로직은 저도 정확히 이해한 것은 아닙니다만  결과적으로 paths에 들어가는 것은 객체를 담은 리스트이며 이 리스트에는 params라는 키값이 있어야 하며 이 params의 값으로 {id: "1"} 처럼 id가 포함되어야 합니다. 

즉, getStaticPaths 는 반환 객체로 paths 와 fallback 키를 반드시 포함시켜야 합니다. 

  • paths: 어떤 path의 페이지들을 빌드 타임에 생성할 지 정하는 배열입니다. 이 배열에서 각각의 params 값은 페이지 이름에 있는 파라미터와 일치해야 합니다. 
  • fallback: 빌드 타임에 생성해놓지 않은 path로 요청이 들어온 경우 어떻게 할 지 정하는 boolean 값 또는 blocking 값입니다. false인 경우는 getStaticPaths 가 반환하지 않은 모든 경로에 대해 404 페이지를 리턴합니다. 

자세한 내용은 이 블로그 주소를 참고하시면 될 거 같습니다. 블로그 주소


Q.  서버 사이드에서 콘솔 로그 시,  2번씩 찍힙니다. 

  • react에서도 똑같은 현상이 발생했었는데 원인도 동일합니다. next.config.js에 있는 reactStrictMode를 없애주시거나 false로 변경하면 됩니다. 
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  },
};

module.exports = nextConfig;

 

Q.  fs 모듈이 클라이언트 파일에서 적용되지 않아요.

  • 우선 웹팩 버전을 확인해보세요. 확인을 해보니 저는 webpack5(버전 5)를 사용하고 있었습니다. 웹팩5부터 더이상 node core 모듈즈에 대한 자동 폴리필을 제공하지 않기 때문에 fs모듈을 제대로 읽어오지 못해서 생기는 오류입니다. 웹팩4 버전까지는 노드 코어 모듈에 대해 기본적으로 폴리필을 제공합니다.
  • 저는 아래와 같이 수정하니 정상적으로 작동하였습니다. 
/** @type {import('next').NextConfig} */
const nextConfig = {
  // reactStrictMode: true,
  swcMinify: true,
  //내가 사용하고 있는 웹팩 버전 5임 node core에 대한 폴리필을 제공하지 않으므로
  //직접 작성해줘야 한다.
  //참고자료: https://stackoverflow.com/questions/64557638/how-to-polyfill-node-core-modules-in-webpack-5
  // webpack5: true,
  webpack: (config) => {
    config.resolve.fallback = { ...config.resolve.fallback, fs: false };

    return config;
  },
};

module.exports = nextConfig;

Q.  getStaticProps 내부 코드에 console.log가  터미널에 뜨지않아요. 

  • 우선 getStaticProps는 서버사이드에서 로그가 뜨므로 console.log시 브라우저 콘솔에서 뜨지 않습니다. vscode를 사용한다면 터미널에서 console값이 출력됩니다.
  • 해당 메소드를 쓰는 곳이 pages에 있는 js파일인지 확인해보세요. 또한, 페이지 컴포넌트이므로 경로가 index.js에 있는 것이 아니라면 해당 경로로 이동했을 때만 값이 뜹니다.
  • 혹시 홈(pages/index.js)에서 다른 페이지 js파일을 임포트해서 사용한 것은 아닌지 확인해보세요. 저는 컴포넌트 개념으로 사용하다보니 index.js에 projects.js를 임포트해서 사용했었는데요(헷갈려서 막쓴 거 같네요). pages에 있는 js는 각각 다른 경로를 가진 컴포넌트들입니다. 말 그대로 페이지 개념인거죠. -> 맞음 제가 이거 때문에 1시간 날렸습니다.
댓글