Ở các phần trước chúng ta đã trải nghiệm với việc sử dụng công cụ NPM để cài đặt framework, các công cụ (gọi chung là các gói), cũng đã làm quen với khái niệm cài đặt cục bộ (local), toàn cục (global) trong môi trường Nodejs.
Phần này chúng ta sẽ cùng tìm hiểu kĩ hơn về các khái niệm trên, đồng thời rút ra được kinh nghiệm trong việc lựa chọn kiểu cài đặt cho phù hợp.
Ngoài ra, thực hành nhiều sẽ giúp bạn có kỹ năng tốt, dễ nhớ và dễ hiểu về công nghệ.
Để thực hành, chúng ta sẽ tạo mới một ứng dụng (ví dụ kieu-cai-dat):
- Trong ổ đĩa E:\, tạo thư mục có tên kieu-cai-dat
- Mở cửa sổ dòng lệnh, di chuyển dấu nhắc chuột tới kieu-cai-dat
- Dùng lệnh npm init -y để tạo tập tin package.json cho ứng dụng
E:\kieu-cai-dat>npm init -y
Wrote to E:\kieu-cai-dat\package.json:
{
"name":
"kieu-cai-dat",
"version":
"1.0.0",
"main":
"index.js",
"scripts": {
"test":
"echo \"Error: no test specified\" && exit 1"
},
"keywords":
[],
"author":
"",
"license":
"ISC",
"description":
""
}
Chúng ta đã tạo ra được tập tin package.json trong thư mục dự án. Tập tin package.json sẽ ghi lại thông tin của các gói được cài đặt theo kiểu cục bộ.
Dấu hiệu để nhận ra một gói được cài theo kiểu cục bộ là thông tin của gói sẽ được lưu trong package.json.
Do chúng ta chưa cài bất kỳ gói nào cho dự án (kieu-cai-dat) theo kiểu cục bộ, nên package.json chưa có thông tin gì về gói cục bộ.
[package.json]
{
"name": "kieu-cai-dat",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error:
no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}
Cài đặt một gói kiểu cục bộ
Một gói cục bộ sẽ được cài đặt bằng lệnh npm theo cú pháp sau:
npm install <package_name>
Ví dụ, chúng ta sẽ cài đặt gói Express theo kiểu cục bộ vào dự án kieu-cai-dat
E:\kieu-cai-dat>npm install
express
added 69 packages, and audited 70
packages in 9s
14 packages are looking for
funding
run `npm fund` for
details
found 0 vulnerabilities
Một gói được cài đặt theo kiểu cục bộ, thì bạn chỉ có thể sử dụng ở trong phạm vi của dự án. Như vậy, bạn chỉ có thể sử dụng gói Express trong dự án kieu-cai-dat, nếu bạn tạo một dự án khác (ví dụ kieu-cai-dat-2) thì dự án mới tạo sẽ không sử dụng được gói Express trong dự án kieu-cai-dat.
Chúng ta sẽ lấy phạm vi thư mục dự án (kieu-cai-dat) làm giới hạn để xác định giữa cục bộ và toàn cục. Cái gì nằm trong dự án thì gọi là cục bộ, nằm ngoài dự án thì gọi là toàn cục.
Do Express được cài đặt theo kiểu cục bộ, nên thông tin về gói này sẽ được ghi lại trong tập tin package.json, mục dependencies:
[package.json]
"description": "",
"dependencies": {
"express": "^4.21.2"
}
Vị trí lưu trữ gói cục bộ
Khi một gói được cài đặt theo kiểu cục bộ, mã nguồn của gói sẽ được lưu trong dự án (kieu-cai-dat), tại thư mục node_modules.
Mỗi khi dự án có
sử dụng các gói cục bộ, Nodejs sẽ tìm kiếm gói tương ứng trong thư mục
node_modules.
Nội dung thư mục node_modules sẽ thay đổi khi bạn thực hiện lệnh cài đặt/gỡ bỏ gói bằng lệnh npm.
Gỡ bỏ một gói cục bộ
Để gỡ bỏ gói Express, sử dụng lệnh:
npm uninstall <package_name>
Ví dụ:
E:\kieu-cai-dat>npm uninstall express
removed 69 packages, and audited
1 package in 1s
found 0 vulnerabilities
Sau khi gỡ bỏ gói Express, mục dependencies trong package.json cũng được cập nhật lại.
Cài đặt một gói kiểu toàn cục (global)
Để cài đặt một gói kiểu toàn cục, sử dụng lệnh npm install có thêm tham số -g
npm install <package_name> -g
Tham số (hay cờ) -g là viết tắt của global.
Ví dụ, chúng ta sẽ cài đặt gói nodemon theo kiểu toàn cục.
E:\kieu-cai-dat>npm install nodemon -g
changed 29 packages in 4s
4 packages are looking for funding
run `npm fund` for details
Mặc dù đã cài đặt thành công nodemon, nhưng vào kiểm tra trong tập tin package.json, sẽ không thấy có thông tin được cập nhật. Vì chỉ có cài gói theo kiểu cục bộ thì mới được cập nhật vào package.json.
Vị trí lưu trữ gói toàn cục
Sau khi cài đặt thành công, để biết được gói toàn cục được lưu ở đâu trong máy tính, sử dụng lệnh sau:
npm root -g
Ví dụ:
E:\kieu-cai-dat>npm root -g
C:\Users\Teo\AppData\Roaming\npm\node_modules
Theo đường dẫn C:\Users\Teo\AppData\Roaming\npm\node_modules, bạn sẽ thấy được gói nodemon.
Để xem các gói đã được cài đặt theo kiểu toàn cục trên máy tính, sử dụng lệnh sau:
npm ls -g --depth 0
Ví dụ:
E:\kieu-cai-dat>npm ls -g --depth 0
C:\Users\Teo\AppData\Roaming\npm
+-- nodemon@3.1.9
`-- pnpm@10.4.1
Trong đó,
- npm ls: để liệt kê các gói đã được cài đặt trên máy, ls là viết tắt của list
- -g là cờ báo, để chỉ hiển thị các gói kiểu toàn cục (global)
- --depth 0: chỉ hiển thị các gói toàn cục cấp cao nhất
(top-level), không hiển thị các gói là con-cháu (sub-dependencies) của gói cấp cao nhất
Nên cài đặt gói theo kiểu cục bộ hay toàn cục
Trong quá trình phát triển ứng dụng web, việc quyết định cài đặt một gói là cục bộ hay toàn cục phụ thuộc vào mục đích sử dụng của gói đó và cách bạn muốn tích hợp nó vào ứng dụng hoặc hệ thống của mình.
Các trường hợp nên cài gói cục bộ:
- Khi gói chỉ cần thiết cho một dự án cụ thể và không cần sử dụng ở phạm vi rộng hơn
- Khi bạn muốn các phụ thuộc (dependencies) của dự án được quản lý chặt chẽ trong tập tin package.json, giúp dễ dàng tái tạo môi trường phát triển ở máy khác (ví dụ: khi chia sẻ mã nguồn hoặc triển khai)
- Khi gói là một phần của ứng dụng hoặc thư viện mà bạn đang phát triển (ví dụ: express)
Các trường hợp nên cài gói toàn cục:
- Khi gói là công cụ dòng lệnh (CLI) hoặc tiện ích mà bạn muốn sử dụng ở bất kỳ đâu trong hệ thống, không phụ thuộc vào dự án cụ thể (ví dụ: nodemon)
- Khi bạn cần chạy gói như một lệnh độc lập từ cửa sổ dòng lệnh mà không cần viết script trong package.json
Một số lưu ý
[1] Ưu tiên cài cục bộ khi có thể: ngay cả với các công cụ dòng lệnh như eslint hay prettier, bạn vẫn có thể cài cục bộ và chạy chúng thông qua script trong package.json. Điều này giúp đảm bảo mọi thành viên trong nhóm hoặc môi trường CI/CD sử dụng cùng phiên bản. Ví dụ: thay vì cài nodemon toàn cục, bạn có thể cài cục bộ và chạy npx nodemon app.js.
[2] Khi nào cần cả hai? Đôi khi bạn muốn cài toàn cục để tiện sử dụng cá nhân, nhưng vẫn cài cục bộ cho dự án để đảm bảo tính nhất quán. Ví dụ: bạn cài typescript toàn cục để chạy lệnh tsc nhanh chóng, nhưng vẫn thêm nó vào devDependencies của dự án.
[3] Tránh lạm dụng cài toàn cục: chỉ nên cài toàn cục cho các công cụ thực sự cần thiết ở phạm vi hệ thống. Việc cài quá nhiều gói toàn cục có thể dẫn đến khó quản lý và xung đột phiên bản.
7.2 Dependencies và devDependencies
Nhắc lại, chỉ có các gói được cài đặt theo kiểu cục bộ (trong dự án), thì mới được cập nhật thông tin trong package.json, trong mục dependencies và devDependencies.
Như vậy, dependencies và devDependencies là hai phần trong tập tin package.json, dùng để quản lý các gói mà dự án của bạn phụ thuộc vào. Sự khác biệt giữa chúng nằm ở mục đích sử dụng và giai đoạn mà chúng được yêu cầu trong vòng đời của dự án.
Các gói nằm trong mục dependencies
- Là các gói cần thiết để ứng dụng của bạn chạy trơn tru trong môi trường sản xuất, triển khai (production). Đây là những phụ thuộc "cốt lõi" mà mã nguồn của bạn trực tiếp sử dụng để hoạt động.
- Là một phần không thể thiếu trong xử lý logic của ứng dụng, ví dụ: framework express, thư viện xử lý HTTP, truy vấn cơ sở dữ liệu
- Khi người khác cài đặt dự án của bạn bằng lệnh npm install, các gói trong dependencies sẽ được tải về, vì chúng cần thiết để chạy ứng dụng
Ví dụ:
"dependencies": {
"express": "^4.21.2"
}
Cách cài đặt một gói là dependencies
Sử dụng lệnh sau:
npm install <package-name> --save
Lưu ý: từ npm phiên bản 5 trở lên, --save là mặc định, nên bạn chỉ cần dùng lệnh sau:
npm install <package-name>
Các gói nằm trong mục devDependencies
- Là các gói chỉ cần thiết trong quá trình phát triển ứng dụng (development) hoặc kiểm thử (testing), không cần thiết khi ứng dụng chạy ở môi trường sản xuất, triển khai (production)
- Khi gói là công cụ hỗ trợ lập trình viên, như công cụ kiểm tra cú pháp (linter), trình biên dịch (transpiler), framework kiểm thử (testing framework), hoặc công cụ khởi động server trong lúc thử nghiệm (nodemon)
- Khi cài đặt ứng dụng lên môi trường triển khai (production), các gói trong devDependencies sẽ không được cài đặt, giúp giảm dung lượng và tăng hiệu suất
Ví dụ:
"devDependencies": {
"nodemon": "^3.0.1",
}
Cách cài đặt một gói là devDependencies
Sử dụng lệnh sau:
npm install <package-name> --save-dev
7.3 Bài tập
Bài tập 7.1 Thực hiện các cài đặt trong bài học.
Câu 7.2 Trong môi trường phát triển ứng dụng Nodejs, phát biểu nào không đúng khi nói về gói cục bộ?
A. Gói cục bộ được cài đặt trong thư mục node_modules của dự án
B. Gói cục bộ chỉ có thể được sử dụng trong dự án mà nó được cài đặt
C. Gói cục bộ được quản lý thông qua file package.json và có thể sử dụng các phiên bản khác nhau giữa các dự án
D. Gói cục bộ luôn được cài đặt toàn cục trên hệ thống để tất cả các dự án đều có thể truy cập
Câu 7.3 Trong môi trường phát triển ứng dụng Nodejs, phát biểu nào không đúng khi nói về gói toàn cục?
A. Gói toàn cục luôn được liệt kê trong tập tin package.json của dự án
B. Gói toàn cục thường được sử dụng cho các công cụ dòng lệnh (CLI) như nodemon
C. Gói toàn cục được lưu trong thư mục toàn cục của hệ thống và có thể truy cập từ bất kỳ dự án nào
D. Gói toàn cục được cài đặt bằng lệnh npm install -g <package-name>
Câu 7.4 Trong môi trường phát triển ứng dụng Nodejs, phát biểu nào không đúng khi nói về kiểu cài đặt dependencies?
A. Các gói trong dependencies được cài đặt cục bộ trong dự án bằng lệnh npm install <package-name>
B. Các gói trong dependencies là các phụ thuộc cần thiết để ứng dụng chạy trong môi trường triển khai, sản xuất (production)
C. Các gói trong dependencies chỉ được sử dụng trong giai đoạn phát triển và không cần thiết khi triển khai ứng dụng (production)
D. Các gói trong dependencies được liệt kê trong tập tin package.json và tự động cài đặt khi chạy npm install
Câu 7.5 Trong môi trường phát triển ứng dụng Nodejs, phát biểu nào không đúng khi nói về kiểu cài đặt devDependencies?
A. Các gói trong devDependencies được cài đặt bằng lệnh npm install <package-name> --save-dev
B. Các gói trong devDependencies là các phụ thuộc cốt lỗi để ứng dụng chạy trong môi trường triển khai (production)
C. Các gói trong devDependencies chỉ cần thiết trong giai đoạn phát triển hoặc kiểm thử, không cần cho môi trường triển khai (production)
D. Các gói trong devDependencies không được cài đặt khi chạy npm install --production
----
Gợi ý làm bài tập
Câu 7.2(D), 7.3(A), 7.4(C), 7.5(B)