Turborepo: Tăng tốc phát triển với Monorepo
Trong quá trình phát triển phần mềm, đặc biệt là khi làm việc với nhiều dự án con trong cùng một hệ thống, việc quản lý mã nguồn trở nên phức tạp hơn bao giờ hết. Đây là lúc Turborepo – một công cụ quản lý monorepo hiệu quả – trở thành giải pháp lý tưởng để tăng tốc quá trình phát triển và xây dựng dự án. Trong bài viết này, chúng ta sẽ tìm hiểu về cách Turborepo giúp bạn tiết kiệm thời gian và tối ưu hóa quy trình làm việc.
1. Monorepo là gì?
Monorepo là một cách tiếp cận quản lý mã nguồn trong đó tất cả các dự án liên quan đều được lưu trữ trong một kho mã duy nhất. Thay vì sử dụng nhiều repository cho từng dự án nhỏ (microservice, frontend, backend, thư viện dùng chung), với monorepo, bạn chỉ cần một kho mã duy nhất.
Lợi ích của Monorepo:
- Dễ dàng chia sẻ mã: Các thư viện dùng chung giữa các dự án có thể dễ dàng được chia sẻ mà không cần phải quản lý chúng ở các repository riêng lẻ.
- Dễ dàng đồng bộ hóa: Các thay đổi lớn trong mã nguồn có thể được thực hiện nhất quán trên tất cả các phần của hệ thống.
- Đơn giản hóa quản lý dự án: Thay vì phải quản lý nhiều repo, bạn chỉ cần làm việc với một repo duy nhất.
Tuy nhiên, monorepo cũng có nhược điểm, như thời gian build dài khi có nhiều dự án trong cùng một repo. Đây là lúc Turborepo trở nên hữu ích.
2. Turborepo là gì?
Turborepo là một công cụ được xây dựng để quản lý và tối ưu hóa quá trình phát triển trong một monorepo. Nó được tạo ra bởi Vercel và giúp phát triển các dự án đa nền tảng một cách nhanh chóng và hiệu quả thông qua:
- Caching thông minh: Lưu trữ kết quả của các quá trình build và test, giúp giảm thời gian lặp lại những công việc không cần thiết.
- Incremental builds: Chỉ xây dựng lại những phần của dự án đã thay đổi.
- Pipeline task: Quản lý các tác vụ (tasks) phụ thuộc lẫn nhau một cách dễ dàng.
- Remote caching: Chia sẻ cache giữa các máy tính khác nhau hoặc CI/CD pipeline, giúp đồng bộ hóa các kết quả.
3. Lợi ích chính của Turborepo
3.1. Tăng tốc build và test
Một trong những tính năng quan trọng nhất của Turborepo là khả năng sử dụng cache thông minh. Bất cứ khi nào bạn chạy build hoặc test, Turborepo sẽ lưu trữ kết quả. Nếu bạn thực hiện lại cùng một thao tác mà không có thay đổi trong mã nguồn, Turborepo sẽ lấy kết quả từ cache thay vì thực hiện lại toàn bộ quá trình build/test. Điều này giúp tiết kiệm rất nhiều thời gian, đặc biệt là khi làm việc với các dự án lớn.
3.2. Build theo kiểu incremental
Không phải mọi thay đổi đều cần phải build lại toàn bộ hệ thống. Với incremental builds, Turborepo chỉ xây dựng lại những phần của dự án có thay đổi. Ví dụ, nếu bạn chỉ thay đổi mã nguồn của frontend, thì backend và các phần khác của dự án sẽ không bị build lại. Điều này không chỉ giúp tối ưu thời gian mà còn giúp CI/CD pipeline hoạt động hiệu quả hơn.
3.3. Quản lý các pipeline task dễ dàng
Turborepo cho phép bạn định nghĩa các pipeline task phụ thuộc lẫn nhau, chẳng hạn như build, lint, và test. Bạn có thể dễ dàng sắp xếp thứ tự chạy của các tác vụ này và quản lý phụ thuộc giữa chúng. Điều này giúp quản lý quy trình phát triển trở nên đơn giản hơn.
3.4. Chia sẻ cache từ xa (Remote Caching)
Với tính năng remote caching, các kết quả build và test có thể được chia sẻ giữa nhiều môi trường khác nhau. Nếu một thành viên trong nhóm đã build và lưu trữ kết quả, các thành viên khác hoặc CI/CD pipeline có thể sử dụng lại kết quả này thay vì build lại từ đầu.
4. Cách sử dụng Turborepo trong thực tế
Khi sử dụng Turborepo trong các dự án lớn, việc quản lý tài nguyên dùng chung là một trong những lợi ích quan trọng. Dưới đây là chi tiết về cách sử dụng Turborepo trong thực tế, đặc biệt tập trung vào việc chia sẻ và quản lý tài nguyên dùng chung trong một dự án cụ thể.
4.1 Cấu trúc monorepo với tài nguyên dùng chung
Khi bạn có nhiều dự án con (frontend, backend, mobile) và cần chia sẻ một số thư viện hoặc mã nguồn dùng chung, việc sử dụng monorepo kết hợp với Turborepo giúp bạn dễ dàng quản lý và đồng bộ hóa mã nguồn giữa các dự án.
Cấu trúc thư mục ví dụ:
/my-monorepo /apps /frontend # Dự án React hoặc Next.js /backend # Dự án NestJS hoặc Express /mobile # Dự án React Native hoặc Flutter /packages /shared-ui # Thư viện UI dùng chung giữa frontend và mobile /utils # Thư viện tiện ích dùng chung giữa tất cả các ứng dụng /types # Định nghĩa kiểu dữ liệu chung turbo.json # Cấu hình cho Turborepo package.json # Các dependency dùng chung tsconfig.json # Cấu hình TypeScript dùng chung
apps/
: Thư mục chứa các dự án riêng biệt, ví dụ frontend, backend, và mobile.packages/
: Thư mục chứa các tài nguyên dùng chung như thư viện UI (shared-ui
), thư viện tiện ích (utils
), và các định nghĩa kiểu TypeScript (types
).
4.2 Cách tổ chức tài nguyên dùng chung
Trong cấu trúc trên, các thư viện hoặc mã nguồn dùng chung được đặt trong thư mục packages
, giúp các dự án trong apps
có thể dễ dàng import và sử dụng chúng.
Ví dụ về thư viện UI dùng chung (shared-ui
):
Nếu bạn có một thư viện UI tùy chỉnh được sử dụng trong cả frontend và mobile, bạn có thể đặt mã nguồn của thư viện này trong thư mục packages/shared-ui
.
/packages /shared-ui /components Button.tsx Card.tsx /index.ts package.json tsconfig.json
components/
: Chứa các component nhưButton
,Card
, và các thành phần UI khác.index.ts
: File xuất các component.package.json
: Quản lý các dependency riêng của thư viện UI.tsconfig.json
: Cấu hình TypeScript cho thư viện này.
Các dự án con như frontend và mobile có thể sử dụng thư viện này bằng cách thêm nó vào dependencies trong package.json của dự án tương ứng:
{ "dependencies": { "shared-ui": "workspace:*" }
}
Chia sẻ thư viện tiện ích (utils
):
Một thư viện tiện ích (utils
) có thể chứa các hàm dùng chung như formatDate
, parseURL
, hoặc validateEmail
. Cấu trúc của thư viện tiện ích có thể như sau:
/packages /utils /functions formatDate.ts parseURL.ts /index.ts package.json
4.3 Cấu hình Turborepo để quản lý tài nguyên dùng chung
Trong tệp turbo.json
, bạn có thể định nghĩa các task cho từng phần của dự án, và Turborepo sẽ đảm bảo chỉ chạy lại những phần bị thay đổi hoặc phụ thuộc vào những thay đổi đó.
Cấu hình turbo.json
:
{ "$schema": "https://turbo.build/schema.json", "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] }, "lint": { "outputs": [] }, "test": { "outputs": ["coverage/**"] } }
}
dependsOn: ["^build"]
: Điều này có nghĩa là mỗi dự án phụ thuộc vào kết quả build của các dự án dùng chung. Ví dụ, nếu thư việnutils
thay đổi, tất cả các dự án phụ thuộc vào nó (frontend, backend, mobile) sẽ tự động được build lại.
4.4 Cách sử dụng tài nguyên dùng chung trong từng dự án
Import tài nguyên dùng chung vào frontend và mobile:
Trong dự án frontend (React hoặc Next.js), bạn có thể sử dụng thư viện UI dùng chung như sau:
import { Button, Card } from 'shared-ui/components'; const HomePage = () => ( <div> <Button label="Click me" /> <Card title="This is a card" /> </div>
); export default HomePage;
Tương tự, trong dự án mobile (React Native), bạn cũng có thể import các component từ shared-ui
:
import { Button } from 'shared-ui/components'; const MobileScreen = () => ( <View> <Button label="Press me" /> </View>
); export default MobileScreen;
Sử dụng thư viện tiện ích (utils
) trong backend:
Trong dự án backend (NestJS), bạn có thể sử dụng các hàm từ thư viện tiện ích utils
để xử lý dữ liệu:
import { formatDate } from 'utils/functions'; @Injectable()
export class DateService { formatCurrentDate() { return formatDate(new Date()); }
}
4.5 Remote Caching và CI/CD
Remote Caching:
Tính năng remote caching của Turborepo giúp chia sẻ cache giữa các thành viên trong nhóm hoặc các pipeline CI/CD, giúp giảm thời gian build khi chạy các tác vụ đã được thực hiện trước đó. Bạn có thể cấu hình remote cache trên các nền tảng như Vercel, AWS, hoặc Google Cloud.
Để kích hoạt remote caching, bạn có thể thêm cấu hình vào tệp .turbo/config.json
:
{ "team": "your-team-id", "remoteCache": { "enabled": true }
}
Sau đó, các kết quả build hoặc test của một thành viên trong nhóm sẽ được lưu vào cache, và các thành viên khác có thể sử dụng lại cache này mà không cần phải build lại từ đầu.
Tích hợp Turborepo vào CI/CD:
Trong pipeline CI/CD, Turborepo giúp giảm thời gian build bằng cách chỉ thực hiện các tác vụ cần thiết. Bạn có thể sử dụng Turborepo trong CI/CD với các lệnh tương tự như khi chạy cục bộ, ví dụ:
turbo run build
Nếu sử dụng remote caching, Turborepo sẽ đồng bộ hóa cache giữa các lần chạy, giúp tiết kiệm tài nguyên và thời gian trong quá trình CI/CD.
4.6. Kết luận
Sử dụng Turborepo trong dự án monorepo với các tài nguyên dùng chung mang lại nhiều lợi ích như:
- Dễ dàng chia sẻ và quản lý tài nguyên giữa các dự án con.
- Tối ưu hóa quy trình build và test, chỉ chạy lại những phần cần thiết.
- Hỗ trợ remote caching, giúp giảm thiểu thời gian build khi làm việc trong nhóm hoặc CI/CD pipeline.
- Quản lý phụ thuộc linh hoạt, đảm bảo các dự án liên quan luôn được đồng bộ hóa một cách hiệu quả.
Turborepo là một công cụ không thể thiếu nếu bạn đang làm việc với monorepo lớn và cần tối ưu hóa quy trình phát triển.
5. Khi nào nên sử dụng Turborepo?
Turborepo là lựa chọn lý tưởng khi:
- Bạn đang phát triển một hệ thống với nhiều dịch vụ và dự án con.
- Bạn muốn tối ưu hóa thời gian build và deploy.
- Bạn muốn quản lý dependency giữa các dự án một cách dễ dàng.
- Bạn muốn đồng bộ hóa quá trình build/test giữa các máy tính và CI/CD pipeline.