+3

Ngừng "chiến đấu" với `node_modules`: Hướng dẫn quản lý Monorepo hiện đại năm 2026

Nếu bạn là một lập trình viên Full-stack vào năm 2026, khả năng cao là bạn đang làm việc trong một Monorepo.

Logic của việc này là không thể phủ nhận: chia sẻ type (kiểu dữ liệu) giữa backend API và frontend client, commit nguyên tử (atomic commits), và một quy trình build thống nhất. Đó được coi là "Chén Thánh" của hiệu suất phát triển.

image.png Cho đến khi bạn nhìn vào dung lượng ổ đĩa của mình. Hoặc cố gắng chạy lệnh npm install.

Thực tế của Monorepo thường rơi vào một cuộc chiến hỗn loạn chống lại node_modules. Bạn dành hàng giờ để debug các "Phantom Dependencies" (sự phụ thuộc ma), chờ đợi các bản build lẽ ra phải được cache, và vật lộn với cơn ác mộng khi Backend cần Node 18 (LTS) trong khi Frontend lại đòi hỏi Node 22 (Current).

Đã đến lúc ngừng cuộc chiến vô nghĩa này. Năm 2026, chuỗi công cụ (toolchain) đã trưởng thành. Dưới đây là hướng dẫn hiện đại để thuần hóa con quái vật Monorepo mà không làm bạn phát điên.

1. Loại bỏ npm/Yarn, chuyển sang pnpm (hoặc Bun)

Nếu bạn vẫn đang sử dụng npm hoặc yarn (v1) cổ điển trong một monorepo, bạn đang tự làm khó mình (hard mode). Cấu trúc node_modules phẳng là công thức tạo ra "Phantom Dependencies" (code truy cập vào các gói mà nó không khai báo phụ thuộc trực tiếp) và tiêu tốn dung lượng ổ đĩa khổng lồ.

Năm 2026, tiêu chuẩn là pnpm.

image.png

  • Vị cứu tinh không gian ổ đĩa: pnpm sử dụng kho lưu trữ có thể định địa chỉ theo nội dung (content-addressable store). Nếu bạn có 100 dự án sử dụng lodash, pnpm chỉ lưu nó vào ổ đĩa một lần duy nhất.
  • Tính nghiêm ngặt: Nó sử dụng symlink để thực thi các cây phụ thuộc nghiêm ngặt. Nếu bạn không thêm nó vào package.json, bạn không thể import nó. Không còn cảnh "trên máy tôi chạy được nhưng lên CI thì chết".

Lựa chọn thay thế: Bun. Nếu dự án của bạn thuần JavaScript/TypeScript, Bun đang thu hút sự chú ý lớn như một sự thay thế trực tiếp (drop-in replacement) với tốc độ cài đặt dependency nhanh hơn theo cấp số nhân.

2. Đã giải quyết: Cơn ác mộng "Đa phiên bản" Node

Đây là nỗi đau kinh điển của Monorepo:

  • /apps/backend: Một ứng dụng NestJS yêu cầu Node 18 (do một số thư viện doanh nghiệp cũ).
  • /apps/frontend: Một ứng dụng Next.js 16 yêu cầu Node 22 trở lên.
  • /packages/shared: Một thư viện cần được biên dịch cho cả hai.

Trước đây, bạn có hai lựa chọn tồi tệ:

  1. Thể dục nhịp điệu với NVM: Liên tục gõ nvm use 18nvm use 22 trong các tab terminal khác nhau.
  2. Docker hóa mọi thứ: Chạy tất cả trong container, ngốn hết 16GB RAM và rút cạn pin laptop của bạn.

Giải pháp 2026: ServBay

Đối với các nhà phát triển trên macOS, ServBay đã nổi lên như giải pháp gọn gàng nhất cho vấn đề này. Đây là công cụ được thiết kế đặc biệt để quản lý môi trường phát triển cục bộ một cách toàn diện.

