0
0
Lập trình
Admin Team
Admin Teamtechmely

Nx: Giải Pháp Bí Mật Của Công Nghệ Lớn Để Xây Dựng Monorepo Mở Rộng

Đăng vào 7 tháng trước

• 8 phút đọc

Chủ đề:

KungFuTech

Mục Đích & Nguyên Tắc

Mục tiêu: Xây dựng một monorepo mở rộng và dễ bảo trì cho TypeScript, React, Elysia.js (hoặc NestJS) — tối ưu hóa cho tốc độsự rõ ràng khi đội ngũ và mã nguồn phát triển.

Nguyên tắc chỉ đạo:

  • Nguồn thông tin duy nhất cho mã chia sẻ → các gói nằm trong /packages.
  • Ứng dụng độc lập, chỉ phụ thuộc vào các gói.
  • Ranh giới nghiêm ngặt được thực thi bởi quy tắc của Nx để ngăn chặn sự phụ thuộc lộn xộn.
  • Tự động thông minh → sinh, lint, xây dựng và kiểm tra chỉ những gì thay đổi.
  • Hạnh phúc của lập trình viên → phản hồi nhanh, công cụ nhất quán, giảm thiểu gánh nặng nhận thức.

Tại Sao Điều Này Quan Trọng

Khi nhiều đội nhóm và ứng dụng chia sẻ một mã nguồn, mọi thứ có thể đi lệch hướng rất nhanh:

  • Ứng dụng bắt đầu phụ thuộc vào nhau → sự kết nối trong quá trình triển khai và sự cố ẩn.
  • Logic chia sẻ bị trùng lặp hoặc thực hiện không đồng nhất.
  • Thời gian xây dựng tăng vọt khi repo phát triển.
  • Việc hướng dẫn lập trình viên mới trở nên đau đớn — họ không biết mã nên nằm ở đâu hoặc cái gì là an toàn để thay đổi.

Bằng cách tuân theo cấu trúc này:

  1. Ứng dụng độc lập
    • Bạn có thể triển khai, kiểm tra và mở rộng từng ứng dụng mà không lo lắng về những ứng dụng khác.
    • Ví dụ: Ứng dụng web LMS của bạn không bị hỏng nếu ai đó thay đổi backend thương mại điện tử.
  2. Nguồn thông tin duy nhất trong /packages
    • Các tiện ích, mô hình, hợp đồng và thành phần UI chia sẻ nằm ở một nơi.
    • Không có trùng lặp mã → không có “bug đã sửa ở đây nhưng thiếu ở đó”.
  3. Pipelines nhanh với bộ nhớ cache của Nx
    • Nx biết chính xác mã nào phụ thuộc vào mã nào → nó chỉ tái xây dựng và kiểm tra tập hợp tối thiểu các dự án bị ảnh hưởng.
    • Điều này giữ cho CI và phát triển cục bộ nhanh như chớp.

Các Vấn Đề Mà Nx Giải Quyết

Vấn Đề Cách Tài Liệu Này Giải Quyết
Các ứng dụng phụ thuộc trực tiếp vào nhau Quy tắc nghiêm ngặt: Các ứng dụng chỉ phụ thuộc vào các gói, không bao giờ vào các ứng dụng khác.
Trùng lặp mã giữa các ứng dụng Tập trung mã chia sẻ trong /packages.
Cấu trúc thư mục khó hiểu Quy ước rõ ràng, dễ dự đoán cho bố cục và đặt tên thư mục.
Xây dựng & kiểm tra chậm Đồ thị bị ảnh hưởng của Nx + bộ nhớ cache thông minh = chỉ chạy những gì đã thay đổi.
Đồng bộ kiểu FE/BE dễ vỡ Gói contracts chia sẻ với Zod → FE/BE luôn an toàn kiểu.
Sự hỗn loạn môi trường Quy tắc rõ ràng cho việc xử lý .env và gói cấu hình.
Hướng dẫn lập trình viên mới mất tuần lễ Các công cụ sinh, tài liệu rõ ràng và nhãn → tăng tốc nhất quán, nhanh chóng.

Bố Cục Không Gian Làm Việc

Copy
apps/                  # Ứng dụng có thể triển khai độc lập
web/                 # Frontend React (Next.js hoặc Vite)
admin/               # Bảng điều khiển quản trị
marketing/           # Trang web tiếp thị công khai
mobile/              # Ứng dụng React Native
api-nest/            # Dịch vụ backend NestJS
api-scheduler/       # Dịch vụ công việc nền

packages/              # Mã tái sử dụng (FE & BE)
shared/
util/              # Hàm tiện ích thuần túy (không truy cập env hoặc mạng)
models/            # Mô hình TypeScript chia sẻ
contracts/         # Schem Zod + hợp đồng API
lms/                 # Miền LMS
feature/           # Điều phối trạng thái / hooks
ui/                # Thành phần UI
data-access/       # Khách hàng API (frontend) hoặc kho dữ liệu (backend)
util/              # Trợ giúp riêng cho LMS
ecommerce/           # Miền thương mại điện tử
feature/
ui/
data-access/
util/
tools/                 # Công cụ sinh Nx tùy chỉnh + script

Quy Tắc Cốt Lõi

1 — Ứng Dụng Là Độc Lập

  • Các ứng dụng sống trong /apps/.
  • Chúng không thể nhập bất kỳ thứ gì từ ứng dụng khác.
  • Chúng chỉ nhập từ /packages.
  • Điều này đảm bảo ranh giới triển khai sạch sẽ và loại bỏ sự kết nối ẩn.

