🧊

AstroでPDFファイルからルートを生成したい

イメージとしては、MDやMDXと同様に、PDFも置いたらそのままURLになってほしいというもの。

そんな機能はない

はず。

少なくとも、MDやMDXのような一級のサポートはない。

なので、

  • /publicにPDFファイルを置く
  • getStaticPaths()でそのファイルを探す
  • 個別ルートでは、単にリダイレクトするか、fetch()して横流しする

ということになりがち。

だが、/publicはカオスになりがちなので、あまりやりたくない。

ワークアラウンド

問題は、元ソースとして扱うPDFをいかにしてビルド後のアウトプットに持っていくか。dist/_astroにいかにして持っていくか。

というわけで、[id].pdf.tsというファイル名で、エンドポイントを立てて、自力でビルドする。

import { readdir, readFile } from "node:fs/promises";
import type { APIRoute } from "astro";

const PDF_DIR = "./path/to/pdf";

export async function getStaticPaths() {
  const events = await readdir(PDF_DIR);
  return events.map((id) => ({
    params: { id },
    props: {},
  }));
}

// ---

export const GET: APIRoute = async ({ params: { id } }) => {
  const pdfPath = `${PDF_DIR}/${id}`;

  let pdfBuf;
  try {
    pdfBuf = await readFile(pdfPath);
  } catch (cause) {
    throw new Error(`Failed to read ${pdfPath}`, { cause });
  }

  return new Response(pdfBuf, {
    headers: {
      "Content-Type": "application/pdf",
      "Content-Disposition": `inline; filename="${id}"`,
      "Content-Length": pdfBuf.length.toString(),
    },
  });
};

ビルド時にPDFを読んで、それをそのまま吐き出してるので、やや処理としては無駄があるけど、やりたいことはできた。