こんにちは。KOUKIです。
NextJSとTypeScriptに興味が出てきまして、勉強がてら備忘を記事に残したいと思います。
前提事項
Node.JSがローカルにインストールされていることを前提とします。
1 2 3 4 5 |
$ npx -v 8.5.5 $ node -v v17.9.0 |
プロジェクトの作成
下記のコマンドで、プロジェクトを作成しましょう。
1 |
npx create-next-app next-site --typescript |
作成が完了したら、下記のコマンドでNextJSを起動します。
1 2 |
cd next-site/ npm run dev |
ブラウザを立ち上げて「localhost:3000」でアクセスしましょう。

上記の画面が表示されれば、OKです。
さあ、ワクワクのスタートです…
TypeScriptの設定追加
先ほどのコマンドを実行したときに、「tsconfig.json」ファイルが作成されます。
ここには、TypeScriptの設定がまとめられています。
設定の追加も可能です。例として「”strictNullChecks”: true」を設定しておきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
{ "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "strictNullChecks": true, <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 追加 "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"] } |
フロントページの変更
pagesフォルダ配下のindex.tsxファイルが先ほど表示したフロントのページになるので、以下のように編集してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import type { NextPage } from 'next' import Head from 'next/head' import Image from 'next/image' import styles from '../styles/Home.module.css' const Home: NextPage = () => { return ( <> <Head> <title>Create Next App</title> <meta name="description" content="Generated by create next app" /> <link rel="icon" href="/favicon.ico" /> </Head> <div className={styles.container}> <main className={styles.main}> <h1 className={styles.title}>Welcome To Next Site</h1> </main> </div> </> ) } export default Home |

フロントページのCSSの変更
stylesフォルダのHome.module.cssがフロントページのCSSになるため、変更しましょう。
1 2 3 4 5 6 7 8 9 10 11 |
.container { padding: 0 2rem; display: grid; place-items: center; } .title { line-height: 1.15; font-size: 4rem; text-align: center; } |
フロントページのindex.tsxも少し変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const Home: NextPage = () => { return ( <> <Head> <title>Create Next App</title> <meta name="description" content="Generated by create next app" /> <link rel="icon" href="/favicon.ico" /> </Head> <main> <header className={styles.container}> <h1 className={styles.title}>Welcome To Next Site</h1> </header> </main> </> ) } |

Componentの作成
次は、Componentを作成しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
mkdir -p components/header touch components/header/index.tsx # Home.module.css -> header.module.cssに変更しておく mv styles/Home.module.css components/header/header.module.css $ tree -L 3 -I node_modules . ├── README.md ├── components │ └── header │ ├── header.module.css │ └── index.tsx ├── next-env.d.ts ├── next.config.js ├── package.json ├── pages │ ├── _app.tsx │ ├── api │ │ └── hello.ts │ └── index.tsx ├── public │ ├── favicon.ico │ └── vercel.svg ├── styles │ └── globals.css ├── tsconfig.json └── yarn.lock |
Header Componentには、以下のコードを実装しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
import styles from './header.module.css' const Header = () => { return ( <header className={styles.container}> <h1 className={styles.title}>Welcome To Next Site</h1> </header> ) } export default Header |
続いて、フロントページのindex.tsxを変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import type { NextPage } from 'next' import Head from 'next/head' import Header from '../components/header' const Home: NextPage = () => { return ( <> <Head> <title>Create Next App</title> <meta name="description" content="Generated by create next app" /> </Head> <main> <Header /> </main> </> ) } export default Home |

元々、フロントページに設定されていたHeaderをComponent化したので、他のページでも使いまわすことが可能になりました。
共通CSSについて
stylesフォルダ配下のglobals.cssは、NextJSアプリ共通に適用させるCSSを書くところみたいです。
試しに、背景及びテキスト文字の色を変更してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/* 追加 */ :root { --pageg-background: #222; --page-text: #ddd; } 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; background-color: var(--pageg-background); /* 適用 */ color: var(--page-text); /* 適用 */ } a { color: inherit; text-decoration: none; } * { box-sizing: border-box; } |

結構簡単ですよね^^
importの絶対パスの設定
現状、他のモジュールを読み込むときは、相対パスになっています。
1 |
import Header from '../components/header' |
TypeScriptの設定で絶対パスに変更できるので、試してみましょう。
tsconfig.jsonに以下の設定を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "compilerOptions": { "baseUrl": ".", // 追加 "paths": { // 追加 "@components/*": ["components/*"], "@styles/*": ["styles/*"] }, ... }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"] } |
componentsとstylesを対象にしました。
相対パスになっていたimportを絶対パスに変更しましょう。
1 2 3 |
// pages/index.tsx // import Header from '../components/header' import Header from '@components/header' |
1 2 3 |
// pages/_app.tsx // import '../styles/globals.css' import '@styles/globals' |
Ctrl + CでNextJSサーバーを一旦Stopして、下記のコマンドでリスタートしましょう。
1 |
$ npm run dev |

OKですね。
ナビゲーションの実装
サイトには欠かせないナビゲーションを実装しましょう。
1 2 3 |
mkdir components/navigation touch components/navigation/index.tsx touch components/navigation/navigation.module.css |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import type { NextPage } from 'next' import Head from 'next/head' import Header from '@components/header' import Navigation from '@components/navigation' const Home: NextPage = () => { return ( <> <Navigation /> <Head> <title>Create Next App</title> <meta name="description" content="Generated by create next app" /> </Head> <main> <Header /> </main> </> ) } export default Home |
HomeページとAboutページのナビゲーションを作成しました。続いて、CSSの実装を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
.list { list-style: none; padding: 1em 0; display: flex; } .list > * + * { margin-left: 1rem; } .navAnchor { text-decoration: underline 2px; } .navAnchor:hover, .navAnchor:focus { text-decoration: underlined dotted 2px; } |
ここまで実装すると以下のナビゲーションが画面上に表示されます。

Aboutページはまだ作成していないので、アクセスすると404エラーのページが表示されます。
これは、NextJSが自動的に生成してくれるもので、実装等は行っていません。
すごく便利ですよね。

Aboutページを作成
Aboutページを作成します。
1 |
touch pages/about.tsx |
pages配下にaboutページを追加しました。pages配下にファイルを置くだけで、NextJSが良しなにルーティングしてくれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import Navigation from '@components/navigation' const About = () => { return ( <> <Navigation /> <header> <h2>This is an About Page</h2> </header> </> ) } export default About |

getStaticProps関数の実装
getStaticProps関数を実装します。
この関数は、アプリ(next-site)のビルド時にServer上で実行されるようです。
ページ上で表示したいデータをビルド時に取得し、そのデータを画面に表示させる、みたいなことができそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
import type { InferGetStaticPropsType } from 'next' import Head from 'next/head' import Header from '@components/header' import Navigation from '@components/navigation' import { getPostList } from 'shared/util' type PostList = string[] // アプリケーションのビルド時に実行される // getStaticPropsはNextJSの機能である // https://nextjs.org/docs/basic-features/data-fetching/get-static-props export const getStaticProps = async () => { const posts: PostList = getPostList() return { props: { posts } } } // InferGetStaticPropsTypeによりpostsがstringのリストであることが類推される const Home = ({ posts }: InferGetStaticPropsType<typeof getStaticProps >) => { return ( <> <Navigation /> <Head> <title>Create Next App</title> <meta name="description" content="Generated by create next app" /> </Head> <main> <Header /> </main> {posts.length > 0 && ( <ul> {/* postsはstringのリストであるため、slugがstringであることが類推される */} {posts.map((slug) => ( <li key={slug}> {slug.replaceAll('-', ' ')} </li> ))} </ul> )} </> ) } export default Home |
ユーザーのPost情報を画面上に表示する処理を書きました。
getPostList関数は、このあと作ります。
getPostList関数の実装
以下のファイルを作成してください。
1 2 |
mkdir shared touch shared/util.tsx |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import fs from 'fs' import path from 'path' export const getPostList = () => { try { // パスの作成 // console.log(process.cwd()) -> /Users/hoge/Desktop/next-site const postsDir = path.join(process.cwd(), 'pages/post') // pages/post配下のファイルの名前を習得 return fs .readdirSync(postsDir) .map(filename => ( filename.substring(0, filename.indexOf('.')) )) } catch { console.warn('There are no posts!') return [] } } |
pages/postディレクトリを検索して、その中に格納れているファイル名を取得する処理を実装しました。
適当にファイルを作成します。
1 2 |
mkdir pages/post touch pages/post/hello-there.tsx |
この状態で画面を表示してみます。

hello thereが表示されましたね。
hello-there.tsxの中身も実装します。
1 2 3 4 5 6 7 |
const HelloThere = () => { return <div> <h1>Hello There!</h1> </div> } export default HelloThere |
これをリストのリンクにして、ページ遷移できるようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
... import Link from 'next/link' ... const Home = ({ posts }: InferGetStaticPropsType<typeof getStaticProps >) => { return ( <> ... {posts.length > 0 && ( <ul> {posts.map((slug) => ( <li key={slug}> <Link href={`post/${slug}`}> <a> {slug.replaceAll('-', ' ')} </a> </Link> </li> ))} </ul> )} </> ) } export default Home |
これで、「hello there」を押下するとページ遷移ができます。

画像を扱う
最後に、画像処理を実装しましょう。
1 |
mkdir -p public/post/hello-there |
ここに何か適当な画像を入れてみてください。
私は、「image1.jpeg」という名前で、下記の画像を入れました。

この画像を先ほど実装した「hello-there.tsx」で読み込みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import Head from 'next/head' import Image from "next/image" const HelloThere = () => { return ( <> <Head> <title>Hello There :: MyBlog</title> <meta property="og:title" content="Hello There :: MyBlog" /> </Head> <article> <h1>Hello There!</h1> <Image src="/post/hello-there/image1.jpeg" width={640} height={427} /> </article> </> ) } export default HelloThere |
Headタグを使うとページごとにTitleをつけられるので、便利です。

おわりに
NextJSのサイト作りを通して、基本的な機能を紹介できたと思います。
NextJSはReactのフレームワークですが、かなり使いやすくなっている印象ですね。
仕事でもガンガン使っていきたいと思います。
それでは、また!
コメントを残す
コメントを投稿するにはログインしてください。