Next.js API Route: ファイルをサーブする

Next.js API Route: ファイルをサーブする

環境:

  • next: v10.0.1

参考:

getStaticProps

通常、静的ファイルをNext.js上で読み込みたい場合、getStaticPropsを使う。これはサーバーサイドで呼び出されるので、fsなどが使える。

// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries. See the "Technical details" section.
export async function getStaticProps() {
  const postsDirectory = path.join(process.cwd(), 'posts')
  const filenames = fs.readdirSync(postsDirectory)

  const posts = filenames.map((filename) => {
    const filePath = path.join(postsDirectory, filename)
    const fileContents = fs.readFileSync(filePath, 'utf8')

    // Generally you would parse/transform the contents
    // For example you can transform markdown to HTML here

    return {
      filename,
      content: fileContents,
    }
  })
  // By returning { props: posts }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}

ただしgetInitialPropsとコンフリクトするため、このメソッドと同時に使用したい場合は、API Routeからファイルをサーブする方法を模索することになる。

API Routeからファイルをサーブする

相対パスpath.resolveを使えば、ローカルでもVercel上でも動作する。

import { NextApiRequest, NextApiResponse } from "next";
import fs from "fs";
import path from "path";

export default (req: NextApiRequest, res: NextApiResponse): void => {
  res.statusCode = 200;

  const postsDirectory = path.resolve('./public', 'posts')
  const filenames = fs.readdirSync(postsDirectory)

  const posts = filenames.map((filename) => {
    const filePath = path.resolve(postsDirectory, filename)
    const fileContents = fs.readFileSync(filePath, 'utf8')

    return {
      filename,
      content: fileContents,
    }
  })

  res.json({ posts });
};

最初Issueを探っててこれを見つけたがVercel上では動かなかった。バージョンが古くて本番環境のパスが変わったりしたんだろうか