Không giống như nvm (sửa đổi đường dẫn shell và gây trễ), ServBay cung cấp các môi trường cô lập. Bạn có thể cài đặt Node 12 đến Node 24 cùng một lúc. image.png

  • Tại sao nó là siêu năng lực cho Monorepo: Bạn không cần phải Docker hóa môi trường phát triển chỉ để có được sự cô lập phiên bản. Bạn có thể chạy dịch vụ backend bằng instance Node 18 của ServBay và dev server frontend bằng instance Node 22 trên cùng một máy, native hoàn toàn, với chi phí tài nguyên bằng không (zero overhead).
  • Sự ổn định: Nó cung cấp một môi trường Node.js ổn định, được biên dịch sẵn, nghĩa là bạn ngừng phải chiến đấu với các lỗi biên dịch (như node-gyp fails) khi chuyển đổi phiên bản.

3. Hệ thống Build thông minh: Turborepo

Trong một Monorepo, chạy npm run build là một cái bẫy. Nó xây dựng lại mọi thứ một cách mù quáng. Nếu bạn chỉ thay đổi một file CSS ở frontend, tại sao bạn lại phải biên dịch lại cả backend API?

Turborepo (hoặc Nx) là bắt buộc trong năm 2026.

image.png

  • Remote Caching (Cache từ xa): Turbo ghi nhớ những gì bạn đã build. Nếu bạn hoặc bất kỳ ai trong team đã build commit này trước đó, Turbo sẽ tải xuống các artifact từ đám mây thay vì build lại.
  • Pipeline Orchestration (Điều phối luồng): Nó hiểu biểu đồ phụ thuộc (dependency graph) của bạn. Nó biết rằng shared-ui phải được build xong trước khi web-app khởi động.

Mẹo cấu hình: Định nghĩa turbo.json để xử lý các tác vụ nặng:

{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

4. Vệ sinh Dependency: Syncpack

Kẻ giết người thầm lặng của Monorepo là "Version Drift" (Trôi phiên bản).

  • Package A dùng react@19.0.0
  • Package B dùng react@19.2.0

Kết quả là có hai bản sao React trong bundle của bạn, gây phình to ứng dụng và các lỗi context khó hiểu.

image.png

Syncpack là một công cụ CLI giúp thực thi các phiên bản dependency nhất quán trên toàn bộ Monorepo của bạn.

# Xác minh rằng tất cả các package đều sử dụng cùng một phiên bản dependency chính xác
npx syncpack list-mismatches

Hãy chạy lệnh này trong quy trình CI của bạn. Nó đảm bảo rằng khi bạn nâng cấp một thư viện, bạn sẽ nâng cấp nó ở mọi nơi.

5. Tự động hóa phát hành: Changesets

Nếu bạn đang quản lý một Monorepo nơi các package được publish lên npm (hoặc private registry), việc đánh số phiên bản thủ công rất dễ gây lỗi.

image.png

Changesets tạo ra một quy trình làm việc nơi các nhà phát triển khai báo ý định của họ ("Tôi đã sửa một lỗi trong component Button") bằng một trình hướng dẫn CLI.

Khi bạn merge vào nhánh main, Changesets sẽ tự động:

  1. Tăng số phiên bản của package đã thay đổi và các package phụ thuộc vào nó.
  2. Cập nhật CHANGELOG.md.
  3. Publish lên npm / registry.

Tổng kết

Monorepo là kiến trúc được lựa chọn cho năm 2026, nhưng nó đòi hỏi một chuỗi công cụ hiện đại.

  1. pnpm: Để tiết kiệm dung lượng ổ đĩa.
  2. Turborepo: Để tiết kiệm thời gian (caching).
  3. ServBay: Để tiết kiệm sự tỉnh táo của bạn (quản lý môi trường Node.js).
  4. Syncpack: Để giữ cho dependencies sạch sẽ.

Hãy ngừng chiến đấu với công cụ. Nâng cấp tech stack của bạn và quay lại với việc viết code đi thôi.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí