建立新的單一儲存庫
本指南使用 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": "*"
}
}
這表示我們的網頁應用程式依賴我們的本機 @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>
<>
);
}
它們直接從名為 @repo/ui/button
的依賴項匯入 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
中共用。很酷吧!
嘗試從此檔案中匯出不同的函式。也許 add(a, b)
可用於將兩個數字加總。
然後,這可以由 web
和 docs
匯入。
了解 tsconfig
我們還有兩個工作空間要查看,typescript-config
和 eslint-config
。每個都允許在單一儲存庫中共用設定。我們來看看 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
。
為了了解我們如何使用自訂 ESLint 組態,讓我們查看 apps/docs/.eslintrc.js
module.exports = {
extends: ["@repo/eslint-config/next.js"],
};
在這裡你可以看到我們直接將 @repo/eslint-config/next.js
匯入到我們的 .eslintrc.js
檔案中。
就像 typescript-config
一樣,eslint-config
讓我們可以在整個 monorepo 中分享 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
註冊 三個任務:lint
、dev
和 build
。在 turbo.json
內部註冊的每個任務都可以使用 turbo run <task>
(或簡寫為 turbo <task>
)執行。
在我們繼續之前,讓我們嘗試執行一個名為 hello
的任務,該任務未在 turbo.json
中註冊
turbo hello
您會在終端機看到錯誤訊息。類似
Could not find the following tasks in project: hello
值得注意的是 - 要讓 turbo
執行任務,它必須在 turbo.json
中。
讓我們調查我們已經準備好的腳本。
4. 使用 Turborepo 進行 linting
嘗試執行我們的 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
腳本並執行它。如需更多詳細資訊,請參閱我們的 pipelines 文件。
使用快取
我們再執行一次 lint
這個指令碼。你會注意到終端機中出現一些新的訊息
cache hit, replaying logs
出現在docs:lint
、web:lint
和@repo/ui:lint
。- 你會看到
3 cached, 3 total
。 - 總執行時間應低於
100ms
,並出現>>> FULL TURBO
。
剛才發生了一件有趣的事。Turborepo 發現我們的程式碼自上次執行 lint 指令碼後並未變更。
它已儲存前一次執行的記錄,因此只需重新執行它們。
讓我們嘗試變更一些程式碼,看看會發生什麼事。對 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
正在執行 linting。2 cached, 3 total
出現在底部。
這表示我們先前任務的結果仍被快取。只有 lint
指令碼在 docs
內部實際執行 - 再一次地,加速處理。如需深入了解,請查看我們的 快取文件。
5. 使用 Turborepo 建置
我們來試著執行我們的 build
指令碼
turbo build
你會看到與我們執行 lint 指令碼時類似的輸出。只有 apps/docs
和 apps/web
在其 package.json
中指定 build
指令碼,所以只有這些會執行。
在 turbo.json
中查看 build
的內部。那裡有一些有趣的設定檔。
{
"pipeline": {
"build": {
"outputs": [".next/**", "!.next/cache/**"]
}
}
}
您會注意到某些 輸出
已指定。宣告輸出表示當 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
。這兩個工作區是唯一指定dev
的。 - 兩個
dev
腳本會同時執行,在埠3000
和3001
上啟動您的 Next.js 應用程式。 - 在終端機中,您會看到
快取略過,強制執行
。
嘗試退出腳本,然後重新執行。您會注意到我們不會進入 FULL TURBO
。這是為什麼?
看看 turbo.json
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true
}
}
}
在 dev
中,我們指定了 "cache": false
。這表示我們告訴 Turborepo 不要快取 dev
腳本的結果。 dev
執行持續的開發伺服器,且不產生任何輸出,因此沒有任何東西可以快取。在我們的文件 關閉快取 中深入了解它。
此外,我們設定 "persistent": true
,讓 turbo 知道這是一個長時間執行的開發伺服器,以便 turbo 能確保沒有其他任務依賴於它。您可以在 persistent
選項的文件 中閱讀更多內容。
一次只在一個工作區上執行 dev
預設情況下,turbo dev
會同時在所有工作區上執行 dev
。但有時,我們可能只想選擇一個工作區。
為了解決這個問題,我們可以在命令中新增 --filter
旗標。
turbo dev --filter docs
您會注意到,現在它只執行 docs:dev
。從我們的文件中深入了解 過濾工作區。
摘要
做得好!您已了解有關新單一儲存庫的所有資訊,以及 Turborepo 如何讓您更容易處理任務。
後續步驟
- 需要新增更多任務?深入了解如何使用 管線
- 想要加快您的 CI 速度?設定 遠端快取。
- 想要一些靈感?看看我們的 範例(在新分頁中開啟) 目錄