見出し画像

Turborepo で Next.js と Chakra UI、TailwindCSS を組み合わせたモノレポアプリをセットアップ

この記事では、Turborepo を使用してモノレポ構成の React アプリを構築します。アプリに Next.js プロジェクトを追加して、Chakra UI と TailwindCSS を導入します。さらに、TeypeScript、ESLint、Husky pre-commits の設定も行います。

概要:

  1. TurborepoモノレポにNext.jsアプリケーションをセットアップする。

  2. TailwindCSSをセットアップする。

  3. 共有のTypeScript設定、ESLint設定、Husky pre-commits、共有UIライブラリをセットアップする。

  4. プロジェクトにChakra UIとTailwindCSSを統合する。

Turborepo

プロジェクトを前進させるモノレポ。Turborepoは、JavaScriptおよびTypeScriptコードベース向けの高性能ビルドシステムです

turborepo.org

Turborepoは、JavaScript/TypeScriptのモノレポ向けの非常に高速なビルドシステムです。モノレポとは、複数のプロジェクトを含み、しばしば複数のフレームワークを使用する、単一の統合されたコードリポジトリのことを指します。
なぜTurborepoを使用するのか?

  • コンテンツ認識ハッシュによる高速な増分ビルド:Turborepoはキャッシュハッシュが変更されていない場合、キャッシュからアプリをビルドします。これにより、何をビルドする必要があるかを判断し、アプリケーションのビルドを高速化します。

  • ランタイムオーバーヘッドなし:Turborepoは、ランタイムコードに干渉したり、ソースマップに触れたりしません。必要な作業のみを行います。

  • 並列実行:すべてのコアを最大限の並列性で使用してビルドを実行し、アイドル状態のCPUを無駄にしません。

  • Turborepoを使用するその他の理由は、こちらのドキュメントに記載されています。

では、以下のコマンドでTurborepoモノレポを作成しましょう:

npx create-turbo@latest

このコマンドは、まずTurborepoを作成する場所を尋ね、次に使用したいパッケージマネージャーを尋ねます。(私はyarnを選択しましたが、npmやpnpmを選択することもできます。個人の好みによります。)

セットアップが完了したら、ディレクトリにcdで移動し、お好みのIDEでプロジェクトを開きます。
Turborepoによって作成されたフォルダ構造とプロジェクトについて説明しましょう。

  • apps:アプリケーションが格納されます。デフォルトでは、docsとwebという2つのNext.jsアプリケーションが作成されます。私たちは独自のNext.jsアプリケーションをTailwindCSSのセットアップと共に作成するので、後でこの2つを削除して独自のものを作成します。

  • packages:モノレポの共有設定(ESLinttsconfig、共有UI)用のファイルです。

  • package.json:ご覧の通り、これはyarn workspacesを使用しています。ここには依存関係とスクリプトがあり、appsディレクトリ内のアプリケーションを実行し、そのコマンドを実行します。

  • turbo.json:ビルド、リント、開発のパイプラインを持つTurbo設定です。これは強力なツールです。dependsOnを作成できます:コマンドの階層的な実行です。上のスクリーンショットでは、ビルドパイプラインは['^build']に依存しています。キャレット(^)は、トポロジカルな依存関係を先にビルドしてから自身をビルドすることを意味します。プロジェクトのすべての依存関係と開発依存関係が最初にビルドされてから、ビルドスクリプトを実行することを保証します。

では、このプロジェクトで使用しないコードを削除しましょう:

rm -rf node_modules apps/docs apps/web

理由TypeScriptとTailwindCSSが設定されたNext.jsアプリケーションを追加します。以下のコマンドを使用してアプリを追加しましょう:

cd apps && yarn create next-app --example with-tailwindcss demo-app && cd ..

注意:このチュートリアルでは、単一のプロジェクトの設定ファイルとセットアップを示しますが、appsディレクトリ内に複数のプロジェクトが必要な場合でも、プロセスは同じです。

これにより、TypeScriptTailwindの設定が済んだdemo-appがappsディレクトリに作成されます。

tailwindとtypescriptを設定したデモアプリ

次に、demo-appプロジェクト内のpackage.jsonファイルとnext.config.jsファイルを少し更新しましょう。まず、nameversion属性を追加し、次にpackagesディレクトリからuits-configの依存関係を追加します。これでpackage.jsonファイルとnext-config.jsファイルは以下のようになります。

{
  "name": "demo-app",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "latest",
    "react": "18.1.0",
    "react-dom": "18.1.0",
    "ui": "*"
  },
  "devDependencies": {
    "@types/node": "17.0.35",
    "@types/react": "18.0.9",
    "@types/react-dom": "18.0.5",
    "autoprefixer": "^10.4.7",
    "postcss": "^8.4.14",
    "tailwindcss": "^3.1.2",
    "typescript": "4.7.2",
    "eslint": "7.32.0",
    "eslint-config-custom": "*",
    "next-transpile-modules": "9.0.0",
    "tsconfig": "*"
  }
}
/** @type {import('next').NextConfig} */
const withTM = require('next-transpile-modules')(['ui']);

