NxでNextjsのアプリをセットアップ・構築する

この記事は、Next.js Advent Calendar 2020です。

最近ReactアプリをセットアップするときにNxをちょいちょい使うので、Nextjs使った版をまとめてみました。

Nxを使うメリット

1: nx gを使ったコンポーネント生成

AngularやNestjsなどではよく見かける「generate」コマンドが実はReactアプリ系ではあまり存在しません。

知っている限りでは、NxだけがReact ComponentやRedux Sliceを生成するコマンドをサポートしていました。

これがあると、新規にファイルを追加する時のタスク量がかなり削減できますので、正直これのためだけにNxをつかっている時もあります。

2: Nestjsなどで別途実装したAPIと型データを共有できる

NextjsであればAPIも実装できますが、それ以外の場合はAPIを別途実装する必要があります。

そんなときにNxでどちらも管理していれば、どちらのアプリでも使う型定義ファイルを用意することでAPIとUIどちらでも同じ型を参照した実装が可能になります。

3: フルリニューアル(式年遷宮)が比較的容易

フルリニューアルする際、別ブランチでコードを置き換えるのではなく「全く新しいアプリ」をNxで追加してしまうという方法がとれます。

nx generate @nrwl/next:application new-dashboardのように新しくアプリをセットアップし、libs側に実装している処理やコンポーネントを再利用しながらアプリの実装を行います。

そして最後にNetlifyやAWS Amplify consoleなどでデプロイするディレクトリを新しい方に切り替えることで、リニューアルが完了します。

この方法であれば、現行アプリとリニューアル版アプリ両方の保守・開発を並行して行うことができます。

もちろんリポジトリの容量が倍増しますし、現行アプリの振る舞いが変わるような変更については慎重に行う必要があるという点はありますが、別ブランチ・別リポジトリで書き直すよりも差分などが発生しにくいかと思います。

Nxを使うデメリット

1: Nx -> Next.js -> Reactの3層構造による保守の煩雑化

NextjsはReactでアプリケーションを作るためのフレームワークです。そしてそのNextjsをモノレポで動かすためのフレームワークがNxです。つまりReactを2つのフレームワークでラップしている状態です。

Nxでの管理方法やコマンドを覚えつつ、Nextjsの作法に従ってアプリを作り、Reactのメジャーアップデートに適宜対応する形になりますので、正直管理対象は増えます。

webpack.config.jsをカスタムしたり、メジャーリリース前の機能を試したいとなると入り組んだ場所にある地雷を踏むケースがありえますので、できるだけ素直に使うケースに絞った方が安全かなと思います。

2:複数アプリのホストによるCIやCDの長時間化または複雑化

単純に複数のアプリを1リポジトリで管理することになることがデメリットです。

affectedコマンドを使うことで、差分ベースでコマンドを実行することができますが、それでもリポジトリ容量は大きくなりますし、複数アプリ分のnode_modulesをインストールすることによる遅延などもありえます。

3:機能を持て余しがち

Nxコマンドでさまざまなファイルをビルドしたり、差分ベースのテストやリントを実行できます。が、コマンドをそれぞれ覚える必要がありますので、慣れるまでは使わないコマンドなどが結構出てきます。

「行ってこい」でリリースする系などで手早く終わらせたい場合には、オーバースペックすぎるかもしれません。

NxでNextjsアプリをセットアップ

ワークスペースの作成

まずはワークスペースを作ります。対話式で設定できますので、回答していきましょう。

「What to create in the new workspace」でNextjsを選択するだけでOKです。

$ npx create-nx-workspace@latest
? Workspace name (e.g., org name)     nx-nextjs-example
 ? What to create in the new workspace next.js           [a workspace with a single Next.js application]
 ? Application name                    hello-next-js
 ? Default stylesheet format           CSS
 ? Use Nx Cloud? (It's free and doesn't require registration.) No

Nx with Nextjsのディレクトリ構造

apps/[app-name]配下にあること以外は普通のNextjsアプリケーションがセットアップされていることが伺えます。

% tree -L 4 -I node_modules 
 .
 ├── README.md
 ├── apps
 │   ├── hello-next-js
 │   │   ├── babel-jest.config.json
 │   │   ├── index.d.ts
 │   │   ├── jest.config.js
 │   │   ├── next-env.d.ts
 │   │   ├── next.config.js
 │   │   ├── pages
 │   │   │   ├── _app.tsx
 │   │   │   ├── index.module.css
 │   │   │   ├── index.tsx
 │   │   │   └── styles.css
 │   │   ├── public
 │   │   │   ├── nx-logo-white.svg
 │   │   │   └── star.svg
 │   │   ├── specs
 │   │   │   └── index.spec.tsx
 │   │   ├── tsconfig.app.json
 │   │   ├── tsconfig.json
 │   │   └── tsconfig.spec.json
 │   └── hello-next-js-e2e
 │       ├── cypress.json
 │       ├── src
 │       │   ├── fixtures
 │       │   ├── integration
 │       │   ├── plugins
 │       │   └── support
 │       ├── tsconfig.e2e.json
 │       └── tsconfig.json
 ├── babel.config.json
 ├── jest.config.js
 ├── jest.preset.js
 ├── libs
 ├── nx.json
 ├── package-lock.json
 ├── package.json
 ├── tools
 │   ├── generators
 │   └── tsconfig.tools.json
 ├── tsconfig.base.json
 └── workspace.json

コンポーネントライブラリを追加する

このままNextjsのディレクトリにアプリを実装しても良いのですが、せっかくなのでUIライブラリを追加しましょう。

# Generate UI lib
$ yarn nx g @nrwl/react:lib ui

# Add a component
$ yarn nx g @nrwl/react:component xyz --project ui

これでReactのComponentを管理するディレクトリ群が作成されます。

% tree libs -L 4
 libs
 └── ui
     ├── README.md
     ├── babel-jest.config.json
     ├── jest.config.js
     ├── src
     │   ├── index.ts
     │   └── lib
     │       ├── ui.module.css
     │       ├── ui.spec.tsx
     │       ├── ui.tsx
     │       └── xyz
     ├── tsconfig.json
     ├── tsconfig.lib.json
     └── tsconfig.spec.json
 4 directories, 10 files

あとはこれを@[workspace-name]/[library-name]でimportしてやればOKです。

import React from 'react';
import {Ui, Xyz} from '@nx-nextjs-example/ui'
import styles from './index.module.css';

export function Index() {
  return (
    <div className={styles.page}>
      <Ui />
      <Xyz />

テストコードやCSSファイルも一緒に追加してくれることや、index.tsでexportまで自動で行ってくれることなど、nx gコマンドでコンポーネントを追加するメリットは個人的にかなり大きいかなと思います。

おわりに

たぶんまだ地雷を踏み抜いてないだけな気はしますが、Reactアプリをモノレポで管理したい場合にはLernaで頑張るよりNxを使う方が便利です。

2021年のアドベントカレンダーあたりで運用してみての話などが書けたらなとは思います。

Comment