Next.js 공식 홈페이지에서 제공하는 튜토리얼 step 3

이승재·2021년 12월 31일
0

Next.js

목록 보기
2/9
post-thumbnail

step2와 이어집니다.

public

public 디렉토리는 이미지와 같은 정적 데이터를 갖고있는 디렉토리입니다. public디렉토리 안에있는 자원들은 루트 경로를 통해 사용할 수 있습니다.

public디렉토리 안에 images 디렉토리를 만든 후에 profile.jpg 라는 아무 사진을 만들어 봅시다.

기존에 HTML을 통해 사진을 표출할 땐

<img src="/images/profile.jpg" alt="Your Name" />

다음과 같이 표시 했었습니다.

이는 이 항목들을 수동으로 처리해야 함을 의미합니다.

  • 다양한 화면 크기에 대한 이미지 반응 보장
  • 타사 도구 또는 라이브러리를 사용하여 이미지 최적화 뷰포트로 들어갈 때만 영상 로드

하지만 next/imageimg 태그의 확장판으로

  • Next.js는 기본적으로 이미지 최적화를 지원합니다. 이를 통해 브라우저가 지원할 때 WebP와 같은 최신 포맷으로 이미지의 크기를 조정하고 최적화하고 제공할 수 있다. 이렇게 하면 뷰포트가 작은 장치로 큰 이미지를 전송할 필요가 없습니다.
  • 또한 Next.js는 미래의 이미지 포맷을 자동으로 채택하여 이러한 포맷을 지원하는 브라우저에 제공할 수 있다.

image는 기본적으로 lazyloading이 지원되어 있어 스크롤을 내릴시에 로드되고 그외에 속도에 영향을 주지 않게 된다.

Matadata

Next에서title과 같은 matadata를 수정하기 위해선 Head 태그를 사용합니다.

index.js 에서 다음과 같은 코드를 확인해 보세요

<Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
</Head>

step 2 에서 만든 first-post.js에서 Head를 추가해보고 변화를 확인해 봅시다.

import Link from 'next/link'
import Head from 'next/head'

export default function FirstPost() {
    return (
        <>
            <Head>
                <title>First Post</title>
            </Head>
            <h1>First Post</h1>
            <h2>
                <Link href="/">
                    <a>Back to home</a>
                </Link>
            </h2>
        </>
    )
}

다음과 같이 first-post.js 의 내용을 수정해 봅시다.

화면을 이동할 때마다 브라우저 title이 변경되며 개발자 도구를 통해 head 태그를 확인해 봤을 때 변경됨을 확인 할 수 있습니다.

Head에 대한 API는 https://nextjs.org/docs/api-reference/next/head 이곳에서 더 확인해 보세요.

lang 특성을 추가하기 위해 html 태그를 커스터마이징 하려면 pages/_document.js 파일을 작성하여 사용자 정의할 수 있습니다.
관련 내용은 https://nextjs.org/docs/advanced-features/custom-document 이곳에서 더 확인해 보세요.

Third-Party JavaScript

Next.js 에선 Third-Party를 어떻게 추가할 수 있을 까요. first-post.js 에 Facebook SDK를 추가해 봅시다.

메타 데이터 외에도 빠르게 받아와야 되는데이터들은 head 에 넣듯이 다음과 같이 작성해 보자

<Head>
  <title>First Post</title>
  <script src="https://connect.facebook.net/en_US/sdk.js" />
</Head>

이 스크립트는 Facebook 소셜 플러그인 및 기타 기능을 도입하는 데 일반적으로 사용되는 Facebook SDK를 포함합니다.
이러한 방식으로 스크립트를 포함하면 동일한 페이지에서 가져온 다른 자바스크립트 코드에 대해 언제 로드되는지 명확하게 알 수 없게 됩니다.
특정 스크립트가 렌더 차단 중이고 페이지 내용 로드를 지연시킬 수 있는 경우 성능에 심각한 영향을 미칠 수 있습니다.

Script 태그를 사용해 이것을 해결해 봅시다.
Script 태그에는 src, strategy, onLoad 3가지 속성이 있습니다.

  • src : 서드 파티 스크립트의 주소
  • strategy: 서드 파티를 언제 로드해 올건지에 대한 값이다.
  • onLoad : 서드 파티를 가져온 후 실행하는 javascript 잘 가져 왔는지 확인 용도로 사용하기도 함

