step2와 이어집니다.
public
디렉토리는 이미지와 같은 정적 데이터를 갖고있는 디렉토리입니다. public
디렉토리 안에있는 자원들은 루트 경로를 통해 사용할 수 있습니다.
public
디렉토리 안에 images
디렉토리를 만든 후에 profile.jpg
라는 아무 사진을 만들어 봅시다.
기존에 HTML을 통해 사진을 표출할 땐
<img src="/images/profile.jpg" alt="Your Name" />
다음과 같이 표시 했었습니다.
이는 이 항목들을 수동으로 처리해야 함을 의미합니다.
하지만 next/image
는 img
태그의 확장판으로
image는 기본적으로 lazyloading이 지원되어 있어 스크롤을 내릴시에 로드되고 그외에 속도에 영향을 주지 않게 된다.
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 이곳에서 더 확인해 보세요.
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를 실행하여 스크립트가 이 전역 변수를 채웠는지 확인할 수 있습니다.
이미 index.js
에서의 styling 코드를 확인하 신 분들도 있을 겁니다.
<style jsx>{`
…
`}</style>
다음과 같은 형식으로 작성되어 있는데요
이 페이지는 styled-jsx라는 라이브러리를 사용하고 있습니다. 이것은 CSS-in-JS 라이브러리입니다.
이 라이브러리를 사용하면 React 구성 요소 내에서 CSS를 작성할 수 있으며 CSS 스타일은 범위가 지정됩니다 (다른 구성 요소는 영향을받지 않습니다).
모든 페이지를 감쌀 수 있는 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;
}
그리고 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)
CSS Module 은 컴포넌트 단위로써 CSS를 적용할 때 유용하게 사용합니다. 하지만 누구나 사용하는 글로벌한 CSS를 적용하고 싶다면 어떻게 할까요?
글로벌한 CSS 를 만들기 위해선 page/_app.js
파일을 생성하고 다음과 같이 작성해 보세요
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}
이 App
컴포넌트는 모든 다른 페이지의 최상위 구성요소 입니다. 페이지 사이를 탐색할 때 이 컴포넌트를 사용하여 상태 유지를 할 수 있게 됩니다.
_app.js
를 추가하였다면 실행시키고 있던 것을 중지시키고 다시 실행 시켜야 포함이 되게 됩니다.글로벌 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 태그가 스타일이 입혀진 것을 볼 수 있다.
설명을 위해 간단히 스타일을 조금씩만 추가해 보았습니다. 나머지 스타일링을 하여 좀더 보기 편하게 만들어 봅시다.
.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;
}
.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;
}
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>
)
}
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>
)
}
classnames
library to toggle classesnpm 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>
)
}
Next.js 는 별도의 설정 없이 PostCSS를 사용합니다.
PostCSS 구성을 사용자 정의하려면 postcss.config.js라는 최상위 파일을 생성하면 됩니다. Tailwind CSS와 같은 라이브러리를 사용할 경우 유용합니다.
믹스인과 같은 여러 기능이 있는 빌트인된 Sass를 사용해 보는 것도 좋을 듯하다.