Pnpm là gì? So sánh với npm/yarn thì như thế nào?
Bài viết giới thiệu tổng quan về pnpm, những ưu và nhược điểm của package manager này. Trong tương lai, mình sẽ viết bài viết để trình bày quá trình migrate từ npm/yarn sang pnpm
Pnpm là gì?
- Theo trang chủ pnpm.io, thì cụm từ này là viết tắt của cụm "performant npm", dịch ra tiếng Việt là: "npm hiệu suất cao". Chỉ cần nghe tên thôi, thì bạn cũng biết là mục đích của pnpm là gì rồi đấy 😹 (cho những bạn chưa biết thì
npm
là viết tắt của cụm từ "node package manager"). - Fun fact là tác giả của
pnpm
đã phát triển công cụ này ở thời điểm màyarn
chưa xuất hiện. Cũng có thể đó là lí do tại sao tác giả lại đặt cái tên làpnpm
🤔
Pnpm có ưu điểm gì
Tiết kiệm bộ nhớ
Giả sử bạn đang có 10 project trên máy, nếu sử dụng npm
thì bạn sẽ có tổng cộng 10 thư mục node_modules
nặng hơn hố đen vũ trụ 😸.
Nhưng với pnpm
thì khác, pnpm
giới thiệu 1 nơi gọi là content-addressable store
như bạn có thể thấy ở hình bên dưới.
Có thể nhận thấy, pnpm
không lưu package vô thư mục node_modules
, mà lưu ở content-addressable store
(bạn có thể hiểu nó như là một global store). Vì thế, ở node_modules
của các project dùng pnpm, thì thực chất, các package sẽ link đến real path ở global store.
Nhờ thế, mà ta giảm được việc phải tải đi tại lại những package giống nhau khi init một project mới. Đó là lí do tại sao pnpm
tiết kiệm bộ nhớ hơn npm/yarn
pnpm
cũng có chế độ offline như yarn, vì các package đã lưu ở global store, nên hoàn toàn có thể truy cập trong điều kiện network offline
Tốc độ cài đặt nhanh chóng
Pnpm cài đặt thông qua 3 bước như sau:
- Dependency resolution: các dependency cần thiết sẽ được tải về store (chính là cái
content-addressable store
mình đề cập ở trên) - Directory structure calculation: xây dựng cấu trúc thư mục node_modules dựa trên các dependency
- Linking dependencies: hard linked các dependency từ store vào node_modules
Cách này sẽ nhanh hơn so với cách cài đặt truyền thống (npm) đó là: resolving, fetching, and writing tất cả các dependency vào node_modules
Dễ dàng nhận thấy, pnpm
đạt được tốc độ cài đặt nhanh nhờ vào việc không có blocking time giữa các step. Điều này là do sự khác biệt giữa approach của pnpm với npm và yarn
Thư mục node_modules ở dạng non-flat
Trước hết phải đặt câu hỏi tại sao npm lại theo hướng flat node_modules? 🤔
Ngược dòng thời gian, quay về quá khứ trước khi npm version 3 ra mắt, lúc này, node_modules ở npm vẫn đang ở dạng non-flat. Như ví dụ ở dưới: (để ý là bên trong foo
cũng có 1 thư mục node_modules có chứa dependency là bar
)
node_modules
└─ foo
├─ index.js
├─ package.json
└─ node_modules
└─ bar
├─ index.js
└─ package.json
Cách tiếp cận này đã nảy sinh các vấn đề như:
- Xảy ra vấn đề long directory path trên hệ điều hành windows, vì package tạo ra cây dependency quá "sâu"
- Packages bị duplicate ở nhiều nơi, vì là depenency của các package khác ----> bạn tưởng tượng hiện tại
node_modules
đã rất là nặng rồi, nếu issue này không được giải quyết thì nó còn kinh khủng cỡ nào 😾
Vì vậy, để giải quyết vấn đề này, npm quyết định flat node_modules. Từ sau npm version 3, cấu trúc thư mục node_modules sẽ trở thành vầy:
node_modules
├─ foo
| ├─ index.js
| └─ package.json
└─ bar
├─ index.js
└─ package.json
Như bạn có thể thấy, tuy bar
là dependency của foo
, chứ không phải của project. Nhưng bar
vẫn được để cùng cấp với foo
. Cá nhân mình thấy việc flat như vầy làm cho cái node_modules nó rối rắm vì có quá nhiều dependency
Trong cuộc sống hàng ngày, một problem sinh ra thì sẽ có rất nhiều cách giải quyết. Và cách giải quyết của pnpm không giống với npm. Thay vì flat như npm, pnpm vẫn keep non-flat structure mà vẫn giải quyết được các vấn đề ở trên.
Cũng là 2 package foo
và bar
, khi dùng pnpm thì ta sẽ có thư mục node_modules như sau:
node_modules
├─ foo -> .registry.npmjs.org/foo/1.0.0/node_modules/foo
└─ .registry.npmjs.org
├─ foo/1.0.0/node_modules
| ├─ bar -> ../../bar/2.0.0/node_modules/bar
| └─ foo
| ├─ index.js
| └─ package.json
└─ bar/2.0.0/node_modules
└─ bar
├─ index.js
└─ package.json
---------------------------------------
->: a symlink (or junction on Windows)
Như bạn đã thấy ở trên,
- Package
foo
là một symlink dẫn tới.registry.npmjs.org/foo/1.0.0/node_modules/foo
. Khi execute, node sẽ tìm tới real path của package và run. - Package
foo
vẫn chứa dependency của nó làbar
ở dạng symlink. Và điều đặc biệt làfoo
không có node_modules ở bên trong, bằng cách này cây dependency của foo sẽ không "sâu" như ở npm trước khi release v3.
Nhìn sơ thì cấu trúc có vẻ phức tạp, nhưng khi ở những project lớn bạn sẽ thấy structure này sẽ clear hơn so với npm/yarn.
Nhược điểm của pnpm
- Tốc độ cài đặt của
pnpm
có thể sẽ chậm hơnnpm/yarn
ở lần cài đặt package đầu tiên - Vì
pnpm
có dùngsymlink
nên sẽ gây ra ra một số vấn đề liên quan đến permission khi dùng ở hệ điều hành Windows - Cấu trúc non_flat
node_modules
có thể không tương thích với một số package cũ - Hiện tại thì mình chỉ thấy pnpm có nhược điểm là như vậy, bạn có thể bổ sung cho mình ở phần bình luận, cảm ơn bạn
Cài đặt
Bạn có thể đọc thêm ở đây: https://pnpm.io/installation
Giống như cách install yarn
npm install -g pnpm
Các câu lệnh cùng tương đồng với npm
hay yarn
nên bạn cứ tự do mà khám phá.
Ngoài ra, nếu bạn thắc mắc về content-addressable store
mà mình đã đề cập ở trên, bạn có thể sử dụng câu lệnh sau để tìm ra path của store:
pnpm store path
Showcase
pnpm được khá nhiều công ty lớn sử dụng, đây cũng có thể coi như là bằng chứng cho hiệu quả của pnpm (bạn xem thêm ở đây https://pnpm.io/users)
Kết bài
Cảm ơn bạn đã đọc đến đây, như bạn có thể thấy pnpm là một tool khá hiệu quả để quản lí package cho node. Hãy thử pnpm
để tận hưởng nhưng ưu điểm của nó mang lại nhé.
Bài viết trên được mình tham khảo từ các nguồn ở dưới, nếu bạn thấy bài viết này 'quen quen' thì hẳn là bạn đã đọc những bài viết ở dưới rồi.
Tài liệu tham khảo
All rights reserved