前回 sitemap.xml
を作成しましたが、Vercel
(旧 Zeit / now
)でうまく動かなかったので原因と解決方法を追記しておきます。
自サーバーで動かす分には問題ないです。
Vercelの場合の問題と解決
サイトマップ読み込まないなと思ってたらアクセスできなくなってました。
前回作ったのは getServerSideProps
を使ったサーバー関数です。
ビルドファイルも lambda
になっています。
サーバーに置いて next start
する分には問題ないんですが、vercel
に置く場合には上手く動かないようです。まぁ考えてみたら fs
で好き勝手されるのは不味い。
というわけで静的ファイルに書き出して public/
に置くことにします。
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 51 52 53 54 55 56 |
import fs from "fs"; const origin = "https://narumium.net"; const dist = "public/sitemap.xml"; type post = { date: number; path: string; }; const path2post = (dir: string, name: string): post => { const stat = fs.statSync(`${dir}/${name}`); const path = (name == "index.tsx" ? dir : `${dir}/${name}`.replace(".tsx", "") ).replace("src/pages", ""); return { date: stat.mtimeMs, path }; }; const getPosts = (dir: string): post[] => fs .readdirSync(dir, { withFileTypes: true }) .flatMap((d) => d.isFile() ? !d.name.startsWith("_") && d.name.endsWith(".tsx") ? [path2post(dir, d.name)] : [] : getPosts(`${dir}/${d.name}`) ); const generateSitemap = (posts: post[], origin: string): string => { let xml: string = ""; posts.map((post) => { const date: string = new Date(post.date).toISOString().split("T")[0]; xml += `<url> <loc>${origin + post.path}</loc> <lastmod>${date}</lastmod> </url>`; }); return `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> ${xml} </urlset>`; }; const writeXml = () => { const posts = getPosts("src/pages"); // src/ を使っていない場合は pages const sitemap: string = generateSitemap(posts, origin); fs.writeFileSync(dist, sitemap, "utf8"); console.log("Write", dist); }; writeXml(); |
1 2 3 4 |
"scripts": { ... "batch:sitemap": "npx ts-node --project ./tsconfig2.json src/batch/sitemap.ts" }, |
ts-node
で単体スクリプトを実行しています。
tsconfig
が next.js
と同じものだと動かなかったので、"module": "commonjs"
に変更したものを --project
で指定。
サーバー関数ではなくなったので自動で最新になりませんが、そもそも静的ファイルでも特に問題はないです。
Vercel
側でなくクライアント側で実行する必要があるので、プッシュ前に実行して最新化するようにコマンドを作っておけば楽だと思います。