新しいモノレポの作成
このガイドでは、グローバルインストールされたturboを使用します。このセットアップについては、インストールガイドに従ってください。または、下記のコマンドでローカルインストールされたturboをパッケージマネージャーを使用して実行することもできます。
クイックスタート
新しいモノレポを作成するには、create-turbo (新しいタブで開きます) npmパッケージを使用します。
npx create-turbo@latestまた、Turborepoスターターリポジトリをクローンして、モノレポを始めることもできます。Turborepoのサンプルとスターターについては、GitHubのTurborepoのサンプルディレクトリ (新しいタブで開きます)を参照してください。
完全なチュートリアル
このチュートリアルでは、基本的なサンプルを設定する方法を説明します。終了する頃には、turboの使用に自信を持ち、すべての基本的な機能を理解できるようになります。
このチュートリアルでは、コードサンプルから一部のコード行が省略されています。たとえば、package.jsonを表示する場合、すべてのキーを表示するのではなく、重要なキーのみを表示します。
1. create-turboの実行
最初に、次を実行します
npx create-turbo@latestこれにより、create-turbo (新しいタブで開きます) CLIがインストールされ、実行されます。いくつかの質問に回答する必要があります。
turborepoを作成する場所は?
好きな場所を選択してください。デフォルトは./my-turborepoです。
使用するパッケージマネージャーは?
Turborepoはパッケージのインストールを処理しないため、次のいずれかを選択する必要があります。
create-turboは、システムで使用可能なパッケージマネージャーを検出します。どれを選択すればよいかわからない場合は、Turborepoはpnpmを推奨します。
インストール
パッケージマネージャーを選択したら、create-turbo は、選択したフォルダー名の中にたくさんの新しいファイルを作成します。また、デフォルトで basic サンプルに付属するすべての依存関係をインストールします。
2. 新しいリポジトリの探索
ターミナルに何かが表示されていることに気づいたかもしれません。create-turbo は、追加したすべてのものの説明を提供しました。
>>> Creating a new turborepo with the following:
- apps/web: Next.js with TypeScript
- apps/docs: Next.js with TypeScript
- packages/ui: Shared React component library
- packages/eslint-config: Shared configuration (ESLint)
- packages/typescript-config: Shared TypeScript `tsconfig.json`これらはそれぞれワークスペースです。つまり、package.json を含むフォルダーです。各ワークスペースは、独自の依存関係を宣言し、独自のスクリプトを実行し、他のワークスペースが使用するコードをエクスポートできます。
お気に入りのコードエディターで、ルートフォルダー - ./my-turborepo - を開いてください。
packages/ui の理解
まず、./packages/ui/package.json を開きます。パッケージの名前が "name": "@repo/ui" であることに気付くでしょう。これはファイルの先頭にあります。
次に、./apps/web/package.json を開きます。このパッケージの名前が "name": "web" であることに気付くでしょう。ただし、その依存関係も確認してください。
"web" が "@repo/ui" という名前のパッケージに依存していることがわかります。
{
"dependencies": {
"@repo/ui": "*"
}
}これは、Web アプリがローカルの @repo/ui パッケージに依存していることを意味します。
apps/docs/package.json の中を見ると、同じことがわかります。web と docs の両方が @repo/ui に依存しています。これは共有コンポーネントライブラリです。
アプリケーション間でコードを共有するこのパターンは、モノレポでは非常に一般的であり、複数のアプリが単一のデザインシステムを共有できることを意味します。
インポートとエクスポートの理解
./apps/docs/app/page.tsx の中を見てください。docs と web はどちらもNext.js(新しいタブで開きます)アプリケーションであり、どちらも同様の方法で @repo/ui ライブラリを使用しています
import { Button } from "@repo/ui/button";
// ^^^^^^ ^^^^^^^^^^^^^^^
export default function Page() {
return (
<>
<Button appName="web" className={styles.button}>
Click me!
</Button>
<>
);
}それらは Button を @repo/ui/button という依存関係から直接インポートしています。これはどのように機能するのでしょうか? Button はどこから来ているのでしょうか?
packages/ui/package.json を開きます。exports フィールドが表示されます。
{
"exports": {
"./button": "./src/button.tsx",
"./card": "./src/card.tsx",
"./code": "./src/code.tsx"
},
}ワークスペースが @repo/ui/button からインポートするとき、exports は、インポートしているコードにアクセスする場所を示します。
それでは、packages/ui/src/button.tsx の中を見てみましょう
"use client";
import { ReactNode } from "react";
interface ButtonProps {
children: ReactNode;
className?: string;
appName: string;
}
export const Button = ({ children, className, appName }: ButtonProps) => {
return (
<button
className={className}
onClick={() => alert(`Hello from your ${appName} app!`)}
>
{children}
</button>
);
};ボタンが見つかりました!
このファイル内のすべてのものは、@repo/ui/button に依存するワークスペースで使用できるようになります。
このファイルで行う変更はすべて、web および docs で共有されます。とてもクールです!
このファイルから別の関数をエクスポートしてみてください。たとえば、2つの数値を足し合わせるための add(a, b) など。
これは、web と docs でインポートできるようになります。
tsconfig の理解
さらに、typescript-config と eslint-config の 2 つのワークスペースを見てみましょう。これらの各ワークスペースでは、モノレポ全体で構成を共有できます。typescript-config の中を見てみましょう
{
"name": "@repo/typescript-config",
}ここで、パッケージの名前が @repo/typescript-config であることがわかります。
次に、web アプリにある tsconfig.json ファイルの中を見てみましょう。
{
"extends": "@repo/typescript-config/nextjs.json",
}ご覧のとおり、@repo/typescript-config/nextjs.json を tsconfig.json ファイルに直接インポートしています。
このパターンにより、モノレポはすべてのワークスペースで単一の tsconfig.json を共有でき、コードの重複を減らすことができます。
eslint-config の理解
最後のワークスペースは eslint-config です。
まず、packages/eslint-config/package.json の中を見てみましょう
{
"name": "@repo/eslint-config",
"files": [
"library.js",
"next.js",
"react-internal.js"
],
}ご覧のとおり、パッケージの名前は @repo/eslint-config であり、library.js、next.js、react-internal.js の3つのファイルを公開しています。
カスタム ESLint 設定をどのように使用できるかを理解するために、apps/docs/.eslintrc.js の中を見てみましょう
module.exports = {
extends: ["@repo/eslint-config/next.js"],
};ここでは、@repo/eslint-config/next.js を .eslintrc.js ファイルに直接インポートしていることがわかります。
typescript-config と同様に、eslint-config を使用すると、モノレポ全体で ESLint の設定を共有でき、どのプロジェクトで作業していても一貫性を保つことができます。
概要
これらのワークスペース間の依存関係を理解することが重要です。それらをマッピングしてみましょう。
web-ui、typescript-config、およびeslint-configに依存しますdocs-ui、typescript-config、およびeslint-configに依存しますui-typescript-configおよびeslint-configに依存しますtypescript-config- 依存関係はありませんeslint-config- 依存関係はありません
Turborepo CLI はこれらの依存関係を管理する責任がないことに注意してください。上記のすべてのことは、選択したパッケージ マネージャー (npm、pnpm、または yarn) によって処理されます。
3. turbo.json の理解
これで、リポジトリとその依存関係を理解できました。Turborepo はどのように役立つのでしょうか。
Turborepo は、タスクの実行をより簡単かつはるかに効率的にすることで役立ちます。
ルートにある turbo.json の中を見てみましょう。
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**"]
},
"lint": {
"dependsOn": ["^lint"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}ここで確認しているのは、turbo に 3 つのタスク (lint、dev、build) を登録したということです。turbo.json 内に登録されたすべてのタスクは、turbo run <task> (または短縮形の turbo <task>) で実行できます。
先に進む前に、turbo.json に登録されていない hello というタスクを実行してみましょう。
turbo helloターミナルにエラーが表示されます。次のようなもの。
Could not find the following tasks in project: helloこれは覚えておく価値があります。turbo がタスクを実行するには、turbo.json に記述されている必要があります。
すでに用意されているスクリプトを調べてみましょう。
4. Turborepo を使用したリンティング
lint スクリプトを実行してみましょう。
turbo lintターミナルでいくつかのことが発生します。
- いくつかのスクリプトが同時に実行され、それぞれに
docs:lint、@repo/ui:lint、またはweb:lintのいずれかのプレフィックスが付いています。 - それぞれが成功し、ターミナルに
3 successfulと表示されます。 - また、
0 cached, 3 totalと表示されます。これが何を意味するのかは後で説明します。
実行される各スクリプトは、各ワークスペースの package.json から取得されます。各ワークスペースは、独自の lint スクリプトをオプションで指定できます。
{
"scripts": {
"lint": "next lint"
}
}{
"scripts": {
"lint": "next lint"
}
}{
"scripts": {
"lint": "eslint \"**/*.ts*\""
}
}turbo lint を実行すると、Turborepo は各ワークスペースの各 lint スクリプトを確認し、実行します。詳細については、パイプラインに関するドキュメントを参照してください。
キャッシュの使用
lint スクリプトをもう一度実行してみましょう。ターミナルにいくつかの新しいものが表示されます。
cache hit, replaying logsがdocs:lint、web:lint、@repo/ui:lintに対して表示されます。3 cached, 3 totalと表示されます。- 合計実行時間は
100ms未満になり、>>> FULL TURBOが表示されます。
興味深いことが起こりました。Turborepo は、前回のリンティング スクリプトの実行後、コードが変更されていないことに気づきました。
以前の実行からのログを保存していたため、それらを再生しただけです。
何が起こるかを確認するために、コードをいくつか変更してみましょう。apps/docs 内のファイルを変更します。
import { Button } from "@repo/ui/button";
// ^^^^^^ ^^^^^^^^^^^^^^^
export default function Page() {
return (
<>
<Button appName="web" className={styles.button}>
- Click me!
+ Click me now!
</Button>
<>
);
}次に、lint スクリプトを再度実行します。次のことに気づくでしょう。
docs:lintには、cache miss, executingというコメントがあります。これは、docsがリンティングを実行していることを意味します。2 cached, 3 totalが下部に表示されます。
これは、以前のタスクの結果がまだキャッシュされていることを意味します。 docs内のlintスクリプトのみが実際に実行されました。これにより、処理が高速化されます。詳細については、キャッシュに関するドキュメントをご覧ください。
5. Turborepoを使ったビルド
buildスクリプトを実行してみましょう。
turbo buildリンティングスクリプトを実行したときと似た出力が表示されるでしょう。apps/docsとapps/webのみが、それぞれのpackage.jsonでbuildスクリプトを指定しているので、それらのみが実行されます。
turbo.json内のbuildの中を見てください。興味深い設定があります。
{
"pipeline": {
"build": {
"outputs": [".next/**", "!.next/cache/**"]
}
}
}いくつかのoutputsが指定されていることに気づくでしょう。出力を宣言すると、turboがタスクの実行を完了したときに、指定した出力がキャッシュに保存されることを意味します。
apps/docsとapps/webはどちらもNext.jsアプリであり、./.nextフォルダーにビルドを出力します。
試してみましょう。apps/docs/.nextビルドフォルダーを削除してください。
もう一度buildスクリプトを実行します。気づくでしょう。
FULL TURBOになりました。ビルドは100ms未満で完了します。.nextフォルダーが再表示されます!
Turborepoは以前のビルドの結果をキャッシュしました。再度buildコマンドを実行したとき、キャッシュから.next/**フォルダー全体が復元されました。詳細については、キャッシュ出力に関するドキュメントをご覧ください。
6. 開発スクリプトの実行
次に、devを実行してみましょう。
turbo devターミナルにいくつかの情報が表示されるでしょう。
docs:devとweb:devの2つのスクリプトのみが実行されます。これらは、devを指定している唯一の2つのワークスペースです。- 両方の
devスクリプトが同時に実行され、ポート3000と3001でNext.jsアプリが開始されます。 - ターミナルには、
cache bypass, force executingが表示されます。
スクリプトを終了して、再度実行してみてください。FULL TURBOにならないことに気づくでしょう。それはなぜでしょうか?
turbo.jsonを見てください。
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true
}
}
}dev内で、"cache": falseを指定しました。これは、Turborepoにdevスクリプトの結果をキャッシュしないように指示していることを意味します。devは永続的な開発サーバーを実行し、出力は生成しないため、キャッシュするものはありません。詳細については、キャッシュをオフにするに関するドキュメントをご覧ください。
さらに、"persistent": trueを設定して、これが長時間実行される開発サーバーであることをturboに知らせ、turboが他のタスクが依存しないようにすることを保証できるようにします。persistentオプションのドキュメントで詳細を読むことができます。
一度に1つのワークスペースでのみdevを実行する
デフォルトでは、turbo devはすべてのワークスペースでdevを一度に実行します。しかし、1つのワークスペースのみを選択したい場合があります。
これを処理するために、コマンドに--filterフラグを追加できます。
turbo dev --filter docsこれで、docs:devのみが実行されるようになったことに気づくでしょう。ワークスペースのフィルタリングについては、ドキュメントをご覧ください。
まとめ
よくできました!新しいモノレポと、Turborepoがタスクの処理をどのように簡単にするかについて学びました。
次のステップ
- タスクを追加する必要がありますか?パイプラインの使用について学びましょう。
- CIを高速化したいですか?リモートキャッシュを設定します。
- インスピレーションが必要ですか?examples (新しいタブで開きます)のディレクトリをご覧ください。