LoginSignup
17
7

More than 1 year has passed since last update.

Next.js×TypeScript をカスタムサーバー(Express)で起動する

Last updated at Posted at 2022-01-20

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 を作成します。

tsconfig.server.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "CommonJS",
    "outDir": "dist",
    "noEmit": false
  },
  "include": ["server"]
}

server/index.ts を作成します。

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 を編集

package.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を使用することができます。

router.ts
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`);
});

index.ts
    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 を作成します。

nodemon.json
{
  "watch": ["./server"],
  "ext": "ts",
  "exec": "ts-node ./server/index.ts"
}

tsconfig.jsonpackage.json を編集します。

tsconfig.json
{
  "compilerOptions": {
  // 同じ環境で動くようにCommonJSに変更しておく
    "module": "CommonJS",
  }
}

package.json
{
  "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

17
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
7