Next.jsはwebpackやbabel,ESLintを内包し、 SSG/SSRやリソースの最適化といった機能を提供するReactのフレームワーク。
create-next-appを実行し、npm run dev
すると
development modeでサーバーが起動するので localhost:3000/abcd
にアクセスすると pages/abcd.tsx
の export default
されたコンポーネントが描画される。
Fast Refleshが効いているのでファイルを更新するとすぐに反映される。
$ npx create-next-app --ts
$ cd my-app
$ tree -I node_modules .
.
├── README.md
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── pages
│ ├── _app.tsx
│ ├── api
│ │ └── hello.ts
│ └── index.tsx
├── public
│ ├── favicon.ico
│ └── vercel.svg
├── styles
│ ├── Home.module.css
│ └── globals.css
└── tsconfig.jso
$ npm run dev
# prod
$ npm run build
$ npm run start
pre-rendering
フロントエンドでDOMをレンダリングする場合、通常はJSのロード後コンポーネントが初期化されるhydrationを待つ必要があるが、 Next.jsでは全てのページに対して、ビルド時のStatic Generation (SSG)か、リクエスト時のServer Side Redering (SSR)を行いpre-renderingするため、最初からページを表示することができる。SEOにも有効。
デフォルトではStatic Generationされ、SSRよりもこちらが推奨される。
/pages/1
のようなDynamic Routesでも、
ブログの記事のように動的なコンテンツでない場合、
事前に getStaticPaths()
でpathと、それに対応するpropsを getStaticProps()
で取得してStatic Generationできる。
$ cat pages/\[id\].tsx
import styles from '../styles/Home.module.css'
import { useRouter } from 'next/router'
import Link from 'next/link'
import { GetStaticPropsContext, GetStaticPaths, InferGetStaticPropsType } from 'next'
type Params = {
id: string
}
export const getStaticPaths: GetStaticPaths<Params> = async () => {
return {paths: [{params: {id: "1"}}, {params: {id: "2"}}], fallback: false};
}
export const getStaticProps = async (context: GetStaticPropsContext<Params>) => {
return {props: {contents: `id is ${context.params?.id}`, id: context.params?.id}}
}
export default function Home({ contents, id }: InferGetStaticPropsType<typeof getStaticProps>) {
const router = useRouter()
return (
<div className={styles.container}>
{contents}
<Link href={`/${parseInt(id || "0") + 1}`}>
<a>+1</a>
</Link>
</div>
)
}
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/1
200
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/100
404
リクエストごとにSSRする場合、 getServerSideProps()
でpropsを返す。
import styles from '../styles/Home.module.css'
import { useRouter } from 'next/router'
import Link from 'next/link'
import { GetServerSideProps, GetServerSidePropsContext, InferGetServerSidePropsType } from 'next'
type Params = {
id: string
}
export const getServerSideProps = async (context: GetServerSidePropsContext<Params>) => {
return {props: {contents: `id is ${context.params?.id}`, id: context.params?.id}}
}
export default function Home({ contents, id }: InferGetServerSidePropsType<typeof getServerSideProps>) {
const router = useRouter()
return (
<div className={styles.container}>
{contents}
<Link href={`/${parseInt(id || "0") + 1}`}>
<a>+1</a>
</Link>
</div>
)
}
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/1
200
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/100
200
production serverでは、Staric GenerationされたページへのLinkがviewportに入った際にpropsが先読みされる。
// GET http://localhost:3000/_next/data/EOKMebLh4ObHV3QqgePIS/2.json
{"pageProps":{"contents":"id is 2","id":"2"},"__N_SSG":true}