專案程式碼組織:Polyrepo vs. Monorepo
專案程式碼組織主要有兩種方式:
許多大型科技公司都使用Monorepo,例如Yandex。 Monorepo有助於在團隊和業務部門之間共享創意和最佳實踐。更多關於Monorepo和相關工具的信息,請訪問https://www.php.cn/link/b01ccf4f29b57b0b1bdb9407050db28d。本文將重點放在使用PNPM建立Monorepo的簡單方案。
PNPM使用工作區(workspaces)來整合單一倉庫中的多個項目。
環境搭建
首先,建立一個空資料夾作為新的Monorepo專案。在倉庫內初始化PNPM:
<code class="language-bash">pnpm init</code>
然後,建立一個pnpm-workspace.yaml
文件,描述包資料夾:
<code class="language-yaml">// pnpm-workspace.yaml packages: - 'packages/**' - 'apps/**'</code>
/packages
資料夾存放共用程式庫,/apps
資料夾存放應用程式(例如,獨立的React Native行動應用程式和使用相同元件或連接程式庫與API伺服器通訊的Web應用程式)。
本文將使用一個Telegram發布機器人為例,其原始碼位於GitHub:https://www.php.cn/link/8164ca2fe04767628ac1c6813e8a0867。下載並解壓縮到/apps/publish-bot
資料夾,然後執行安裝指令:
<code class="language-bash">pnpm install</code>
建立Telegram工具包
在/packages
資料夾中建立一個名為telegram-utils
的資料夾,初始化PNPM和TypeScript:
<code class="language-bash">pnpm init && pnpm add -D typescript && pnpm tsc --init</code>
該套件將提供一個函數,用於組合來自所有訊息(文字、影片和照片)的文字和標題。需要安裝Telegraf包:
<code class="language-bash">pnpm add telegraf</code>
所有原始碼都應位於/src
目錄中。為了方便功能分組,建議建立不同的資料夾。組合文字的功能位於/texts
資料夾中,程式碼如下:
<code class="language-typescript">// packages/telegram-utils/src/texts/combineTexts.ts import { Message } from 'telegraf/types'; import { FmtString, join } from 'telegraf/format'; type GroupedMessages = { photos: Array<Message.PhotoMessage>; videos: Array<Message.VideoMessage>; text: Array<Message.TextMessage>; }; export const combineTexts = ({ photos, videos, text }: GroupedMessages) => { const photoTexts = photos .map(photo => photo.caption ? new FmtString(photo.caption, photo.caption_entities) : undefined) .filter((t): t is Required<FmtString> => t !== undefined); const videoTexts = videos .map(video => video.caption ? new FmtString(video.caption, video.caption_entities) : undefined) .filter((t): t is Required<FmtString> => t !== undefined); const allTexts = []; if (text.length) allTexts.push(join(text.map(t => new FmtString(t.text, t.entities))), '\n'); if (photoTexts.length) allTexts.push(join(photoTexts, '\n')); if (videoTexts.length) allTexts.push(join(videoTexts, '\n')); return join(allTexts, '\n'); };</code>
代碼說明:
undefined
;建立/texts
資料夾的索引檔:
<code class="language-bash">pnpm init</code>
在package.json
檔案中使用exports
欄位設定套件功能的匯出:
<code class="language-yaml">// pnpm-workspace.yaml packages: - 'packages/**' - 'apps/**'</code>
為了在應用程式中辨識Monorepo包,為所有包加上前綴@monorepo
。重新命名package.json
檔案中的telegram-utils
套件:
<code class="language-bash">pnpm install</code>
新增建置腳本:
<code class="language-bash">pnpm init && pnpm add -D typescript && pnpm tsc --init</code>
完整的package.json
檔案:
<code class="language-bash">pnpm add telegraf</code>
設定TypeScript編譯器:啟用增量編譯以節省建置時間,僅處理變更的部分;啟用複合編譯以使用專案參考。將/src
資料夾定義為rootDir
,將套件的outDir
定義為/dist
。更新後的tsconfig.json
:
<code class="language-typescript">// packages/telegram-utils/src/texts/combineTexts.ts import { Message } from 'telegraf/types'; import { FmtString, join } from 'telegraf/format'; type GroupedMessages = { photos: Array<Message.PhotoMessage>; videos: Array<Message.VideoMessage>; text: Array<Message.TextMessage>; }; export const combineTexts = ({ photos, videos, text }: GroupedMessages) => { const photoTexts = photos .map(photo => photo.caption ? new FmtString(photo.caption, photo.caption_entities) : undefined) .filter((t): t is Required<FmtString> => t !== undefined); const videoTexts = videos .map(video => video.caption ? new FmtString(video.caption, video.caption_entities) : undefined) .filter((t): t is Required<FmtString> => t !== undefined); const allTexts = []; if (text.length) allTexts.push(join(text.map(t => new FmtString(t.text, t.entities))), '\n'); if (photoTexts.length) allTexts.push(join(photoTexts, '\n')); if (videoTexts.length) allTexts.push(join(videoTexts, '\n')); return join(allTexts, '\n'); };</code>
整合
回到/apps/publish-bot
,將@monorepo/telegram-utils
套件加入依賴項。注意,不需要指定套件版本,使用workspace:*
表示:
<code class="language-typescript">// packages/telegram-utils/src/texts/index.ts export * from './combineTexts';</code>
安裝依賴項:
<code class="language-json">// packages/telegram-utils/package.json "exports": { "./texts": { "import": "./src/texts/index.ts", "require": "./dist/texts/index.js" } }</code>
更新發布機器人的preview
指令:
<code class="language-json">// packages/telegram-utils/package.json "name": "@monorepo/telegram-utils"</code>
更新/apps/publish-bot/tsconfig.json
:
<code class="language-json">// packages/telegram-utils/package.json "scripts": { "build": "tsc -p tsconfig.json" }</code>
在建構應用程式碼前,需要先建置所有依賴項:
<code class="language-json">// packages/telegram-utils/package.json { "name": "@monorepo/telegram-utils", "version": "1.0.0", "main": "index.js", "scripts": { "build": "tsc -p tsconfig.json" }, "keywords": [], "license": "ISC", "exports": { "./texts": { "import": "./src/texts/index.ts", "require": "./dist/texts/index.js" } }, "devDependencies": { "typescript": "^5.7.3" }, "dependencies": { "telegraf": "^4.16.3" } }</code>
總結
現在,發布機器人使用內部共享庫/包,並位於Monorepo中。這使得快速建立新功能和在多個應用程式中重複使用程式碼成為可能。
圖片來自Unsplash的Gabriel Heinzer
以上是使用 PNPM 在 Monorepo 中建置並運行您的專案的詳細內容。更多資訊請關注PHP中文網其他相關文章!