Don't think! Just do it!

종합 IT 기술 정체성 카오스 블로그! 이... 이곳은 어디지?

Next.js

Next.JS 프로젝트 기본 템플릿 만들기#1

방피터 2022. 6. 14. 23:37

nextjs 말고도 이런 저런 것들이 많이 필요한 것 같아.

기본적으로 ui framwork도 하나 있어야 할 것 같고 tailwindcss도 사용하고 싶고 storybook도 사용하면 좋을 것 같고 .env.local, .npmrc, .nvmrc 파일도 만들어놔야 하잖아. 또 package.json도 이리저리 만져놔야 하고..

next.js 프로젝트 할 때마다 하기 귀찮으니까 나님용 기본 템플릿 하나 만들어서 github repository 하나 파놔야겠다~ 싶더라고 ㅋㅋ

 

먼저 스토리북 설정은 끝냈고 👇

2022.06.10 - [Next.js] - Next.js에 StoryBook 설정하기!

 

Next.js에 StoryBook 설정하기!

아니 이게 뭐야! 이것저것 검색하다보니... 현업에서 스토리북이라는 걸 사용하고 있네.. 역시 등신 에휴.. 또 나만 몰랐네. 역시 사람은 다른 사람들이랑 어울려야 해 ㅋㅋ 혼자 이러고 있으니

engschool.tistory.com

난 mui를 사용하고 싶어 그러니까 그것도 설정하고 .env.local은 next.js프로젝트에서 사용하는 environment 파일이야. api key 같은 거 넣어둬야 할 수 있으니까 걍 비어 있는 폴더 하나 만들어 두자구.

여러 설정파일들

또 .npmrc 파일이랑 nvmrc 파일을 추가해줄건데 npmrc는 npm에 옵션을 줄 수 있고 nvmrc 파일을 통해 어떤 node version을 사용할 지 명시해 줄거야. 두 파일을 새로 만들고 각각 아래와 같이 입력.

.nvmrc

lts/gallium 버전을 사용할거임!! 버전정보는 여기에서!! https://nodejs.org/ko/about/releases/

 

릴리스 | Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

.npmrc

강력크한 npm engine 규칙을 사용할거야! 이거 설정되어 있느면 에러 있으면 인스톨 못함 ㅇㅇ 그렇습니다!

 

그리고 package.json에 engines 규칙을 넣어주자구! 아래와 같이!

package.json

대강 봐도 알겠지? node는 버전 14이상 사용할 것 yarn도 버젼 1.22.0 이상 사용할 것 그리고 npm은 사용하지 말 것! npm이랑 yarn 섞어서 쓰면 가끔 프로젝트가 엉망이 되는 경우가 있거든! 그 후로 난 yarn만 사용하는데 버릇 때문인지 가끔씩 npm도 쓰거든 그러면 여간 찜찜한게 아냐. npm 못쓰게 하는 건 너무 좋은 듯!

자 이렇게 하고 npm으로 install 아무거나 하면 아래 캡쳐처럼 unsupported engine 에러가 발생하면서 설치가 실패!

unsupported engine

이런식으로 engine 관리를 하면 여러 사람과 같이 프로젝트 관리하기가 좋겠지!!

 

자 이제 ui 프레임워크 설치해주자고, 가장 다운로드 수가 많은 ui 프레임워크인 mui를 사용할거임. 그리고 mui의 기본이 되는 emotion을 설치해주자고 👇

yarn add @mui/material @emotion/react @emotion/styled @emotion/cache

설치 후 딱히 다른 작업 없이 mui를 바로 사용할 수 있지만 css 리셋이랑 SSR 정도는 설정해주자구 _app.tsx(js)와 _document.tsx(js) 파일들을 수정해서 말이지. 보통 다른 블로그에서는 nextjs + mui ssr 설정할 때 @mui/styles 에서 ServerStyleSheets()로 스타일 추출해서 때려박는 방식을 쓰고 있길래 나도 해보려고 봤더니 모듈이 deprecated인거야. 그럼 쓰면 안되잖아~

@mui/styles는 더이상 쓰지 말자.

그래서 mui에서 제공하는 nextjs 예제를 보니 전혀 다른 방식으로 SSR을 하고 있더라고 따라서 mui에서 제공하는 nextjs 예제를 바로 가져다 쓰기로 결정. 👇

https://github.com/mui/material-ui/tree/master/examples/nextjs-with-typescript

 

_app.tsx(js)