http://localhost:3000/posts/first-post에 접속해 보세요.
브라우저의 개발자 도구를 사용하면 위의 메시지가 콘솔에 기록되어 있는 것을 볼 수 있습니다.
window.FB를 실행하여 스크립트가 이 전역 변수를 채웠는지 확인할 수 있습니다.

CSS Styling

이미 index.js 에서의 styling 코드를 확인하 신 분들도 있을 겁니다.

<style jsx>{`
  …
`}</style>

다음과 같은 형식으로 작성되어 있는데요
이 페이지는 styled-jsx라는 라이브러리를 사용하고 있습니다. 이것은 CSS-in-JS 라이브러리입니다.
이 라이브러리를 사용하면 React 구성 요소 내에서 CSS를 작성할 수 있으며 CSS 스타일은 범위가 지정됩니다 (다른 구성 요소는 영향을받지 않습니다).

Layout Commponent

모든 페이지를 감쌀 수 있는 Layout 컴포넌트를 다음과 같이 만들어 봅시다.

  • commponents 디렉토리 안에 Layout.js를 만들어 보세요.
export default function Layout({ children }) {
  return <div>{children}</div>
}

만든 Layout 컴포넌트를 통해 first-post.js 를 감싸보세요.

export default function FirstPost() {
    return (
        <Layout>
            <Head>
                <title>First Post</title>
            </Head>
            <Script
                src="https://connect.facebook.net/en_US/sdk.js"
                strategy="lazyOnload"
                onLoad={() =>
                    console.log(`script loaded correctly, window.FB has been populated`)
                }
            />
            <h1>First Post</h1>
            <h2>
                <Link href="/">
                    <a>Back to home</a>
                </Link>
            </h2>
        </Layout>
    )
}

그다음 본격적으로 CSS를 추가해 봅시다.

  • commponents 디렉토리 안에 layout.module.css 파일을 만들고 다음과 같이 작성해 보세요
.container {
    max-width: 36rem;
    padding: 0 1rem;
    margin: 3rem auto 6rem;
  }
  • CSS Module을 사용시에는 네이밍을 module.css로 작성하세요

그리고 layout.js를 다음과 같이 수정해 보세요

import styles from './layout.module.css'

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

다음과 같이 CSS가 적용되는 모습이다. 기존에 CRA를 통한 Post-css module과 비슷한 것 같다.

Next.js에 빌트인 되어있는 기능이다.(CSS Module, Sass, styled-jsx)

Global Styles

CSS Module 은 컴포넌트 단위로써 CSS를 적용할 때 유용하게 사용합니다. 하지만 누구나 사용하는 글로벌한 CSS를 적용하고 싶다면 어떻게 할까요?

글로벌한 CSS 를 만들기 위해선 page/_app.js 파일을 생성하고 다음과 같이 작성해 보세요

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

App 컴포넌트는 모든 다른 페이지의 최상위 구성요소 입니다. 페이지 사이를 탐색할 때 이 컴포넌트를 사용하여 상태 유지를 할 수 있게 됩니다.

  • _app.js 를 추가하였다면 실행시키고 있던 것을 중지시키고 다시 실행 시켜야 포함이 되게 됩니다.

Global CSS 를 추가해 보자

글로벌 CSS 는 무조건 _app.js 를 통해서만 가져올 수 있습니다.

  • 최상위에 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;
}

그리고 _app.js에 import 해주자.

import '../styles/global.css'

글로벌로 적용된 a 태그가 스타일이 입혀진 것을 볼 수 있다.

코드 다듬기

설명을 위해 간단히 스타일을 조금씩만 추가해 보았습니다. 나머지 스타일링을 하여 좀더 보기 편하게 만들어 봅시다.

components/layout.module.css

.container {
  max-width: 36rem;
  padding: 0 1rem;
  margin: 3rem auto 6rem;
}

