【モノレポ入門】Next.js + TypeScript + Nx で環境構築をする
はじめに
この記事で書くこと
今回は、Next.js + TypeScript + Nx を使用して環境構築をする方法を書きます。
経緯としては、あるプロジェクトを作るにあたり、
- 汎用的な部分を使いまわせるようにしたい
- 以前作ったような物を再度作る際に、スピード感を持って開発できるようにしたい
といった意図から、フロントエンドの開発にモノレポを採用することになった為、
今回環境構築をして、学んだことをまとめようと思います。
モノレポとは
メリット
-
コードを共有できる
プロジェクトを跨いでコードを共有できる為、コンポーネントやTypeScriptの型を共有して効率化できる。 -
ツールの標準化がしやすい
tsconfigやeslintなどはルートディレクトリにあるbaseファイルを継承した形で作られるため、
プロジェクト毎の差異が出ずに標準化がしやすい
デメリット
- 個人的に未知の領域だったので、学習コストがかかりそう
Nxとは
Nx は、ファーストクラスの monorepo サポートと強力な統合を備えた、スマートで高速かつ拡張可能なビルド システムです。
引用元 https://nx.dev/getting-started/intro
メリット
-
開発環境のセットアップが容易
今回はNext.jsで環境を作成したのですが、コマンド一つで Next.js、TypeScript、ESLint、Prettier、SCSS、Jest、Cypress、などのツールが入ったプロジェクトが作成ができ、とても便利でした。
環境構築
まずはじめに、 下記のNxの公式ドキュメントのSetting up Next.jsという欄を進めていきます。
下記コマンドで、モノレポ環境のワークスペースと1つ目のアプリケーションの作成が開始します。
$ npx create-nx-workspace@latest --preset=next
ワークスペース名(リポジトリ名)を入力
> NX Let's create a new workspace [https://nx.dev/getting-started/intro]
? Repository name › sample
1つ目に作成する、アプリケーション名を入力
> NX Let's create a new workspace [https://nx.dev/getting-started/intro]
✔ Repository name · sample
? Application name › admin ›
使用するCSSを選択
> NX Let's create a new workspace [https://nx.dev/getting-started/intro]
✔ Repository name · sample
✔ Application name · admin
? Default stylesheet format …
CSS
SASS(.scss) [ http://sass-lang.com ]
LESS [ http://lesscss.org ]
Stylus(.styl) [ http://stylus-lang.com ]
styled-components [ https://styled-components.com ]
emotion [ https://emotion.sh ]
styled-jsx [ https://www.npmjs.com/package/styled-jsx ] ›
分散キャッシングを有効にしてCIを高速化するか?
※詳しくはこちら
? Enable distributed caching to make your CI faster …
Yes I want faster builds
No
作成完了
✔ Installing dependencies with npm
✔ Nx has successfully created the workspace: sample.
✔ NxCloud has been set up successfully
> NX Successfully initialized git.
上記のコマンドで作成されたリポジトリ構成が下記のようになります。
sample
└ apps - 各プロジェクトのアプリケーション
└ libs - ライブラリ(共通の処理やコンポーネント、UIなど)
└ tools - コードベースで動作するスクリプト
- workspace.json - ワークスペースの設定
- nx.json - プロジェクトの追加情報
- tsconfig.base.json - 共通のTypeScriptの設定
下記の用にadminという名前で1つ目のアプリケーションが作成され、
自動でe2eテスト用のリポジトリも作成されました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475069/e94e34a5-f0e0-575b-2c4e-b5cb54fd2de8.png" width=50%>
ワークスペースにアプリケーションを追加する
下記コマンドで、ワークスペース内にアプリケーションを追加します。
$ npx nx g @nrwl/next:app アプリ名
例) npx nx g @nrwl/next:app liff
例のコマンドをワークスペース内で実行すると、
下記の用にliffという名前でNext.jsで構築されたアプリケーションが追加されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475069/8e4814a2-c76a-5b9c-33d4-421c9a5e87d7.png" width=50%>
ライブラリの作成
アプリケーション間での、共通の処理やコンポーネントを格納するリポジトリを作成できます。
$ npx nx g @nrwl/next:lib my-new-lib
ページやコンポーネントの作成
ページの追加
adminリポジトリにログインページを追加してみます。
$ npx nx g @nrwl/next:page ページ名 --project=追加するアプリケーション名
例) npx nx g @nrwl/next:page login --project=admin
コンポーネントの作成
adminリポジトリにlogin-formを追加してみます。
$ npx nx g @nrwl/next:component コンポーネント名 --project=追加するアプリケーション名
例) npx nx g @nrwl/next:component login-form --project=admin
adminリポジトリに上記コマンドのみで、
テスト用のspacファイルを含む、loginページとlogin-formのコンポーネントの追加ができました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475069/b39a2311-1e11-2eea-e21f-6fc72cd2d47a.png" width=50%>
コンポーネントとページの作成に関しては、
コマンド一つで、関連するscssファイルから、テスト用のspecファイルまで作成され、
自動でルーティングも組まれるため、大変便利だと感じました。
開発サーバーを立ち上げる
下記のコマンドを実行して開発サーバー立ち上げを実行
$ npx nx serve 立ち上げるアプリケーション名
例) npx nx serve admin
ローカルサーバが立ち上がり、下記のような初期ページが表示されました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475069/ab517fc4-515a-417e-adbd-b3c5f1b4a5ee.png" width=100%>
試しに/loginにアクセスしてみると、
やはり自動でルーティングが設定されており、コマンドで作成したログインページを開くことができました。
汎用ライブラリを両方のアプリケーションから呼び出してみる
試しにcommon-headerという汎用ライブラリを作成し(ライブラリの作成)、
adminリポジトリと、liffリポジトリからコンポーネントを呼び出してみます。
下記のコマンドを実行して汎用ライブラリを作成
$ nx g @nrwl/next:lib common-header
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475069/a2fa0eb5-f5b2-97ae-1775-698f3c5747b4.png" width=50%>
ライブラリの作成コマンドで作成したライブラリの中身
import styles from './common-header.module.scss';
export interface CommonHeaderProps {}
export function CommonHeader(props: CommonHeaderProps) {
return (
<div className={styles['container']}>
<h1>ここは汎用ヘッダーです!</h1>
</div>
);
}
export default CommonHeader;
adminのログインページ
import styles from './index.module.scss';
/* import { CommonHeader } from '@<作成したworkspace名>/common-header';*/
import { CommonHeader } from '@sample/common-header';
export interface LoginProps {}
export function Login(props: LoginProps) {
return (
<div className={styles['container']}>
<CommonHeader></CommonHeader>
<h1>Welcome to Login!</h1>
</div>
);
}
export default Login;
liffリポジトリのliff-mypage
import styles from './index.module.scss';
import { CommonHeader } from '@sample/common-header';
/* eslint-disable-next-line */
export interface LiffMypageProps {}
export function LiffMypage(props: LiffMypageProps) {
return (
<div className={styles['container']}>
<CommonHeader></CommonHeader>
<h1>Welcome to LiffMypage!</h1>
</div>
);
}
export default LiffMypage;
両方のアプリケーションから汎用コンポーネントを呼び出す事ができました!
まとめ
使いこなせば便利な機能がたくさんありそうなので、
公式ドキュメントにある下記のようなチュートリアルを進めてみて、
使いこなせるようにいろいろ触ってみようと思います。
引用
その他のドキュメント
Next.js と Nx の詳細を学ぶのに役立つその他のリソースを次に示します。
ブログ投稿: Juri Strumpflohner によるNext.js と Nx シリーズを使用したブログの構築
ビデオチュートリアル: Typescript NX Monorepo with NextJS and Express by Jack Herrington
Visual Studio CodeにNxに関するプラグインもあるみたい
少し詰まったポイント
初めてnxコマンドを叩こうとして下記のエラーに遭遇
nx: command not found error
下記記事のnpxを付ける方法で解決
Discussion