Next.jsでExpressカスタムサーバーを試してみる機会があり、せっかくなので記事にしました。
tsconfig
などの具体的な説明は省略しています。
環境構築
Next プロジェクトの作成
ひとまず、Next.js × TypeScript の環境を作成します。
--ts
のオプションを付けることでTypeScript化した状態でNext.jsのプロジェクトを生成してくれます。(便利、、、!!)
npx create-next-app@latest --ts your-app-name
Expressの導入
必要なパッケージをinstall
cross-env
は環境変数設定のためにインストールします。
npm i express cross-env
npm i --save-dev @types/express
tsconfig.server.json
を作成します。
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "CommonJS",
"outDir": "dist",
"noEmit": false
},
"include": ["server"]
}
server/index.ts
を作成します。
import express, { Request, Response } from "express";
import next from "next";
const dev = process.env.NODE_ENV === "development";
const port = 4000;
const app = next({ dev });
const handle = app.getRequestHandler();
(async () => {
try {
await app.prepare();
const server = express();
server.all("*", (req: Request, res: Response) => {
return handle(req, res);
});
server.listen(port, () => {
console.log(`${port}で起動中`);
});
} catch (e) {
console.error(e);
}
})();
cross-envを使用して、環境変数を設定しdevモードかどうかの判定を行います。
app.prepare()
で別サーバーでNext.jsを使うための初期化を行います。
app.getRequestHandler()
はハンドラを作成し、expressのserverでリクエストとレスポンスをラップすることで、Nextjs内でURLをルーティングすることが可能になり、通常どおりURLで /pages
にアクセスすることができます。
続いて、packege.json
を編集
{
"scripts": {
"dev": "tsc -p tsconfig.server.json && cross-env NODE_ENV=development node ./dist/index.js",
"build": "tsc -p tsconfig.server.json",
},
}
あとは npm run dev
or npm run build
を行い、実行するだけです。
以上の通り、Next.jsはexpressのルーティングをラップしているだけで簡単にカスタムサーバーを構築することができます。
また、expressのエコシステムも問題なく使うことができます。以下のようにserverにミドルウェアを登録してあげることで、/test
以下はexpressで作成したAPIを使用することができます。
import express, { Request, Response } from "express";
export const router = express.Router();
router.get("/", (req: Request, res: Response, next) => {
res.status(200).json(`GET`);
});
router.post("/", (req: Request, res: Response, next) => {
res.status(200).json(`POST`);
});
const server = express();
server.use("/test", router);
server.all("*", (req: Request, res: Response) => {
return handle(req, res);
});
画面はpages、内部APIはExpressのカスタムサーバーのapiと役割を分けたい時などに良いと思います。
おまけ: ホットリロードできるようにnodemonで動かす
nodemon とはNode.jsベースのappのソースコードの変更を監視して、自動でサーバーを再起動してくれるツールです。
特に解説を行いませんが、以下の設定することでソースコードを変更するたびに再起動することがなくなるので、開発効率が上がり非常に便利です。
npm i --save-dev nodemon
nodemon.json
を作成します。
{
"watch": ["./server"],
"ext": "ts",
"exec": "ts-node ./server/index.ts"
}
tsconfig.json
と package.json
を編集します。
{
"compilerOptions": {
// 同じ環境で動くようにCommonJSに変更しておく
"module": "CommonJS",
}
}
{
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon",
},
}
環境変数でconst app = next({ dev })
にdev環境かどうかを教えてあげないとホットリロードされないので注意です。
参考資料
・ https://nextjs-ja-translation-docs.vercel.app/docs/advanced-features/custom-server
・https://gonta616.hatenablog.com/entry/2020/05/17/232007
・https://www.forcia.com/blog/001559.html