import * as React from 'react';
import Head from 'next/head';
import { AppProps } from 'next/app';
import { ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import { CacheProvider, EmotionCache } from '@emotion/react';
import theme from '../src/theme';
import createEmotionCache from '../src/createEmotionCache';

// Client-side cache, shared for the whole session of the user in the browser.
const clientSideEmotionCache = createEmotionCache();

interface MyAppProps extends AppProps {
  emotionCache?: EmotionCache;
}

export default function MyApp(props: MyAppProps) {
  const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;
  return (
    <CacheProvider value={emotionCache}>
      <Head>
        <meta name="viewport" content="initial-scale=1, width=device-width" />
      </Head>
      <ThemeProvider theme={theme}>
        {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
        <CssBaseline />
        <Component {...pageProps} />
      </ThemeProvider>
    </CacheProvider>
  );
}

 

 

_app.tsx에서는 CssBaseline 태그 넣어서 css 리셋시키고 (왜냐하면 사용자 브라우저 설정마다 style 설정이 다르니까 똑같이 보이게 하려고 일단 리셋 css 적용시키는 거임.) emotion 모듈의 CacheProvider로 SSR로 구현해. 

다음은 _document.tsx(js) 파일이야.

import * as React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import createEmotionServer from '@emotion/server/create-instance';
import theme from '../src/theme';
import createEmotionCache from '../src/createEmotionCache';

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head>
          {/* PWA primary color */}
          <meta name="theme-color" content={theme.palette.primary.main} />
          <link rel="shortcut icon" href="/static/favicon.ico" />
          <link
            rel="stylesheet"
            href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
          />
          {/* Inject MUI styles first to match with the prepend: true configuration. */}
          {(this.props as any).emotionStyleTags}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

MyDocument.getInitialProps = async (ctx) => {

  const originalRenderPage = ctx.renderPage;
  const cache = createEmotionCache();
  const { extractCriticalToChunks } = createEmotionServer(cache);

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App: any) =>
        function EnhanceApp(props) {
          return <App emotionCache={cache} {...props} />;
        },
    });

  const initialProps = await Document.getInitialProps(ctx);
  const emotionStyles = extractCriticalToChunks(initialProps.html);
  const emotionStyleTags = emotionStyles.styles.map((style) => (
    <style
      data-emotion={`${style.key} ${style.ids.join(' ')}`}
      key={style.key}
      // eslint-disable-next-line react/no-danger
      dangerouslySetInnerHTML={{ __html: style.css }}
    />
  ));

  return {
    ...initialProps,
    emotionStyleTags,
  };
};

여기에서 원래 css 추출해서 때려박는게 있어야 하는데 여긴 emotionCache라는 걸로 다 해결하고 있어. 문서를 읽어봐도 무슨 소린지 잘 모르겠어서 좀 더 살펴봐야 할 것 같아 ㅠㅠ 문서도 빈약함. 암튼 예제대로 하려면 theme.ts하고 createEmotionCache.ts라는 파일을 만들어 줘야해. theme.ts는 그냥 theme 정의한 거고 createEmotionCache는 옵션이랑 함께 createCache() 사용하게 해주는 것 뿐.

추가 파일들

createEmotionCache.ts

import createCache from "@emotion/cache";

// prepend: true moves MUI styles to the top of the <head> so they're loaded first.
// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
export default function createEmotionCache() {
  return createCache({ key: "css", prepend: true });
}

theme.ts

import { createTheme } from "@mui/material/styles";
import { red } from "@mui/material/colors";

// Create a theme instance.
const theme = createTheme({
  palette: {
    primary: {
      main: "#556cd6",
    },
    secondary: {
      main: "#19857b",
    },
    error: {
      main: red.A400,
    },
  },
});

export default theme;

이것들까지 포함시키고 테스트하면 SSR이 적용된 걸 확인할 수 있겠지? 시험삼아 welcome to next.js 아래 mui 기본 버튼을 variant 별로 한개씩 넣어봤어.

원래 모습

_document.tsx를 지우고(SSR 기능을 없애고) javascript를 disable로 테스트하면 아래처럼 mui 기본스타일이 없는 쌩 html만 나와.

SSR 적용 X

그런데 _document.tsx를 통해 SSR이 적용된 상태에서 javascript를 disable로 테스트하면 아래 캡쳐처럼 버튼에 mui 기본 스타일이 적용된 걸 확인할 수 있지. 나머지 요소들은 mui로 작성한 게 아니라서 스타일이 없는 상태로 보여지는 거구.

SSR 적용

 ※ 이건 당구장 표시 100개 있어야해. 현재(2022.06.14) next.js 12.1.6 버전에서는 SSR이 정상적으로 되지 않아. 정식 릴리즈는 아니고 프리 릴리즈 상태인 12.1.7 canari.38 버전으로 업그레이드 해주니까 되더라고! 매우 참고해!

 

이제 tailwindcss만 적용하면 되겠다. emotion styled에다가 tailwindcss로 css 넣으면 괜찮을 것 같아서 ㅎㅎ 근데 글이 너무 길어지니까 그건 내일! 휴 빡시다 ㅋㅋ

반응형