module.exports = withTM({
  reactStrictMode: true,
});

次に、yarn installを実行します。
では、共有設定ファイルを作成しましょう。TypeScriptESLintの設定があるpackagesディレクトリに移動します。tsconfigフォルダ内にbase.jsonがあり、これがnext.jsonによって拡張されていることがわかります。ここにすでにコードがあるので、demo-appプロジェクトに同じコードを追加して冗長にする必要はありません。そこで、プロジェクト内のtsconfig.jsonファイルを以下のように変更しましょう:

{
  "extends": "tsconfig/nextjs.json",
  "compilerOptions": {
    //add other additional options
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

Prettier設定

次に、ルートディレクトリにprettierrc.jsonファイルを追加します。Turborepoのセットアップを実行したときにすでにインストールされているので、何もする必要はありません。設定を含むファイルを追加するだけで問題なく動作します。私のprettierrc.jsonファイルは以下のようになっています:

{
  "tabWidth": 2,
  "semi": true,
  "trailingComma": "all",
  "printWidth": 80,
  "arrowParens": "avoid",
  "singleQuote": true
}

共有ESLint設定

共有TypeScript設定を行ったように、ESLint設定も同様に行いましょう。要件に応じて設定を追加できますが、デモのためにpackages/eslint-config-custom/index.jsに"no-console": 2ルールを追加しました。

module.exports = {
 extends: ['next', 'prettier'],
 rules: {
  'no-console': 2,
  '@next/next/no-html-link-for-pages': 'off',
  'react/jsx-key': 'off',
 },
};

次に、demo-appのルートディレクトリに.eslintrc.jsファイルを作成し、以下のコードを追加します。

module.exports = {
  ...require('eslint-config-custom/index'),
  parserOptions: {
    tsconfigRootDir: __dirname,
    project: './tsconfig.json',
  },
};

基本的に、共有のeslint-config-customフォルダからESLint設定を拡張しています。確認のために、コードにconsole.log文を追加すると、以下のスクリーンショットのようにエラーが表示されます:

これは共有のESLint設定が機能していることを意味します🎉

共有Tailwind設定

demo-appプロジェクトにはすでにTailwindCSSのセットアップがあります。
新しいNextアプリケーションが必要な場合、Tailwind設定も共有する必要があります。この新しいセクションでこれを行いましょう。Tailwindを設定するために必要な依存関係を追加します:postcss autoprefixer prettier-plugin-tailwindcss tailwindcss。以下のコマンドを使用してuiパッケージに依存関係を追加します:

yarn workspace ui add -D tailwindcss postcss autoprefixer prettier-plugin-tailwindcss

これにより、packages/uiディレクトリに依存関係が追加されます。次に、packages/uiにTailwind設定ファイルを追加しましょう:

postcss.config.js

module.exports = {
 plugins: {
  tailwindcss: {},
  autoprefixer: {},
 },
}

tailwind.config.js

module.exports = {
 content: [
  './**/*.{js,ts,jsx,tsx}',
 ],
 theme: {
  extend: {},
 },
 plugins: [],
}

次に、demo-appのtailwind.config.jsに共有設定をインポートしましょう。

module.exports = {
 ...require('ui/tailwind.config'),
 content: [
  './pages/**/*.{js,ts,jsx,tsx}',
  './components/**/*.{js,ts,jsx,tsx}',
  '../../packages/ui/**/*.{js,ts,jsx,tsx}',
 ],
 theme: {
  extend: {},
 },
 plugins: [],
};

また、Nextアプリケーションを使用しているので、packages/uitsconfig.jsonファイルを更新して、packages/tsconfigから設定を取得するようにしましょう。

{
 "extends": "tsconfig/nextjs.json",
 "include": ["."],
 "exclude": ["dist", "build", "node_modules"]
}

機能しているかテストするために、packages/uiのボタンコンポーネントを以下のように変更しましょう:

import * as React from 'react';
export const Button = () => {
 return <button className="rounded-full bg-blue-500">Boop</button>;
};

そして、demo-appのindex.tsxでこのコンポーネントを使用します。TailwindCSSがプロジェクトで機能していることが確認できます。🎉

import type { NextPage } from 'next';
import { Button } from 'ui';

const Home: NextPage = () => {
  return (
    <div className="flex min-h-screen flex-col items-center justify-center py-2">
      <main className="flex w-full flex-1 flex-col items-center justify-center px-20 text-center">
        <Button />
      </main>
    </div>
  );
};

export default Home;

Huskyとlint-stagedのセットアップ:

Huskyはコミットなどを改善します 🐶 ワンワン!

husky

Huskyは、GitHubリポジトリでの異なるフックの動作を管理できる便利なツールです。pre-commit、commit-message、deployなど、さまざまなタイプのgitフックに対して異なるスクリプトを追加することができます。
lint-staged: lint-stagedの役割は、すべてのファイルに対してリントを実行する代わりに、変更されたファイルのみをリントすることで時間を節約することです。
それでは、プロジェクトにHuskyとlint-stagedを追加していきましょう。

yarn add -D -W husky lint-staged

このコマンドの-Wは、ルートのpackage.jsonに依存関係をインストールします。
ルートのpackage.jsonファイルのscriptsセクションに'prepare':'husky install'を追加します。これによりhuskyがインストールされます。次に、huskyをインストールするために以下のコマンドを実行します。

yarn prepare
プロジェクトにhuskyがインストールされたことを確認してください。

また、リポジトリのルートに.huskyフォルダが作成されます。lint-stagedを設定するために、ルートディレクトリのpackage.jsonファイルに以下のコードを追加しましょう:

"lint-staged": {
 "apps/**/*.{js,ts,jsx,tsx}": [
   "eslint --fix"
 ],
 "packages/ui/**/*.{js,ts,jsx,tsx}": [
   "eslint --fix"
 ],
 "*.json": [
   "prettier --write"
 ]
}

これにより、appsとpackages/uiのプロジェクトに対してリントが実行されます。次に、以下のコマンドを使用してpre-commitフックを追加しましょう:

npx husky add .husky/pre-commit "npx lint-staged"

このコマンドは.huskyディレクトリにpre-commitファイルを作成します:

これにより、ユーザーがコミットする前に、ステージングされたファイルに対してlint-stagedが実行されます。HuskyとLint-stagedのセットアップが実際に動作しているかテストして確認するために、以下のコマンドを使用してプロジェクトの変更をコミットしてみましょう:

git commit -am 'medium article setup turborepo, tailwind, lint, husky'

確認のために、index.tsxにconsole.log("TEST")を追加してgit commitを実行すると、lint-stagedがエラーを投げます:

console.logを削除すると、コミットは成功します。

pre-commitフックが正常に動作していることがわかります。🎉

次に、ChakraUIについて学び、このチュートリアルで作成したアプリケーションに統合しましょう。

Chakra UI

アクセシブルなReactアプリを迅速に作成Chakra UIは、Reactアプリケーションを構築するために必要な構成要素を提供する、シンプルでモジュラーでアクセシブルなコンポーネントライブラリです。

chakra-ui.com

では、以下のコマンドを使用して、プロジェクトにChakra UIパッケージを追加しましょう:
注意-Wフラグは、ルートのpackage.jsonファイルに依存関係をインストールします。

yarn add -W@chakra-ui/react@emotion/react@emotion/styled framer-motion

セットアップが完了すると、package.jsonファイルに依存関係が表示されます。セットアップをテストするには、以下の手順に従ってください:

  1. Next.jsプロジェクトの_app.tsxファイルを更新します。ChakraProviderでラップします。

import '../styles/globals.css';
import type { AppProps } from 'next/app';
import { ChakraProvider } from '@chakra-ui/react';
function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider>
      <Component {...pageProps} />
    </ChakraProvider>
  );
}
export default MyApp;

