Open8

NxでNext.jsのMonorepo構成を試す

koshikoshi

関連した複数のNext.jsアプリを作成する必要があり、Monorepo構成がドンピシャなのではと思い始めて見る。
ちなみに筆者は業務でMonorepoをやるのは初なので、とりあえずドキュメントに沿ってやってみる。

https://nx.dev/l/r/getting-started/nx-setup

koshikoshi

最初のセットアップ

$ npx create-nx-workspace nx-test-2 --package-manager=yarn 

プロジェクト名は nx-test-2, アプリ名は next-app-01 とする。
Package Managerは Yarn, StylingはEmotionを使う。

するとこんな感じで、apps以下に Next.js アプリができる。e2eもできてる。便利。

koshikoshi

起動

yarn start

yarn startnx serve コマンドが実行できる。

koshikoshi

アプリを追加してみる

複数のNext.jsアプリを運用する想定なので、新たなappを追加する

$ npx nx g @nrwl/next:app                                                                                                                         
✔ What name would you like to use for the application? · next-app-02

next-app-02 という新しいNext.jsアプリが追加されたので、起動してみる。

$ yarn start next-app-02

無事起動できた。ちなみに、yarn start だけでは1つめの方 next-app-01 のアプリが起動した。
これは nx.jsondefaultProject によるものっぽい。

koshikoshi

Reactライブラリを追加してみる

複数のNext.jsアプリで共通で使うようなReact UIコンポーネントを、ライブラリという形で追加してみる。

$ npx nx g @nrwl/react:lib shared-ui-components --importPath=@nx-test-2/ui-components 
✔ Which stylesheet format would you like to use? · @emotion/styled

すると、./libs 以下に shared-ui-components ディレクトリが生成され、tsconfig.base.json にもpath が追加された。便利。

koshikoshi

(要検証)srcディレクトリに対応してない?

Next.js はsrc ディレクトリに対応しているのだが、Nxのapps内のNext.jsでsrcディレクトリを作ってみたら、_app.tsx を読み込まない。

@nrwl/next が悪さをしてるような気がするが、要検証。時間がなく一旦後回し。

koshikoshi

ESLint, Prettier, Stylelint を導入する

通常のNext.jsアプリでは、 NPM Scriptを通してLinter, Formatterを使用していたが、Nxだと各appにpackage.jsonが無い。そこで、project.jsontargets として登録してみた。これが最適解なのかはわからないが、今の所問題ない。「こっちのやり方の方が良いぜ!」があれば教えて下さいm(_ _)m

デフォルトの lint targetは、eslintのみの実行だと思われるので、overrideする。ついでに Format 用の fix target も作成した。

apps/app-01/project.json
{
  ...略
  "targets": {
    "lint": {
      "executor": "@nrwl/workspace:run-commands",
      "options": {
        "commands": [
          "stylelint './**/*.(tsx|ts)'",
          "prettier --check .",
          "eslint ."
        ],
        "cwd": "apps/app-01",
        "parallel": true
      }
    },
    "fix": {
      "executor": "@nrwl/workspace:run-commands",
      "options": {
        "commands": [
          "stylelint --fix './**/*.(tsx|ts)'",
          "prettier --write .",
          "eslint --fix ."
        ],
        "cwd": "apps/app-01",
        "parallel": false
      }
    }
  },
}

lintはparallelに、fixはシーケンシャルに実行するようにした。
npm-run-all でいうところの run-p, run-s を使う感覚で書ける。

これで

nx run app-01:lint

または

nx lint app-01

でLintを実行できる

koshikoshi

Nx + ngrok

Nxで作成したReactアプリケーションをlocalhostで起動する際に、ngrokをかます必要があったのでやり方をメモ。

そのままだと ngrokが生成したURLを叩いても Invalid Host Header と表示されてしまうので、修正が必要。
今回は "executor": "@nrwl/web:webpack", なので、カスタムのwebpack設定ファイルを置けばよい。

https://nx.dev/guides/customize-webpack を参考にまんま持ってきて、

apps/app-01/custom-webpack.config.js
// Helper for combining webpack config objects
const { merge } = require('webpack-merge');

module.exports = (config, context) => {
  return merge(config, {
    devServer: {
      allowedHosts: ['.ngrok.io'],
    },
  });
};

のように allowedHosts で ngrokを許可し、

apps/app-01/project.json
{
  ...略
  "targets": {
    "build": {
      "executor": "@nrwl/web:webpack",
  ...略
        "webpackConfig": "apps/app-01/custom-webpack.config.js"
      },
}

とすればよい。production deployの際は非許可にするのを忘れないこと。