Bàn về câu lệnh npm run build - tại sao cần phải build?

Bàn về câu lệnh npm run build - tại sao cần phải build?

Tin ngắn hàng ngày dành cho bạn
  • Void - cái tên mình đã nhắc đến từ cách đây khá lâu. Từ đợt mà continue.dev mới nổi lên á. Nó tương tự như Cursor và Windsurf, mới hôm nay họ đã phát hành phiên bản Beta và cho phép mọi người tải xuống.

    Điểm mạnh thì đây là nguồn mở, miễn phí, dùng các mô hình miễn phí cục bộ trên máy qua Ollama hoặc LM Studio... Không thích thì cắm API của bên khác vào cũng được. Mình vừa dùng thử thì thấy khả năng gợi ý và khung chat khá tương đồng với Cursor, có cả tính năng Agent luôn nhé 👏. Hoạt động ổn định hơn continue.dev (lần cuối dùng), việc còn lại là chọn mô hình xịn xịn tí 🤤

    » Xem thêm
  • Zed mới đây đã giới thiệu thêm tính năng Agent - tương tự như Agent trong Cursor hay Write trong Windsurf và họ gọi nó là The Fastest AI Code Editor.

    Cũng nhanh thật đấy vì Zed viết bằng Rust. Cơ mà chiến lược của họ có vẻ thay đổi, tập trung vào AI thay vì phát triển kho tiện ích mở rộng vốn đang có rất ít, không thể cạnh tranh được với VSCode 🥶

    Zed: The Fastest AI Code Editor

    » Xem thêm
  • Ngay sau thông tin OpenAI đạt được thoả thuận mua lại Windsurf với giá 3 tỉ đô thì ngày hôm nay Cursor đã miễn phí 1 năm dùng bản Pro cho sinh viên. Chaaaaà 🤔

    OpenAI Reaches Agreement to Buy Startup Windsurf for $3 Billion

    Cursor for Students | Cursor - The AI Code Editor

    » Xem thêm

Vấn đề

npm run build một câu lệnh không quá xa lạ với các lập trình viên JavaScript khi chuẩn bị phát hành phiên bản mới cho ứng dụng. Theo cách hiểu đơn giản, npm run build thực hiện công việc chuyển đổi mã trong dự án thành mã có thể chạy được trong trình duyệt hoặc Node.js.

Nhưng tại sao lại cần phải có bước build? Bản chất của việc build là gì? Có phải tất cả dự án JavaScript/Node.js cần phải build hay không? Hy vọng bạn đọc sẽ tìm được câu trả lời trong bài viết dưới đây.

NPM Scripts

package.json là một tệp quan trọng có trong hầu hết dự án JavaScript/Node.js. Chức năng của nó là lưu trữ thông tin dự án cũng như cấu hình và các lệnh sẽ được sử dụng. Lấy ví dụ, package.json lưu lại tất cả các thư viện để mỗi khi cần cài đặt các gói phụ thuộc (dependencies) chỉ cần chạy npm install.

scripts là một thuộc tính trong package.json, nó lưu giữ các giá trị trông giống như dưới đây:

{
  "scripts": {
    "dev": "vite",
    "tsc": "vue-tsc --noEmit",
    "build": "npm run tsc && vite build",
    "build-dev": "vue-tsc --noEmit && vite build --mode development",
    "serve": "vite preview"
  }
}

Khi đó nếu chúng ta gõ npm run build thì ở bên dưới câu lệnh thực sự được chạy đó chính là vue-tsc --noEmit && vite build. Nói cách khác build chỉ là tên đại diện cho câu lệnh thực sự muốn chạy. Nếu bây giờ tôi không thích build, đổi tên nó thành release cũng không thành vấn đề. Nếu muốn chạy, chỉ cần gõ npm run release. npm run release lúc này cũng giống như npm run build trước đó.

scripts sinh ra để che giấu đi sự phức tạp trong việc nhớ các câu lệnh sẽ được sử dụng trong dự án. Ở ví dụ trên, việc ghi nhớ npm run build so với vue-tsc --noEmit && vite build theo bạn thì cái nào dễ hơn? Trong một dự án không chỉ sử dụng một lệnh duy nhất mà con số có khi lên đến cả hàng chục. Chúng còn có khả năng móc nối đến nhau, nghĩa là lệnh này bằng nhiều lệnh khác cộng lại. Đấy là lúc scripts phát huy tác dụng là một nơi hoàn hảo để lưu trữ lại các giá trị.

Hãy nhìn vào dòng lệnh build trên, nó là sự kết hợp của tscvite build. Tạo ra nhiều lệnh ở cấp độ phân tử giúp bạn có thể tái sử dụng. Việc đặt tên cho chúng mang lại ý nghĩa gợi nhớ. Hãy hình dung khi mở package.json ở bất kỳ dự án nào ra mà thấy có build trong scripts thì chắc hẳn đó chính là lệnh có liên quan đến việc sắp sửa phát hành một phiên bản mới cho ứng dụng.

Sự phức tạp của giới Trình duyệt/Node.js

