$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

Next.jsのドキュメントを全部読んでみた

最近Next.jsのドキュメントが更新されて、APIリファレンスが付くなど読みやすくなったので、この機会に全部読んでみた。メモを置いておく。


https://nextjs.org/docs/routing/introduction#dynamic-route-segments

pages/post/[…all] → /post/* (/post/2020/id/title) こんなことできるのか!ただ全部吸い込まれるのは使いづらそう


https://nextjs.org/docs/routing/shallow-routing

router.pushにshallowオプションを加えると、getInitialPropsを実行しないレンダリングができる。ページ内でクエリやハッシュフラグメントを変えるなどで便利に使えそう

import { useEffect } from 'react'
import { useRouter } from 'next/router'

// Current URL is '/'
function Page() {
  const router = useRouter()

  useEffect(() => {
    // Always do navigations after the first render
    router.push('/?counter=10', null, { shallow: true })
  }, [])

  useEffect(() => {
    // The counter changed!
  }, [router.query.counter])
}

export default Page

https://nextjs.org/docs/api-routes/introduction

api routesはヘルスチェックエンドポイントとか作るのに便利そう


https://nextjs.org/docs/api-routes/api-middlewares

api限定の設定を入れられる

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
}

micro middleware を使えばハンドラを拡張できる

import Cors from 'micro-cors'

const cors = Cors({
  allowMethods: ['GET', 'HEAD'],
})

function handler(req, res) {
  res.json({ message: 'Hello Everyone!' })
}

export default cors(handler)

https://nextjs.org/docs/api-routes/response-helpers

Next.jsのresにはres.jsonなど便利メソッドが生えている


https://nextjs.org/docs/deployment

サーバサイドのデプロイは、.next、node_modules、package.jsonを配置したら良い

Generally you'll have to follow these steps to deploy to production:
        Run npm install
        Run npm run build (runs next build)
        Potentially copy the .next, node_modules, and package.json to your server.
        Run npm run start (runs next start) on the server

https://nextjs.org/docs/advanced-features/dynamic-import

dynamic importを、使って一部だけssrしないようにできる

import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(
  () => import('../components/hello3'),
  { ssr: false }
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithNoSSR />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

https://nextjs.org/docs/advanced-features/custom-document

  • documentをいじればheadとかを置き換えられる
    • favicon変えたり、apple-touch-icon入れたりと色々できそう
  • DocumentのgetInitialPropsは、SSR時にしか使われない模様

https://nextjs.org/docs/api-reference/next/head

head内のタグは、key propを付けることで、同じkeyなら上書きという挙動ができる。タグが複数付くことを防げる。


https://nextjs.org/docs/api-reference/data-fetching/getInitialProps getinitialpropsに渡ってくるもの

  • pathname - Current route. That is the path of the page in /pages
  • query - Query string section of URL parsed as an object
  • asPath - String of the actual path (including the query) shown in the browser
  • req - HTTP request object (server only)
  • res - HTTP response object (server only)
  • err - Error object if any error is encountered during the rendering

https://arunoda.me/blog/ssr-and-server-only-modules webpack analyzerを使って、bundle sizeを検証することができる


https://nextjs.org/docs/api-reference/next.config.js/introduction 設定できるリストへの参照がここに載ってる


https://nextjs.org/docs/api-reference/next.config.js/environment-variables env設定で環境変数を設定できる

module.exports = {
  env: {
    customKey: 'my-value',
  },
}

https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config next.config.jsのwebpackの設定に渡ってくる引数

The second argument to the webpack function is an object with the following properties:
        buildId: String - The build id, used as a unique identifier between builds
        dev: Boolean - Indicates if the compilation will be done in development
        isServer: Boolean - It's true for server-side compilation, and false for client-side compilation
        defaultLoaders: Object - Default loaders used internally by Next.js:
        babel: Object - Default babel-loader configuration

https://nextjs.org/docs/api-reference/next.config.js/configuring-the-build-id build idを生成する関数を定義できる。gitのrevisionにするとかできそう

最近連載開始して3巻程度で好きな作品たち

社内の朝会のスピーチで発表したのを公開しておく。

漫画の連載追いかけるの好きです。最近連載が始まって単行本3巻程度のもので、好きな作品を紹介します。

大ダーク・1巻

  • ダークファンタジーの設定が良いし絵が最高
  • ドロヘドロの作者の新連載
  • ドロヘドロも2巻から爆発的に面白くなった漫画だけど、大ダークもそのような雰囲気を感じて楽しみにしてる

夏目アラタの結婚・1巻

  • 殺人鬼と面会室ごしに恋愛していく(????)話。サスペンスっぽい。ハラハラします
  • 医龍の作者の新連載

スキップとローファー・2巻

  • ほわほわしてて癒やされる。主人公がいい子。
  • 疲れているときに見て良かった

アンサングシンデレラ・3巻

  • 僕にとってあまり職種として馴染みのない薬剤師のことがわかって面白い

水は海に向かって流れる・2巻

  • シェアハウスに住んだら、親の元不倫相手の子供がいたという話
  • 子供はわかってあげない」の作者の新連載で、同様にボーイ・ミーツ・ガール的?

おとなになっても・1巻

猫が西向きゃ・1巻

  • ”フロー”と呼ばれる奇妙な自然現象(三叉路が七叉路に増殖してるとか)が存在して、それを処理するフロー業者がいるって話
  • 蟲師の人の新連載

まとめ

面白い漫画なかなか見つけられないので、おすすめあったら教えてください!

Next.jsでNot FoundページやISEページをカスタマイズする

https://nextjs.org/docs/advanced-features/custom-error-page を見て設定したが、特にstatusCode周りでハマったのでメモ。

  • pages/_error.tsxを作ると、SSR(Server Side Rendering)時やCSR(Client Side Rendering)時に例外が起きるなどした時やルーティングが存在しないエラーが発生した時に、そのページを表示してくれる
  • このページで400エラー、404エラー、500エラーをハンドリングして、自前のページを作成すれば良い
  • pages/_error.tsxはproduction環境時(next build -> next startした時)にしか使われないので注意。デバッグするときはnext buildをする必要がある
  • statusCode算出周りはハマりどころなので、自前でやったほうが良い場合がある
    • next/errorのgetInitialPropsではCSR時に例外が起きた時、err.statusCodeに何も入っていないという問題がある
    • 参考
  • next/errorによるとstatusCodeには400、404、405、500が入ってくるようなので、エラーページではそれらに対応すれば良い

pages/_error.tsxのサンプル

import React from 'react';
import { NextPage, NextPageContext } from 'next';

// production時(next buildの成果物を使っている時)のエラー表示に使われる
// See Also: https://nextjs.org/docs/advanced-features/custom-error-page

interface Props {
  statusCode: number;
}
const Error: NextPage<Props> = ({ statusCode }) => {
  // ここでエラーページをちゃんと構築する。statusCodeが400の時BadRequest、
  // 404/405の時Not Found、500の問Internal Server Errorが出るように正しく処理すれば良いだろう
  return <div>{statusCode}エラーが発生しました</div>;
};

Error.getInitialProps = async ({ res, err }: NextPageContext) => {
  // statusCodeを算出する。
  // - resが存在する時はSSRであり、res.statusCodeをそのまま利用すれば良い。
  // - resがない場合はCSRである。
  //   - err.statusCodeがあればそれをそのまま利用する
  //   - 意図しない例外が起きてerrがここに渡ってくる場合、単なるErrorオブジェクトが入っていてstatusCodeプロパティがない。errがある時点でISEなので500にする
  // See Also: https://nextjs.org/docs/advanced-features/custom-error-page
  const statusCode = res ? res.statusCode : err ? err.statusCode ?? 500 : 404;

  return { statusCode };
};

export default Error;