Ví dụ (✅ Cho phép):

Copy
apps/web → nhập → packages/lms-ui
apps/web → nhập → packages/shared-contracts

Ví dụ (❌ Cấm):

Copy
apps/web → nhập → apps/admin
apps/admin → nhập → apps/api-nest

2 — Các Gói Là Nguồn Thông Tin Duy Nhất

  • Tất cả mã chia sẻ sống trong /packages/.
  • apps/ là các vỏ mỏng kết nối các gói và cấu hình runtime.

Đặt Tên, Nhãn & Ranh Giới

Đặt Tên Gói

Định dạng: <scope>-<type>

  • scope = miền (lms, ecommerce, shared)
  • type ∈ (feature, ui, data-access, util, models, contracts)

Ví dụ:

  • lms-ui, lms-data-access, shared-contracts.

Thực Thi Ranh Giới Với Nx

Copy
// root .eslintrc.js
rules: {
  "@nx/enforce-module-boundaries": [
    "error",
    {
      enforceBuildableLibDependency: true,
      allow: [],
      depConstraints: [
        { "sourceTag": "type:app", "onlyDependOnLibsWithTags": ["type:package"] },
        { "sourceTag": "type:ui", "onlyDependOnLibsWithTags": ["type:util","type:models","type:contracts","scope:shared","scope:<same>"] },
        { "sourceTag": "scope:shared", "onlyDependOnLibsWithTags": ["scope:shared"] }
      ]
    }
  ]
}

Hợp Đồng & Đồng Bộ FE/BE

Copy
// packages/shared/contracts/course.ts
import { z } from "zod";

export const Course = z.object({
  id: z.string().uuid(),
  title: z.string(),
  published: z.boolean(),
});

export type Course = z.infer<typeof Course>;
  • Frontend: sử dụng các schema này để kiểu hóa khách hàng API và xác thực phản hồi.
  • Backend (Nest hoặc Elysia): sử dụng schema cho xác thực đầu vào/đầu ra.

Quy Tắc Môi Trường & Cấu Hình

  • Các ứng dụng sở hữu các tệp .env của riêng mình.

  • Các gói không bao giờ được đọc trực tiếp từ process.env.

  • Tạo một gói config mà:

    • Đọc biến môi trường tại thời gian chạy.
    • Xác thực chúng bằng Zod.
    • Xuất một đối tượng cấu hình kiểu mạnh.

Bộ Nhớ Cache, Mục Tiêu & Bun

1 — Mục Tiêu Mặc Định (nx.json)

Copy
{
  "targetDefaults": {
    "build": { "cache": true },
    "test": { "cache": true },
    "lint": { "cache": true },
    "typecheck": { "cache": true }
  }
}

2 — Lệnh Bun

Copy
bun i                # Cài đặt phụ thuộc
bun run nx serve web # Chạy một ứng dụng frontend
bun run nx serve api-nest # Chạy backend
bun run nx affected -t lint,typecheck,test,build

Quy Trình Bị Ảnh Hưởng

  • Phát Triển Cục Bộ:
Copy
bun run nx affected:graph
  • Trước Khi Cam Kết:
Copy
bun run nx affected -t lint,test,typecheck
  • CI:
Copy
- run: bun run nx affected -t lint,typecheck,test,build --parallel

Chiến Lược Kiểm Tra

  • Kiểm tra đơn vị → gần nguồn trong __tests__.
  • Kiểm tra thành phần → Thư viện Kiểm tra React.
  • Kiểm tra E2E → Playwright cho các ứng dụng.
  • Kiểm tra hợp đồng → Xác thực BE dựa trên các hợp đồng Zod.

Mẹo Hiệu Suất & DX

  • Sử dụng tệp barrel (index.ts) để biên soạn các xuất khẩu của gói.
  • Giữ các gói nhỏ và tập trung vào miền.
  • Biến các gói cần tiêu thụ Node thành buildable: true.
  • Sử dụng tsup hoặc esbuild cho bản dựng backend nhỏ gọn.

Tại Sao Chọn Nx Hơn Các Đối Thủ

Tính Năng Nx Turborepo Lerna
Đồ thị phụ thuộc ✅ Tự động ❌ Thủ công ❌ Không
Lập lịch & bộ nhớ cache tác vụ ✅ Thông minh (cục bộ + từ xa) ⚠️ Hạn chế
Công cụ sinh tích hợp ✅ Có ❌ Không
Ranh giới có thể thực thi ✅ Có ❌ Không
Hỗ trợ đa ngôn ngữ (React, Elysia, Nest) ✅ Xuất sắc ⚠️ Hạn chế
Bộ nhớ cache từ xa (toàn đội) ✅ Tích hợp ⚠️ Bên thứ ba

Bảng Tóm Tắt Lệnh Nhanh

Copy
bun run nx g @nx/js:lib lms-ui --directory=lms --tags="scope:lms,type:ui,platform:browser"
bun run nx graph
bun run nx affected -t test
bun run nx serve web

Suy Nghĩ Cuối Cùng

Bằng cách thực thi những thực hành này:

  • Mỗi ứng dụng vẫn có thể triển khai và kiểm tra độc lập.
  • Logic chia sẻ sống trong các gói, không được sao chép giữa các ứng dụng.
  • Nx tự động giữ cho việc xây dựng và kiểm tra nhanh chóng ngay cả khi mã nguồn phát triển.
  • Đội ngũ có quy tắc rõ ràng, giảm thiểu sự cản trở trong việc hướng dẫn và giảm lỗi.
Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào