Next.js는 2016년에 발표되어 현재 React.js 기반의 풀스택 웹 개발을 이끄는 프레임워크로 주목받고 있습니다. React의 공식 홈페이지에서는 React로 신규 프로젝트를 구축하는 경우, Next.js를 추천하고 있기도 하죠. Vercel에서는 Next.js의 주요 기능을 다음과 같이 소개하고 있습니다.
다양한 형태의 형태의 데이터에 대하여 최적화를 지원하고 있습니다. 이미지, 동영상과 같은 미디어 에셋 뿐만 아니라 캐싱, 렌더링, 폰트 등 하나의 서비스를 구성하는 여러 요소를 Next.js에서 지원하는 라이브러리를 통해 손쉽게 설정할 수 있습니다.
동적인 HTML 스트리밍을 지원합니다. API에서 데이터 fetch가 완료되지 않은 시점에서는 세팅해놓은 loading 메세지 혹은 화면이 클라이언트에 표시되었다가 fetch가 완료되면 전체 HTML의 일부분에 대하여 동적으로 렌더링 된 부분만 바꿔치기하여 화면을 갱신합니다. 이러한 기능은 React의 Suspense라는 컴포넌트를 활용한 것이며, 자식 요소에서 사용할 데이터의 fetch가 완료될 때 까지 특정 메세지나 화면을 클라이언트에 표시해줍니다.
Next.js는 기본적으로 서버 컴포넌트 렌더링을 지원합니다. 정적 렌더링, 동적 렌더링, 스트리밍 등의 세 가지 렌더링 전략을 활용할 수 있으며, 클라이언트 단의 불필요한 JavaScript 호출을 줄이고 민감 정보 등이 노출되는 것을 방지할 수 있다는 점에서 여러 이점이 있습니다.
일반적으로 서버 컴포넌트를 활용한 데이터 fetch를 권장하고 있습니다. 이는 서버와 클라이언트 사이의 불필요한 호출 주고받기를 줄이고 민감 정보를 보다 더 안전하게 관리할 수 있기 때문이죠. UI/UX 향상을 위해 캐싱과 프리로딩 등의 방식을 혼합 적용하여 병렬 데이터 처리를 효과적으로 수행할 수 있도록 구성할 수 있습니다.
이번 실습에서는 Next.js를 활용한 Markdown 편집기를 배포해보겠습니다. React에서 Markdown을 렌더링 할 수 있는 react-markdown 패키지가 사용되었으며, GitHub 스타일의 Markdown을 적용할 수 있는 등 옵션을 적용할 수 있습니다.
실습은 아래 저장소의 Next.js 어플리케이션을 통해 진행됩니다. 저장소를 clone 하거나 fork 해주세요.
실습 코드의 Next.js에서는 App Router 방식을 활용하여, /app
디렉토리 하위에 있는 React 코드를 렌더링하게 됩니다. 주요 파일로는 layout.js
과 page.js
가 있으며, 파일의 내용은 다음과 같습니다.
layout.js
import { Inter } from "next/font/google";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata = {
title: "Markdown Editor",
description: "Next.js Markdown Editor",
};
export default function RootLayout({ children }) {
return (
<html lang="ko">
<body className={inter.className}>{children}</body>
</html>
);
}
/app
디렉토리에서 UI를 구성하는 최상위 레이아웃을 나타내는 파일입니다. 일반적인 HTML 파일의 <head>
태그에서 정의하는 메타데이터를 metadata
라는 이름의 변수에 대입하여 적용할 수 있습니다.
RootLayout
함수는 전역적으로 적용되는 <html>
과 <body>
태그를 반환하며, 생략할 수 없는 필수요소입니다. 필요에 따라 /app
디렉토리 하위에 다른 디렉토리를 만들어 layout.js
파일을 만들어 페이지를 구분할 수 있습니다.
page.js
'use client';
import { useState, useRef } from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from "remark-gfm";
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { materialLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
export default function Home() {
const [markdown, setMarkdown] = useState(`
# Hello, Cloudtype!
\`\`\`javascript
function sum(a, b) {
return a + b;
}
\`\`\`
`);
const contentRef = useRef(null);
const handleChange = (event) => {
setMarkdown(event.target.value);
};
return (
<div className="flex h-screen font-sans">
<div className="flex-1 p-6">
<textarea
value={markdown}
onChange={handleChange}
className="w-full h-full resize-none border-2 border-gray-300 rounded-lg p-4 text-lg leading-normal focus:outline-none focus:border-blue-500"
/>
</div>
<div className="flex-1 p-6 overflow-auto border-l border-gray-300">
<div ref={contentRef} className='markdown'>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={{
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<SyntaxHighlighter
style={materialLight}
language={match[1]}
PreTag="div"
children={String(children).replace(/\n$/, '')}
{...props}
/>
) : (
<code className={className} {...props}>
{children}
</code>
);
}
}}
>
{markdown}
</ReactMarkdown>
</div>
</div>
</div>
);
}
'use client'
는 Next.js에서 Client Components를 활용할 때에 파일 최상위(import 문의 윗부분)에 선언하는 디렉티브입니다. 클라이언트 단에서 일어나는 이벤트 리스너나 각종 상태값을 관리/조작하기 위해서는 Client Components를 사용해야 하죠. Next.js는 기본적으로 Server Components를 사용하기 때문에 Markdown 에디터에서 useState()
, useRef()
, onChange
등을 활용하기 위해서는 반드시 디렉티브를 설정해야 합니다.
클라우드타입에 로그인 후 우측 네비바의 ➕ 버튼을 눌러 새 프로젝트 창을 띄우고 프로젝트 이름과 표시 이름을 입력한 뒤 생성하기 버튼을 누릅니다.
package.json
파일은 다음과 같습니다.
{
"name": "nextjs-markdown",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"file-saver": "^2.0.5",
"next": "14.2.2",
"react": "^18",
"react-dom": "^18",
"react-markdown": "^9.0.1",
"react-syntax-highlighter": "^15.5.0",
"remark-gfm": "^4.0.0"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.12",
"postcss": "^8",
"tailwindcss": "^3.4.1"
}
}
scripts
에 Next.js 프로젝트를 빌드 및 실행하기 위한 명령어가 정의되어 있습니다.
클라우드타입의 프로젝트 페이지에서 ➕ 버튼을 누르고 Next.js를 선택한 후, 미리 fork 해놓은 nextjs-markdown 를 선택합니다. 기타 설정은 아래를 참고하여 입력한 후 배포하기 버튼을 클릭합니다.
npm run build
혹은 yarn build
배포가 완료되면 Next.js 어플리케이션 페이지의 연결 탭에서 https://
로 시작되는 URL을 통해 서비스에 접속이 가능합니다.