2. ボタンコンポーネントをChakra Buttonコンポーネントで更新します。

import { Button as ChakraButton } from '@chakra-ui/react';
import * as React from 'react';

export const OurButton = () => {
  return (
    <ChakraButton className="rounded-full !bg-blue-500 text-white">
      Boop
    </ChakraButton>
  );
};

3. index.tsxページでボタンを使用します。これでChakraUIが正常に動作しています。

import type { NextPage } from 'next';
import { OurButton } from 'ui';

const Home: NextPage = () => {
  return (
    <div className="flex min-h-screen flex-col items-center justify-center py-2">
      <main className="flex w-full flex-1 flex-col items-center justify-center px-20 text-center">
        <OurButton />
      </main>
    </div>
  );
};

export default Home;
Chakra Buttonで構築されたボタンコンポーネント 🎉

最後に、Turborepoを使用して構築されたNext.jsアプリケーションを含むモノレポアプリケーションが完成しました。また、共有のTypeScriptESLint、Tailwind CSS設定もセットアップしました。そして、Huskyのpre-commitもセットアップしました。最後に、アプリケーションにChakraUIを統合しました。
参考として、以下にGitHubリポジトリのリンクを記載します。何か質問があれば、コメントを残してください。フィードバックは大歓迎です。🙇 🙏
Githubリポジトリ: https://github.com/UjjwolKayastha/next-chakra-tailwind


この記事は、2022年7月に弊社のエンジニア Ujjwol Kayastha が執筆した内容を日本語に翻訳したものです。
英語版はこちらをご覧ください。
https://articles.wesionary.team/next-js-in-turborepo-with-chakra-ui-tailwindcss-6671e6cf730d


採用情報

私たちはプロダクト共創の仕組み化に取り組んでいます。プロダクト共創をリードするプロダクト・マネージャー、そして、私たちのビジョンを市場に届ける営業メンバーを募集しています!


開発パートナーをお探しの企業様へ

弊社は、グローバル開発のメリットを活かし、高い費用対効果と品質を両立しています。経験豊富で多様性のあるチームが、課題を正しく理解し、最適なシステムと優れた体験を実現します。業務システムの開発、新規事業の開発、業務効率化やDX化に関するお困りごと、ぜひ弊社にご相談ください。