· pnpm / nodejs / package-manager

pnpm 10 đánh giá — có gì mới và có đáng nâng cấp không?

pnpm 10 chặn lifecycle scripts của dependency theo mặc định — đây là thay đổi breaking duy nhất. Những gì thực sự thay đổi, ai nên nâng cấp và ai nên chờ.

Bởi · Cập nhật 31 tháng 5, 2026

1.084 từ · 6 phút đọc

Nếu bạn đang bắt đầu dự án mới hoặc muốn isolation nghiêm ngặt hơn cho dependency, hãy nâng cấp pnpm 10 ngay. Nếu quá trình cài đặt của bạn phụ thuộc vào postinstall scripts của các package bên thứ ba, hoặc bạn chạy linter từ monorepo root, hãy dành nửa ngày để audit và thêm allowlist trước khi bump version.

Bài này dành cho ai

Developer Node.js đang quản lý dependency bằng pnpm — cá nhân, team, hay monorepo — và đang cân nhắc xem v10 có xứng đáng với công sức migration không. Nếu bạn đang dùng pnpm 8 trở xuống, hãy đọc changelog của v9 trước. Nếu đang cân nhắc giữa các package manager, xem thêm pnpm vs npm hoặc pnpm vs Yarn.

Những gì thay đổi trong pnpm 10

Lifecycle scripts bị chặn theo mặc định

Đây là thay đổi duy nhất sẽ phá vỡ hầu hết dự án ngay lần install đầu tiên.

pnpm 10 không còn thực thi lifecycle scripts (postinstall, prepare, preinstall) cho bất kỳ dependency nào trừ khi bạn chủ động cho phép. Release notes viết thẳng:

“Lifecycle scripts of dependencies are not executed during installation by default! This is a breaking change aimed at increasing security.”

Động cơ đằng sau thay đổi này rất thực tế. postinstall là vector tấn công phổ biến nhất trong các cuộc tấn công supply chain: một package bị compromise có thể chạy code tùy ý trên máy của mọi developer và mọi CI runner khi cài đặt. pnpm 10 đóng khe hở đó theo mặc định.

Để bật lại scripts cho các package thực sự cần — native modules, bất cứ thứ gì cần compile C++ hoặc tải binary về lúc install — thêm allowlist vào package.json:

{
  "pnpm": {
    "onlyBuiltDependencies": ["esbuild", "sharp", "@img/sharp-darwin-arm64"]
  }
}

Nếu bạn không chắc package nào cần postinstall, chạy pnpm approve-builds (có từ v10.1.0):

pnpm approve-builds

CLI tương tác sẽ liệt kê từng package có build script và cho bạn phê duyệt hoặc từ chối từng cái. Từ v10.32, pnpm approve-builds --all phê duyệt tất cả trong một lần — tiện trong giai đoạn migration khi bạn muốn khôi phục hành vi cũ tạm thời để tiến hành audit sau.

public-hoist-pattern giờ rỗng

Ở pnpm 9 và trước đó, các package eslintprettier được tự động hoist lên node_modules/.bin tại workspace root. Tính năng đó đã bị bỏ.

“Nothing is hoisted by default. Packages containing eslint or prettier in their name are no longer hoisted.”

Các monorepo chạy eslint từ root qua script như "lint": "eslint ." sẽ thấy lỗi Cannot find module 'eslint' hoặc eslint: command not found. Cách sửa: cài eslint trực tiếp ở root, hoặc cấu hình public-hoist-pattern trong .npmrc:

public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*

Store version tăng lên v10

Content-addressable store chuyển sang dùng SHA256 xuyên suốt và có cấu trúc thư mục index/ mới. Lần install đầu tiên sau khi nâng cấp pnpm, một số package có thể tải lại khi pnpm điều chỉnh format store cũ sang mới. Đây là chi phí một lần duy nhất. Store cũ tại ~/.pnpm-store/v3 (v9) không bị xóa tự động — chạy pnpm store prune khi bạn chắc chắn việc nâng cấp đã ổn định.

Hiệu năng

Trang benchmark của pnpm.io (kiểm tra ngày 31/05/2026) ghi nhận install JS-baseline với cache + lockfile + node_modules đạt khoảng 449ms. Phiên bản Rust engine của pnpm (pnpm 🦀) xử lý cùng kịch bản đó trong 56ms — nhanh hơn khoảng 8 lần.

Một lưu ý: tài liệu chính thức không công bố so sánh JS-baseline side-by-side giữa v9 và v10. Con số 449ms phản ánh throughput của v10 hiện tại, không phải mức chênh lệch so với v9.

Hướng dẫn nâng cấp

  1. Cập nhật packageManager trong package.json:

    { "packageManager": "[email protected]" }
  2. Chạy pnpm install và đọc kỹ output. pnpm sẽ liệt kê các package có lifecycle scripts bị chặn.

  3. Chạy pnpm approve-builds để quyết định tương tác package nào cần build scripts. Các lựa chọn được ghi vào pnpm.onlyBuiltDependencies trong package.json.

  4. Sửa hoisting nếu workspace của bạn chạy linter từ root. Thêm chúng vào public-hoist-pattern trong .npmrc, hoặc cài tooling trực tiếp tại workspace root. Để bootstrap monorepo pnpm + Turborepo đúng cách, xem Cách thiết lập monorepo pnpm + Turborepo từ đầu.

  5. Cập nhật CI. Nếu pipeline đang set PNPM_HOME hoặc dùng pnpm setup action, bump version ở đó luôn. Ví dụ với GitHub Actions:

    - uses: pnpm/action-setup@v4
      with:
        version: 10
  6. Kiểm tra issue #9082 nếu bạn đang chạy shared-workspace-lockfile=false. Tại thời điểm viết bài, onlyBuiltDependencies không hoạt động đúng với cấu hình đó. Giải pháp tạm thời là bật lại scripts toàn cục với enable-pre-post-scripts=true trong .npmrc cho các package bị ảnh hưởng, rồi theo dõi issue upstream để chờ bản sửa chính thức.

Không có trang migration chính thức tại pnpm.io/migration/v10 — nguồn tham khảo thực tế là release notes v10.0.0 trên GitHub. Cũng không có codemod tự động (có codemod cho v10→v11, nhưng không có cho v9→v10).

Kết luận

Nâng cấp ngay nếu:

  • Bạn đang bắt đầu dự án mới.
  • Bạn muốn bảo vệ nghiêm ngặt hơn khỏi supply-chain attacks — việc chặn lifecycle scripts là cải thiện bảo mật có thực chất.
  • Bạn đã quản lý danh sách onlyBuiltDependencies tường minh từ trước.

Chờ thêm nếu:

  • Pipeline cài đặt của bạn phụ thuộc vào nhiều postinstall scripts của bên thứ ba chưa được audit.
  • Bạn đang chạy linter từ monorepo root và chưa có thời gian giải quyết vấn đề hoisting.
  • Bạn dùng shared-workspace-lockfile=false với cấu hình workspace phức tạp, chờ issue #9082 được đóng.

Những điều cần lưu ý

  • Chúng tôi không kiểm tra trên Windows. pnpm vốn có vài vấn đề lẻ tẻ trên Windows liên quan đến symlink — hãy tự xác minh trên môi trường đó.
  • Không có số liệu so sánh JS-baseline giữa v9 và v10 từ team pnpm tại thời điểm đăng bài. Con số 449ms là throughput của v10, không phải mức cải thiện đo được so với v9.
  • Affiliate links: không có. pnpm là open-source.

Tài liệu tham khảo