노현진's Blog

pnpm + tsdown으로 React 라이브러리 만들기 ③ - Next.js demo 생성

pnpm + tsdown으로 React 라이브러리를 만드는 과정에서 Next.js demo 생성 방법에 대해 정리한 페이지입니다.

Posted
By HyunJinNo

Tags

monorepo, Nextra, Next.js, pnpm, React, tsdown

Environment

pnpm v10.32.1

nextra v4.6.1

Next.js v16.1.6

react v19.2.3

tsdown v0.21.3

@tsdown/css v0.21.4

1. 개요

pnpm + tsdown으로 React 라이브러리를 만드는 방법에 대해 정리한 페이지입니다.

총 5개의 Part로 분리하여 작성하였으며, 이 페이지에서는 Next.js demo 생성 과정을 다룹니다.

2. Next.js demo 생성하기

2.1. demo 생성하기

먼저 apps 디렉토리를 생성합니다.

bash
1mkdir apps
2cd apps

이후 다음 명령어를 입력하여 생성한 React 라이브러리를 테스트할 demo 애플리케이션을 생성합니다.

bash
1pnpm create next-app

이후 apps/demo 디렉토리에서 불필요한 pnpm-lock.yaml, pnpm-workspace.yaml, node_modules를 삭제합니다.

2.2. Nextra 설치하기

2.2.1. Nextra 의존성 설치하기

생성한 demo 앱에서는 라이브러리 문서를 작성할 예정이므로 정적 사이트 생성 도구인 Nextra를 설치하겠습니다. apps/demo 디렉토리에서 다음 명령어를 입력하여 Nextra를 설치합니다.

bash
1pnpm add nextra nextra-theme-docs

2.2.2. next.config.ts 설정하기

next.config.ts 파일에서 nextra를 설정하고, turbopackresolveAlias 옵션을 사용하여 mdx-components 파일을 alias로 등록합니다. 또한 output: "export" 옵션을 사용하여 정적 사이트로 빌드할 수 있도록 설정합니다.

typescript
1import type { NextConfig } from "next";
2import nextra from "nextra";
3
4const nextConfig: NextConfig = {
5  /* config options here */
6  reactCompiler: true,
7  output: "export",
8  images: {
9    unoptimized: true,
10  },
11};
12
13const withNextra = nextra({
14  // ... other Nextra config options
15});
16
17export default withNextra({
18  ...nextConfig,
19  turbopack: {
20    resolveAlias: {
21      // Path to your `mdx-components` file with extension
22      "next-mdx-import-source-file": "./src/mdx-components.tsx",
23    },
24  },
25});

2.2.3. mdx-components.tsx 생성하기

apps/demo/src 디렉토리에 mdx-components.tsx를 생성합니다.

typescript
1/* mdx-components.tsx */
2
3import { useMDXComponents as getThemeComponents } from "nextra-theme-docs"; // nextra-theme-blog or your custom theme
4import { MDXComponents } from "nextra/mdx-components";
5
6// Get the default MDX components
7const themeComponents = getThemeComponents();
8
9// Merge components
10export function useMDXComponents(components: MDXComponents) {
11  return {
12    ...themeComponents,
13    ...components,
14  };
15}

2.2.4. 검색 기능 추가하기

문서 내 검색 기능을 추가하기 위해 pagefind 패키지를 설치합니다.

bash
1pnpm add -D pagefind

이후 apps/demo 디렉토리 내 package.json 파일을 열고, 다음과 같은 postbuild 스크립트를 추가합니다.

Static exports:

json
1"scripts": {
2  "postbuild": "pagefind --site .next/server/app --output-path out/_pagefind"
3}

2.2.5. 루트 layout 설정하기

먼저 apps/demo/src/app 디렉토리에 있는 page.tsx, favicon.ico 파일을 삭제합니다. 그리고 globals.css 파일을 열고 Tailwind CSS 부분만 남기고 내용을 삭제합니다.

css
1@import "tailwindcss";

이후 apps/demo/src/app 디렉토리에 있는 layout.tsx 파일을 열고 다음과 같이 작성합니다.

typescript
1/* layout.tsx */
2
3import type { Metadata } from "next";
4import { Footer, Layout, Navbar } from "nextra-theme-docs";
5import { Head } from "nextra/components";
6import { getPageMap } from "nextra/page-map";
7import "./globals.css";
8import "nextra-theme-docs/style.css";
9import { Logo } from "@/components/Logo";
10
11export const metadata: Metadata = {
12  title: {
13    default: "react-toc",
14    template: "%s | react-toc",
15  },
16  authors: [{ name: "HyunJinNo", url: "https://github.com/HyunJinNo" }],
17};
18
19const navbar = (
20  <Navbar
21    logo={
22      <div className="flex flex-row items-center gap-2">
23        <Logo width={40} height={40} />
24        <p className="font-bold">react-toc</p>
25      </div>
26    }
27    projectLink="https://github.com/HyunJinNo/react-toc"
28    // ... Your additional navbar options
29  />
30);
31
32const footer = (
33  <Footer className="flex flex-row gap-1">
34    © {new Date().getFullYear()}
35    <a className="hover:underline" href="https://github.com/HyunJinNo">
36      HyunJinNo.
37    </a>
38  </Footer>
39);
40
41export default async function RootLayout({
42  children,
43}: Readonly<{
44  children: React.ReactNode;
45}>) {
46  return (
47    <html
48      // Not required, but good for SEO
49      lang="ko"
50      // Required to be set
51      dir="ltr"
52      // Suggested by `next-themes` package https://github.com/pacocoursey/next-themes#with-app
53      suppressHydrationWarning
54    >
55      <Head
56      // ... Your additional head options
57      >
58        {/* Your additional tags should be passed as `children` of `<Head>` element */}
59        <link rel="icon" href="/react-toc.webp" sizes="any" />
60      </Head>
61      <body>
62        <Layout
63          navbar={navbar}
64          pageMap={await getPageMap()}
65          docsRepositoryBase="https://github.com/shuding/nextra/tree/main/docs"
66          footer={footer}
67          // ... Your additional layout options
68        >
69          {children}
70        </Layout>
71      </body>
72    </html>
73  );
74}

2.2.6. MDX 파일 생성하기

다음과 같이 MDX 파일을 생성하여 문서를 작성할 수 있습니다.

mdx
1---
2title: Introduction
3---
4
5# Introduction
6
7`react-toc` is a library that automatically generates a Table of Contents (TOC) from your headings with scroll tracking.
8
9## Features
10
11- 🔍 Automatically builds a nested TOC from `H2` ~ `H6` elements.
12- 🧱 Provides ready-to-use heading components (`H2` ~ `H6`) with unique, URL-friendly `id`.
13- 🎯 Highlights the active heading as the user scrolls.
14- ⚡ Smooth scrolling to sections when a TOC link is clicked.
15- 🎨 Fully customizable with CSS classes and scroll options.
16- 🧩 Works with React / Next.js.
17- ✏️ Written in TypeScript with full type support.

2.2.7. _meta.global.js 설정하기

apps/demo/src 디렉토리에 _meta.global.js 파일을 생성하고, 모든 페이지 목록을 작성합니다.

javascript
1/* _meta.global.js */
2
3const config = {
4  index: {
5    type: "page",
6    title: "Easy-to-Use TOC Component",
7    display: "hidden",
8    theme: {
9      copyPage: false,
10      layout: "full",
11      toc: false,
12    },
13  },
14  docs: {
15    type: "page",
16    title: "Docs",
17    items: {
18      introduction: {
19        title: "Introduction",
20      },
21      "getting-started": {
22        title: "Getting Started",
23      },
24      api: {
25        title: "API Reference",
26        items: {
27          "toc-provider": {
28            title: "<TocProvider>",
29          },
30          toc: {
31            title: "<Toc>",
32          },
33          headings: {
34            title: "<H2> ~ <H6>",
35          },
36        },
37      },
38    },
39  },
40};
41
42export default config;

2.3. React 라이브러리 설치하기

apps/demo 디렉토리에 있는 package.json 파일을 열고, 다음과 같이 모노레포 내부 패키지를 지정합니다.

json
1{
2  "dependencies": {
3    "@hyunjinno/react-toc": "workspace:*"
4  }
5}

이후 프로젝트 루트에서 다음 명령어를 입력하여 demo에 라이브러리를 설치할 수 있습니다.

bash
1pnpm install

2.4. React 라이브러리 사용하기

설치한 라이브러리를 다음과 같이 사용할 수 있습니다.

typescript
1/* layout.tsx */
2
3import "@hyunjinno/react-toc/style.css";
typescript
1/* TocBasic.tsx */
2
3"use client";
4
5import { H2, H3, H4, H5, H6, Toc, TocProvider } from "@hyunjinno/react-toc";
6
7export const TocBasic = () => {
8  return (
9    <TocProvider className="mt-5 flex flex-row justify-between rounded-lg border border-gray-100 p-4 shadow">
10      <div className="flex flex-col gap-4">
11        <H2>a.1. Heading</H2>
12        <H2>a.2. Heading</H2>
13        <H3>a.2.1. Heading</H3>
14        <H3>a.2.2. Heading</H3>
15        <H3>a.2.3. Heading</H3>
16        <H4>a.2.3.1. Heading</H4>
17        <H4>a.2.3.2. Heading</H4>
18        <H4>a.2.3.3. Heading</H4>
19        <H5>a.2.3.3.1. Heading</H5>
20        <H6>a.2.3.3.1.1. Heading</H6>
21        <H3>a.2.4. Heading</H3>
22        <H2>a.3. Heading</H2>
23      </div>
24      <Toc className="w-44" />
25    </TocProvider>
26  );
27};

3. 다음 Part

다음 글에서는 React 라이브러리를 npm에 배포하는 과정을 다룹니다.

4. 라이브러리 배포하기

4. 참고 자료

This post is licensed under CC BY 4.0 by the author.
공유하기:

© HyunJinNo. Some rights reserved.