Web Frontend を Next.js + TypeScript で書いて Docker でビルドする

「手っ取り早く Web インターフェースを手に入れる方法 2020」シリーズ(?)のBFF サンプルプロジェクト と同じように Web Frontend サンプルプロジェクトを作ってみました。

今回もプロジェクト構成やビルド方法の検証が主目的です。
そのためアプリケーション自体は Docker イメージを実行するとNext.jsの Web サーバーが起動しこんなページが表示されるだけのシンプルな機能しかありません。

❯ docker run -it --rm -p 3000:3000 b2ee27d0d01d

> @ start /app
> next start

> Ready on http://localhost:3000

コードは"mazgi-showcase/202001.nextjs-typescript-jest“にあります。

使っている技術スタックは概ね以下です。

Out of Scope

今回のサンプルでは以下を扱いません。

  • Web API / BFF
  • Business or domain logic
  • Deploy

How to run

BFF と同じように次の 3 ステップで起動できるはずです。

  1. cargo-makeリリースページからダウンロードして bin/cargo-make に配置
  2. (optional) bin/cargo-make make --makefile tasks/setup-project.toml を実行して空の設定ファイルを生成
    • Linux 上で実行する場合にこの手順が必要です
  3. docker-compose up

docker-compose up すると次の 2 つの Docker コンテナが起動します。

  • Visual Studio Code用の Docker コンテナ
    • 起動してすぐ終了しますが意図した動作です
  • Web Frontend の Docker コンテナ
❯ docker-compose up
Creating network "202001nextjs-typescript-jest_default" with the default driver
Creating 202001nextjs-typescript-jest_vscode_1   ... done
Creating 202001nextjs-typescript-jest_frontend_1 ... done
Attaching to 202001nextjs-typescript-jest_vscode_1, 202001nextjs-typescript-jest_frontend_1
vscode_1    | npm WARN workspace No repository field.
vscode_1    | npm WARN workspace No license field.
vscode_1    |
vscode_1    | audited 475 packages in 1.653s
vscode_1    | found 0 vulnerabilities
vscode_1    |
202001nextjs-typescript-jest_vscode_1 exited with code 0
frontend_1  | npm WARN workspace No description
frontend_1  | npm WARN workspace No repository field.
frontend_1  | npm WARN workspace No license field.
frontend_1  | npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.2 (node_modules/fsevents):
frontend_1  | npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
frontend_1  | npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.11 (node_modules/webpack/node_modules/fsevents):
frontend_1  | npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.11: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
frontend_1  | npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.11 (node_modules/jest-haste-map/node_modules/fsevents):
frontend_1  | npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.11: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
frontend_1  |
frontend_1  | audited 891402 packages in 5.599s
frontend_1  | found 0 vulnerabilities
frontend_1  |
frontend_1  |
frontend_1  | > @ dev /workspace
frontend_1  | > next
frontend_1  |
frontend_1  | [ wait ]  starting the development server ...
frontend_1  | [ info ]  waiting on http://localhost:3000 ...
frontend_1  | [ info ]  bundled successfully, waiting for typecheck results...
frontend_1  | [ ready ] compiled successfully - ready on http://localhost:3000

接続すると記事冒頭のスクリーンショットのようなページが返ります。

❯ curl -LI 127.0.0.1:3000
HTTP/1.1 200 OK
Cache-Control: no-store, must-revalidate
X-Powered-By: Next.js
ETag: "6b2-ISeH+ybP2WwZ4qoLiEZ3PPggx20"
Content-Type: text/html; charset=utf-8
Content-Length: 1714
Vary: Accept-Encoding
Date: Wed, 22 Jan 2020 13:10:11 GMT
Connection: keep-alive

また Web Frontend といいつつサーバーが立っているので存在しない path に接続するとちゃんと 404 が返ります。

❯ curl -LI 127.0.0.1:3000/not-found
HTTP/1.1 404 Not Found
Cache-Control: no-store, must-revalidate
X-Powered-By: Next.js
ETag: "88b-4CxhQ5CjqmJABvp/LLA2dxUDW5A"
Content-Type: text/html; charset=utf-8
Content-Length: 2187
Vary: Accept-Encoding
Date: Wed, 22 Jan 2020 13:10:17 GMT
Connection: keep-alive

How to resolve module paths

Web Frontend 開発ではだいたい次のようなステップを手動/自動問わず繰り返して開発を進めることになると思います。

  • npm run dev
  • npm run test
  • npm run build

そしてこれらのステップを繰り返す中で使われるツールも tsc, webpack, babel やそれらのプラグイン等多岐にわたります。

そんな中で module の解決に頭を抱えることが多々 Module not found: Can't resolve 'components/xxx' in '/workspace/src/pages'

本サンプルでは試行錯誤の結果、どうにか path 定義の重複を減らすことができた気がします。
ポイントは以下 2 つのようです。

だいぶ時間を溶かしたのですが解決してみればたった 2 点ですね、そんなもんです。

Build and just before Deploy

BFF とあまり変わらないのですが、Next.js のDeployment > Self hostingに「.next, node_modules, package.json をサーバーに置くべし」と書かれているのでDockerfileの中でそのようにしています。

That’s all

どうにか Web API に加えて Web Frontend の 2020 年らしいたたき台を作れたので今後の開発に活かそうと思います。