[Nodejs thực chiến] Để là chuyên gia npm
Đã làm node thì ngày nào cung phải dùng npm. Việc nắm chắc npm giúp bạn quản lý dependence tốt hơn, nâng cao độ ổn định, tính bảo mật của phần mềm, cũng như hiệu suất làm việc. Sau đây mình tổng hợp một số best practices khi sử dụng npm.
1. Không tự động thay đổi version các packages.
Hãy suy nghĩ về việc dự án bạn phát triển sử dụng momentjs-x.1.4. Nhưng khi deploy tính năng này lên production version tự động tăng lên momentjs-x.1.5 và rất nhiều issue kèm theo được sinh ra. Có một số cách đảm bảo version pakages không thay đổi.
- Config file
.npmrc
:
// save this as .npmrc file on the project directory
save-exact:true
- Install đúng version
npm install <package>@<version> --save-exact
- Bỏ tiền tố
^
trong filepackage.json
{
"name": "blogss",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "3.0.0",
"moment": "^2.29.1"
}
}
Trong file ví dụ thì express sẽ không tự động tăng version còn moment thì có.
2. Install packages ở production với command npm ci
Sử dụng npm ci
thay vì npm i
có một số tiện dụng:
- Nhanh hơn gấp 2 lần
npm i
xem thêm nguyên nhân npm blog - Nếu
package.json
vàpackage-lock.json
khác nhau sẽ tự động báo lổi. Điều này tránh trường hợp nhiều người trong dự án tự thêm package hoặc tăng version trong dự án bằng các thay đổi file pakage.json, mà không thông qua npm cli. - Tự xóa follder
node modules
trước khi install. Điều này đảm bảonode modules
là sản phẩm củapackage.json
vàpackage-lock.json
.
3. Phân biệt rõ dependencies và devDependencies trong file package.json
dependencies
: Packages cần thiết cho ứng dụng ở production.devDependencies
: Packages chỉ cần thiết cho local development và testing.
Để thêm pakage và dependencies
trong file package.json
thực hiện command:
npm install <package-name> [--save-prod]
Để thêm pakage và devDependencies
trong file package.json
thực hiện command:
npm install <package-name> [--save-dev]
Có thể thực hiện bằng cách sửa file package.json
một cách thủ công.
4. Không install devDependencies khi chạy production
devDependencies
là các pakages chỉ sử dụng ở môi trường development hoặc testing. Việc phải install chúng ở production làm quá trình deploy trở nên chậm chạp hơn và còn làm ứng dụng trở nên nặng nề không cần thiết.
Để chắc chắc không install devDependencies, thì cần set NODE_ENV=production
, install bằng command npm ci
Nếu muốn xóa devDependencies
đã được install, trong trường hợp cần devDependencies
trong quá trình build thì có thể remove bằng command: npm prune --production
5. Thường xuyên kiểm tra các package đang sử dụng:
- Kiểm tra các packages bị outdated:
npm outdated [[<@scope>/]<pkg> ...]
- Kiểm tra vấn đề bảo mật
npm audit [--json] [--production] [--audit-level=(low|moderate|high|critical)]
npm audit fix [--force|--package-lock-only|--dry-run|--production|--only=(dev|prod)]
common options: [--production] [--only=(dev|prod)]
6. Ngăn chặn npm tự chạy mã độc( Updated 01/05/2025)
- Hệ thống bị tấn công bằng mã độc từ
package scripts
khi cài npm, nên mình quay lại để viết thêm phần này mong không ai bị nữa. package scripts
,lifecycle scripts
là gì ? Bạn xem trong file package.json, có cái propertiesscripts
có máy cái script ví dụ nhưstart: node index.js
đó làpackage scripts
. Trong những cái thư viện mình dùng , khi install thư viện cũng tự động chạy một số script, gọi chúng làlifecycle scripts
.- Mã độc đôi khi sẽ được cài trong trong cái script này, rất khó để phát hiện vì mã độc khởi chạy khi đang thực hiện install và chưa khởi chạy chương trình, và mã độc không có trong chương trình 🥲.
Giải pháp:
- Mì ăn liền là mình block script: dùng cờ ignore script:
npm i --ignore-scripts
. Khi ignore thì đôi khi đẻ nhiều lổi do không install được một số packages, nhưng biết sao giờ, đôi khi phải chấp nhận mất cái này được cái kia ?! - Còn giải pháp lâu dài thì dùng thư viện uy tín và cố định version như mục mình nói ở trên.
- Không dùng quyền root, hay chạy bằng docker cũng hạn chế thiệt hại rất nhiều.
Bonus. Vì sao tôi không dùng yarn
- Không phải vì yarn không tốt. Yarn được biết đến là install nhanh hơn và còn nhiều tính năng khác hay hơn. Không phải tự nhiêm mà repo github của yarn có 40k sao, trong khi npm cli chỉ có 5,5k sao. "yarn rất tốt nhưng tôi rất tiết!"
- Nguyên nhân 1: Dùng yarn nhưng vẫn phải làm việc với npm. Yarn không lưu trữ các pakages, các pakages thường dùng được npm repository lưu trử, yarn chỉ đóng vai trò tải pakages về. Bạn muốn public một package thì vẫn phải tạo tài khoản npm. Một số command về quản lý package yarn không hỗ trợ. Ví dụ common remove pakage
npm unpublish --force
), issue từ năm 2017. - Nguyên nhân 2: Dùng yarn nhưng vẫn phải cài npm
- Nguyên nhân 3: npm đủ để dùng, vì tôi code microservices. Các service có cấu trúc ngọn nhẹ với số dependence không nhiều.
Cho mình 1 upvote để có động lực viết nhiều bài hơn nhé.
All rights reserved
Bình luận
Nhiều điểm ko đồng tình với tác giả:
Bỏ
^
trong package.json. Điều này nghe có vẻ đúng vì cố định phiên bản package là điều cần thiết để source code chạy mà ko gặp vấn đề về tương thích do package thay đổi phiên bản. Tuy nhiên nó lại ko tốt trong trường hợp package cần được cập nhật bản vá, ví dụ 1.2.0 cần được cập nhật lên 1.2.2 để fix 1 lỗi bảo mật nghiêm trọng chẳng hạn. Tôi chưa tìm thấy tài liệu nào chính thống khuyến khích bỏ^
hay thêm^
,~
,... nhưng khi install 1 package kể cả bằng yarn hay npm nó đều mặc định sử dụng^
, cho thấy yarn/npm cho rằng behavior này là phù hợp nhất. Vậy cố định phiên bản package như thế nào? Đó là package-lock.json hoặc yarn.lock. Trong docs của npmjs khuyến khích commit kèm lock files.Sử dụng npm thay vì yarn. Tác giả có thể dùng npm thay vì yarn tùy sở thích, tuy nhiên mọi người nên nhớ yarn sinh ra để cải thiện tốc độ của npm. Từ node 16.10 trở đi, yarn được tích hợp sẵn trong Corepack, chả cần phải cài yarn riêng từ npm nữa. Mà kể có phải tốn thêm 1 vài phút để cài yarn để tiết kiệm được nhiều phút cho nhiều project khác cũng vẫn đáng. Cũng giống như dùng IE để tải chrome về, tác giả thích dùng IE thì cứ tự nhiên, chả có vấn đề gì mà mọi người phải dùng IE thay vì chrome cả.
Nếu package update bạn phải biết vì sao nó update, nó update có ảnh hướng đến ứng dụng hay không thì bạn mới thực hiện việc update đó. Làm sao bạn biết package đó update để vá lỗi bảo mật nghiêm trọng ? Nếu update tạo ra lô hổng bảo mật nghiệm trọng như các ví dụ này thì sao.-> -> https://github.com/veged/coa/issues/99 -> https://github.com/dominictarr/rc/issues/131 Lệnh
npm i
mặc định -> Không có nghĩa là đủ tốt. Lệnhnpm i
có 3 cái không tối ưu -> thêm tất cả package và nhóm dependency, trong khi có thể thêm vào devDependence nếu có config, -> Thêm tự động thêm tiền tế^
tự động update pakage. -> chậm hơn so vớinpm ci
. Npm để mặc định như vậy để đảm bao đơn giản -> dể dùng -> phù hợp với trình độ mới học và fressher, chạy môi trường dev. Giống như docker vậy, default install latest version của image khi run vậy. Về tài liệu thì bạn có thể xem ở nodebestpractices https://github.com/goldbergyoni/nodebestpractices. Repo với 75k sao trên gihub. Đảm bao uy tín nhé.Về yarn thì mình đã nói rồi yarn tốt và nhanh. Mình cũng không phản đối ai dùng yarn hết. Nhưng usercase của mình đang làm việc là yarn không phù hợp. Vì yarn không thay thế được 100% cho npm, việc mình làm hằng ngày như làm việc với package trên npm như public, unpublic... yarn hỗ trợ kém. Ví dụ như không có command
unpublish
.Cảm ơn bạn đà phản hồi/
Phần cài đặt ko có devDependencies mình thường dùng
npm i --production
thay vì set env.vâng bạn, có nhiều cách, tinh thần là không để chung thôi.