.header {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.backToHome {
  margin: 3rem 0 0;
}

styles/utils.module.css

.heading2Xl {
  font-size: 2.5rem;
  line-height: 1.2;
  font-weight: 800;
  letter-spacing: -0.05rem;
  margin: 1rem 0;
}

.headingXl {
  font-size: 2rem;
  line-height: 1.3;
  font-weight: 800;
  letter-spacing: -0.05rem;
  margin: 1rem 0;
}

.headingLg {
  font-size: 1.5rem;
  line-height: 1.4;
  margin: 1rem 0;
}

.headingMd {
  font-size: 1.2rem;
  line-height: 1.5;
}

.borderCircle {
  border-radius: 9999px;
}

.colorInherit {
  color: inherit;
}

.padding1px {
  padding-top: 1px;
}

.list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.listItem {
  margin: 0 0 1.25rem;
}

.lightText {
  color: #666;
}

components/layout.js

import Head from 'next/head'
import Image from 'next/image'
import styles from './layout.module.css'
import utilStyles from '../styles/utils.module.css'
import Link from 'next/link'

const name = 'Your Name'
export const siteTitle = 'Next.js Sample Website'

export default function Layout({ children, home }) {
  return (
    <div className={styles.container}>
      <Head>
        <link rel="icon" href="/favicon.ico" />
        <meta
          name="description"
          content="Learn how to build a personal website using Next.js"
        />
        <meta
          property="og:image"
          content={`https://og-image.vercel.app/${encodeURI(
            siteTitle
          )}.png?theme=light&md=0&fontSize=75px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg`}
        />
        <meta name="og:title" content={siteTitle} />
        <meta name="twitter:card" content="summary_large_image" />
      </Head>
      <header className={styles.header}>
        {home ? (
          <>
            <Image
              priority
              src="/images/profile.jpg"
              className={utilStyles.borderCircle}
              height={144}
              width={144}
              alt={name}
            />
            <h1 className={utilStyles.heading2Xl}>{name}</h1>
          </>
        ) : (
          <>
            <Link href="/">
              <a>
                <Image
                  priority
                  src="/images/profile.jpg"
                  className={utilStyles.borderCircle}
                  height={108}
                  width={108}
                  alt={name}
                />
              </a>
            </Link>
            <h2 className={utilStyles.headingLg}>
              <Link href="/">
                <a className={utilStyles.colorInherit}>{name}</a>
              </Link>
            </h2>
          </>
        )}
      </header>
      <main>{children}</main>
      {!home && (
        <div className={styles.backToHome}>
          <Link href="/">
            <a>← Back to home</a>
          </Link>
        </div>
      )}
    </div>
  )
}
  • 페이지 내용을 설명하는 메타 태그 추가
  • 홈(/) 이 아니면 <- Back to home 표시 하는 과정 추가
  • Image 태그를 통해 profile.png 출력

index.js

import Head from 'next/head'
import Layout, { siteTitle } from '../components/layout'
import utilStyles from '../styles/utils.module.css'

export default function Home() {
  return (
    <Layout home>
      <Head>
        <title>{siteTitle}</title>
      </Head>
      <section className={utilStyles.headingMd}>
        <p>[Your Self Introduction]</p>
        <p>
          (This is a sample website - you’ll be building a site like this on{' '}
          <a href="https://nextjs.org/learn">our Next.js tutorial</a>.)
        </p>
      </section>
    </Layout>
  )
}

Styling Tips

Using classnames library to toggle classes

npm install classnames or yarn add classnames. 을 사용하여 토글 시켜 반전되는 스타일링이 있을 때 다음과 같이 사용 할 수있다.

.success {
  color: green;
}
.error {
  color: red;
}
import styles from './alert.module.css'
import cn from 'classnames'

export default function Alert({ children, type }) {
  return (
    <div
      className={cn({
        [styles.success]: type === 'success',
        [styles.error]: type === 'error'
      })}
    >
      {children}
    </div>
  )
}

Customizing PostCSS Config

Next.js 는 별도의 설정 없이 PostCSS를 사용합니다.
PostCSS 구성을 사용자 정의하려면 postcss.config.js라는 최상위 파일을 생성하면 됩니다. Tailwind CSS와 같은 라이브러리를 사용할 경우 유용합니다.

Sass 를 사용하자

믹스인과 같은 여러 기능이 있는 빌트인된 Sass를 사용해 보는 것도 좋을 듯하다.

profile
웹개발이 하고싶어요

0개의 댓글