Sự phức tạp của giới trình duyệt/Node.js

Bản thân JavaScript mang nhiều sự phức tạp, nhiều khi bạn không thể hiểu nổi tại sao typeof null == 'object' và vô số những điều vô lý đến thuyết phục khi làm việc với nó. Để giải thích thì có nhiều lý do, một trong số đó là sự phân mảnh của JavaScript. Nếu như với các ngôn ngữ khác, muốn sử dụng chỉ cần tải bản cài đặt về rồi cài vào máy là xong. Sau khi viết mã, muốn triển khai ứng dụng lên máy chủ thì chỉ cần sử dụng đúng phiên bản đã cài đặt trước đó là gần như chắc chắn thành công.

JavaScript thì ngược lại, cho phép chạy mã JavaScript hay không là quyền thuộc về trình duyệt. Mà trình duyệt thì có rất nhiều loại và không phải cái nào cũng tuân thủ theo quy tắc của JavaScript. Nếu như JavaScript phát hành một phiên bản mới thì trình duyệt ngay sau đó phải tung bản cập nhật để hỗ trợ. Điều gì xảy ra nếu người dùng không chịu cập nhật trình duyệt, hoặc trình duyệt không mặn mà với việc chạy đua theo các tính năng mới nhất của JavaScript? Nói cách khác, một đoạn mã JavaScript chạy được trên trình duyệt này chưa chắc đã chạy trên trình duyệt khác. Điều đó khiến cho lập trình viên JavaScript phải vò đầu bứt tai khi giải quyết bài toán "Hỗ trợ tối đa người dùng Internet".

Node.js hạn chế được sự phân mảnh hơn, vì nó chỉ sử dụng V8 của Chrome. Sử dụng Node.js đồng nghĩa với việc bạn phải dùng V8. Mặt khác, Node.js chạy phía máy chủ nên không phải giải quyết bài toán khó như trình duyệt.

Nhìn lại thực tế, không phải người dùng nào cũng có phiên bản trình duyệt mới nhất. Không phải tất cả đều sử dụng Chrome hay Firefox... Lập trình viên luôn e ngại rằng liệu mã sắp viết ra đây có tương thích với tất cả người dùng? Ý tưởng của các công cụ hỗ trợ viết một lần - dùng cho tất cả xuất hiện từ đây.

Có thể bạn đã nghe nói đến babel.js, đây là thư viện chuyển đổi mã JavaScript mới hơn về mã mà hầu hết các trình duyệt có thể chạy được. Hiểu đơn giản nếu bạn muốn dùng các cú pháp JavaScript mới nhất mà vẫn có thể chạy được trên các trình duyệt cũ thì babel.js giúp làm điều đó. Tất cả điều cần làm là cài đặt babel, viết mã rồi sử dụng nó để chuyển đổi mã bạn vừa viết. Đó là lúc lệnh build xuất hiện. Trong build có thể là câu lệnh có sử dụng babel như ví dụ dưới đây.

{
  "scripts": {
    "build": "babel src -d lib"
  }
}

Với sự ra đời của nhiều Framework hỗ trợ xây dựng ứng dụng dựa trên phản ứng như Angular, React, Vue... càng làm xuất hiện thêm nhiều công cụ chuyển đổi mã hơn nữa. Về cơ bản, các Framework che giấu sự phức tạp khi phát triển và cho đến lúc phát hành bằng những công cụ như webpack, rollup, vite... Điều đó giúp cho nhà phát triển ứng dụng tập trung vào công đoạn viết mã nhiều hơn so với việc đi trả lời câu hỏi liệu ứng dụng của tôi có chạy tốt trên IE8?

Có phải tất cả ứng dụng cần phải build?

Câu trả lời là không. Như tôi đã nói build chỉ là một tên đại diện cho câu lệnh phức tạp. Nó còn mang ý nghĩa gợi nhớ. build thường xuất hiện trong dự án có sử dụng các công cụ hỗ trợ chuyển đổi mã đơn giản thành phức tạp ví dụ như babel, hay các công cụ đóng gói như webpack, rollup...

Nếu phát triển một ứng dụng JavaScript đơn giản mà không sử dụng các công cụ trên rõ ràng bạn không cần phải qua một bước build. Trình duyệt hay Node.js có thể chạy được những đoạn mã mà bạn viết.

Tổng kết

package.json là một tệp chứa các thông số và cấu hình cho dự án JavaScript/Node.js. scripts là một thuộc tính chứa các câu lệnh được chạy tương ứng mỗi khi sử dụng npm run. scripts giúp che giấu đi sự phức tạp của câu lệnh và mang ý nghĩa gợi nhớ, build bao hàm những yếu tố đó.

Vì vậy, các dự án mà có sử dụng đến công cụ hỗ trợ chuyển đổi mã như babel, webpack... thì mới cần đến build. Ngược lại, nếu phát triển dự án đơn giản thì không nhất thiết phải có bước build nữa.

Cao cấp
Hello

Tôi & khao khát "chơi chữ"

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...