Điều gì xảy ra khi bạn chạy các lệnh npm?

Bạn nhấn Enter cho một lệnh npm. Dự án của bạn được build. Cảm giác như có phép màu vậy.

Đó không phải là phép màu. Đó là một chuỗi các yêu cầu mạng, phân tích mã nguồn và tối ưu hóa tệp tin.

Đừng chạy các lệnh một cách mù quáng. Thay vào đó, hãy hiểu rõ bộ máy vận hành chúng.

Dưới đây là những gì diễn ra đằng sau 6 lệnh cốt lõi mà bạn sử dụng hàng ngày.

  1. npm install

Lệnh này đọc tệp package.json của bạn. Nó kết nối với một cloud registry để tìm các phiên bản phù hợp cho các công cụ của bạn.

  • Nó tải các package từ registry.
  • Nó tạo thư mục node_modules.
  • Nó xây dựng một cây phụ thuộc (dependency tree).
  • Nó cập nhật package-lock.json để ghi lại các phiên bản chính xác.
  1. npm run format:check

Đây là một bước kiểm tra. Nó kiểm tra xem mã nguồn của bạn có tuân thủ các quy tắc định dạng (style rules) hay không mà không làm thay đổi bất cứ điều gì.

  • Nó xây dựng một bố cục ảo cho các tệp của bạn.
  • Nó so sánh các tệp của bạn với các quy tắc như Prettier.
  • Nó đánh dấu lỗi nếu khoảng trắng hoặc cú pháp của bạn không đúng.

Để khắc phục các lỗi này, hãy chạy npm run format. Lệnh này sử dụng Prettier để viết lại các tệp của bạn theo đúng định dạng.

  1. npm run lint

Hãy coi đây là một trình kiểm tra lỗi chính tả cho mã nguồn của bạn. ESLint tìm kiếm các lỗi làm hỏng logic của bạn.

  • Nó tìm các lỗi cú pháp.
  • Nó xác định các biến không được sử dụng.
  • Nó phát hiện các import bị thiếu.
  • Nó đánh dấu việc sử dụng React Hook không chính xác.
  1. npm run build

Lệnh này chuẩn bị ứng dụng của bạn để đưa ra môi trường thực tế. Nó tạo ra một thư mục dist.

  • Nó sử dụng một bundler để thực hiện tree shaking. Việc này sẽ xóa bỏ những đoạn mã bạn đã import nhưng chưa bao giờ sử dụng.
  • Nó thực hiện minification. Việc này loại bỏ các khoảng trắng và đổi tên các biến để tiết kiệm dung lượng (bytes).
  • Nó xử lý CSS và các tài nguyên (assets).
  • Nó xuất ra các tệp tĩnh đã được tối ưu hóa, sẵn sàng để đưa lên máy chủ.
  1. npm run dev

Lệnh này khởi động máy chủ phát triển (development server) cục bộ của bạn. Nếu bạn sử dụng Vite, nó sẽ sử dụng Native ES Modules.

  • Nó chỉ biên dịch các tệp khi trình duyệt của bạn yêu cầu chúng.
  • Nó sử dụng WebSockets cho Hot Module Replacement (HMR).
  • Nó thay đổi mã nguồn vừa chỉnh sửa trong trình duyệt của bạn ngay lập tức mà không cần tải lại toàn bộ trang.
  1. npm run preview

Hãy sử dụng lệnh này để kiểm tra kỹ lại công việc của bạn trước khi deploy. Lệnh này bỏ qua mã nguồn của bạn và chỉ xem xét thư mục dist.

  • Nó mô phỏng cách ứng dụng của bạn hoạt động trên Vercel hoặc AWS.
  • Nó chạy bản build production của bạn trên một máy chủ cục bộ.

Terminal không phải là một chiếc hộp đen. Khi bạn hiểu rõ các công cụ của mình, bạn sẽ debug nhanh hơn.

Lệnh nào đã thay đổi quy trình làm việc của bạn sau khi bạn hiểu cách nó vận hành? Hãy cho tôi biết ở bên dưới.

Phép màu dưới Terminal: Điều gì thực sự xảy ra khi bạn chạy các lệnh npm

Bạn đã bao giờ tự hỏi điều gì thực sự diễn ra đằng sau những dòng chữ chạy vèo vèo trên màn hình terminal khi bạn gõ một lệnh như npm install chưa? Nó có vẻ đơn giản, nhưng thực tế là một chuỗi các quy trình phức tạp diễn ra trong tích tắc.

