Cẩm Nang Cú Pháp Composer & NPM: Phân Biệt @ vs : và ~ vs ^
Khi làm việc với các dự án Web Development- đặc biệt là Fullstack với Laravel và Vue/React- chúng ta thường xuyên phải cài đặt các thư viện (packages). Tuy nhiên, không ít lập trình viên gặp tình trạng gõ nhầm cú pháp dẫn đến lỗi lệnh, hoặc không hiểu rõ các ký tự phiên bản làm dự án bị xung đột dependency.
Bài viết này sẽ giải thích trọn vẹn và dễ nhớ nhất 2 cặp ký tự hay gây nhầm lẫn nhất: @ vs : và ~ vs ^.
Phần 1: Phân Biệt Cú Pháp Cài Đặt — @ hay :?
Điểm khác biệt cốt lõi ở đây nằm ở Công cụ quản lý gói (Package Manager) mà bạn đang sử dụng.
1. Dấu A-còng (@) — Dành Cho Node.js (NPM / Yarn / Pnpm)
Trong hệ sinh thái JavaScript/Node.js, dấu @ được dùng để phân tách giữa Tên Package và Phiên Bản.
Cú pháp:
npm install <package-name>@<version>Ví dụ:
npm install axios@1.6.0 npm install vue@latest
Lưu ý nhỏ: Nếu thấy dấu
@ở đầu tên package (ví dụ:@types/nodehay@angular/core), đó không phải là phiên bản, mà là Scoped Package (package thuộc về một tổ chức/nhóm cụ thể).
npm install @angular/core@17.0.0
@angular/core: Tên package thuộc tổ chức@angular.
@17.0.0: Phiên bản17.0.0.
2. Dấu Hai Chấm (:) — Dành Cho PHP (Composer)
Trong hệ sinh thái PHP, Composer sử dụng dấu hai chấm : để phân tách tên package và phiên bản.
Cú pháp:
composer require <vendor>/<package>:<version>Ví dụ:
composer require laravel/framework:^11.0 composer require spatie/laravel-permission:^6.0
💡 Mẹo nhớ nhanh:
JS / Node.js >> Dùng @ (nhớ đến Email / Social tag).
PHP / Composer >> Dùng : (nhớ đến cú pháp
Key: ValuehayNamespace::classtrong PHP).
Phần 2: Quản Lý Phiên Bản Semantic — ^ (Caret) vs ~ (Tilde)
Trước khi đi vào ^ và ~, chúng ta cần nhớ lại quy chuẩn đặt tên phiên bản Semantic Versioning (SemVer) gồm 3 chữ số: MAJOR.MINOR.PATCH (Ví dụ: 1.2.3).
MAJOR (
1): Nhảy số khi có thay đổi lớn, có thể làm hỏng code cũ (Breaking Changes).MINOR (
2): Nhảy số khi thêm tính năng mới nhưng vẫn tương thích ngược với code cũ.PATCH (
3): Nhảy số khi sửa lỗi (Bug fixes) hoặc nâng cấp bảo mật nhỏ.
Cả Composer và NPM đều dùng chung quy tắc của ^ và ~ để quyết định phạm vi được phép tự động nâng cấp package khi bạn chạy composer update hoặc npm update.
1. Dấu ^ (Caret) — Mặc Định & Linh Hoạt
Dấu ^ cho phép tự động cập nhật các bản Minor và Patch, nhưng KHÔNG nhảy bản Major.
Ý nghĩa: "Hãy cập nhật miễn sao không làm hỏng app của tôi (không nhảy Major)."
Ví dụ:
^1.2.3Được phép cập nhật up to:
>= 1.2.3và< 2.0.0Phiên bản sẽ nhận:
1.2.4,1.3.0,1.9.9.Phiên bản bị chặn:
2.0.0.
Trường hợp ngoại lệ (
0.x.x): Đối với các package chưa ra mắt bản chính thức (dưới1.0.0), các bản Minor vẫn có thể chứa breaking changes. Do đó^0.2.3sẽ chỉ cho phép cập nhật Patch (từ>= 0.2.3đến< 0.3.0).
2. Dấu ~ (Tilde) — An Toàn & Thận Trọng
Dấu ~ khóa chặt hơn: Nó chỉ cho phép tự động cập nhật chữ số cuối cùng được khai báo (thường là bản vá lỗi Patch).
Ý nghĩa: "Tôi chỉ muốn nhận các bản vá lỗi nhỏ, giữ nguyên bộ tính năng hiện tại."
Ví dụ 1 (Khai báo đủ 3 số - Phổ biến nhất):
~1.2.3Được phép cập nhật up to:
>= 1.2.3và< 1.3.0Phiên bản sẽ nhận:
1.2.4,1.2.9.Phiên bản bị chặn:
1.3.0(chặn Minor).
Ví dụ 2 (Khai báo 2 số):
~1.2Lúc này chữ số cuối cùng được khai báo là Minor (
2), nên nó cho phép nhảy Minor: từ>= 1.2.0đến< 2.0.0.
Bảng So Sánh Nhanh
| Cú pháp | Khai báo | Phạm vi phiên bản được phép tự động nâng cấp |
| ^1.2.3 | 1.2.3 | >= 1.2.3 và < 2.0.0 (Tự động cập nhật Patch + Minor) |
| ~1.2.3 | 1.2.3 | >= 1.2.3 và < 1.3.0 (Chỉ tự động cập nhật Patch) |
| 1.2.3 | 1.2.3 | Đúng duy nhất bản 1.2.3 (Khóa cứng, không cập nhật) |
Tóm Lại: Nên Dùng Khi Nào?
Dùng
^(Caret): Cho hầu hết các package thông thường. Bạn muốn ứng dụng liên tục nhận được tính năng mới và bản sửa lỗi mà vẫn an toàn khỏi các lỗi rủi ro do đổi kiến trúc (Major break).Dùng
~(Tilde): Cho các thư viện Core quan trọng của hệ thống (ví dụ: Core Framework, Payment SDKs, Crypto...) nơi bạn cần sự ổn định tuyệt đối và chỉ muốn nhận các bản vá lỗi/bảo mật khẩn cấp.
Hi vọng bài viết giúp bạn làm chủ được các cú pháp cài đặt package và quản lý dependency cho dự án của mình một cách chuyên nghiệp hơn!