Hãy cùng bóc tách lớp vỏ này để xem "phép màu" thực sự là gì.

1. Shell: Người đưa thư đầu tiên

Khi bạn mở terminal và gõ npm install, người đầu tiên nhận được thông tin không phải là npm. Đó là Shell (như Bash, Zsh, hoặc PowerShell).

Shell đóng vai trò là giao diện giữa bạn và hệ điều hành. Nhiệm vụ của nó là:

  • Đọc lệnh: Nó lấy những gì bạn vừa gõ.
  • Tìm kiếm (Lookup): Nó tìm kiếm trong biến môi trường PATH để xem npm là gì. Nếu nó tìm thấy một tệp thực thi có tên npm, nó sẽ bắt đầu quá trình.
  • Thực thi: Nó tạo ra một tiến trình (process) mới để chạy lệnh đó.

2. npm CLI: Bộ não điều khiển

Sau khi Shell tìm thấy npm, nó sẽ khởi chạy npm CLI (Command Line Interface). Lúc này, npm bắt đầu làm việc.

npm không chỉ là một công cụ tải tệp; nó là một trình quản lý gói (package manager) thông minh. Nó có nhiệm vụ đọc các tệp cấu hình của bạn, chủ yếu là package.json.

3. Quy trình giải quyết phụ thuộc (Dependency Resolution)

Đây là phần "ma thuật" nhất. Khi bạn chạy npm install, npm sẽ thực hiện các bước sau:

Bước A: Phân tích package.json

npm nhìn vào danh sách dependenciesdevDependencies để biết bạn cần những gì.

Bước B: Xây dựng cây phụ thuộc (Dependency Tree)

Đây là nơi mọi thứ trở nên phức tạp. Gói A có thể cần gói B, và gói B lại cần gói C. npm phải xây dựng một bản đồ (graph) khổng lồ để đảm bảo tất cả các phiên bản đều tương thích với nhau.

Bước C: Kiểm tra package-lock.json

Nếu tệp package-lock.json tồn tại, npm sẽ ưu tiên sử dụng thông tin trong đó. Tệp này đảm bảo rằng mọi người trong nhóm phát triển đều cài đặt chính xác cùng một phiên bản của các gói, tránh lỗi "nhưng trên máy tôi vẫn chạy được!".

4. Tải xuống và Cài đặt

Sau khi đã có bản đồ hoàn chỉnh, npm sẽ:

  1. Kiểm tra bộ nhớ đệm (Cache): Nó kiểm tra xem các gói này đã có sẵn trong máy bạn chưa (trong thư mục cache của npm). Nếu có, nó sẽ lấy từ đó để tiết kiệm thời gian.
  2. Tải xuống (Fetching): Nếu không có trong cache, nó sẽ gửi yêu cầu đến npm Registry (một kho lưu trữ khổng lồ trên internet) để tải các gói về.
  3. Giải nén và đưa vào node_modules: Các gói được tải về dưới dạng tệp nén, sau đó được giải nén và đặt vào thư mục node_modules trong dự án của bạn.

5. Thư mục node_modules: Kho chứa khổng lồ

Thư mục node_modules là nơi chứa tất cả mã nguồn của các thư viện mà dự án của bạn phụ thuộc vào. Đôi khi, thư mục này có thể trở nên cực kỳ lớn vì nó chứa không chỉ các gói bạn yêu cầu mà còn cả các phụ thuộc của các phụ thuộc đó (transitive dependencies).

Tóm tắt quy trình

Bước Thành phần Hành động
1 Shell Nhận lệnh và tìm npm trong PATH.
2 npm CLI Đọc package.json và bắt đầu quy trình.
3 Resolution Xây dựng cây phụ thuộc và kiểm tra package-lock.json.
4 Registry/Cache Tải gói từ internet hoặc lấy từ bộ nhớ đệm.
5 File System Giải nén và lưu vào node_modules.

Kết luận

Lần tới khi bạn gõ npm install, hãy nhớ rằng đó không chỉ là một lệnh đơn giản. Đó là sự phối hợp nhịp nhàng giữa Shell, hệ thống tệp, mạng internet và một thuật toán giải quyết phụ thuộc cực kỳ phức tạp. Hiểu được quy trình này sẽ giúp bạn trở thành một nhà phát triển giỏi hơn, đặc biệt là khi gặp phải các lỗi liên quan đến phiên bản hoặc cài đặt.