23 điểm bởi GN⁺ 2025-08-04 | 3 bình luận | Chia sẻ qua WhatsApp
  • Môi trường phát triển Node.js trong vài năm gần đây đã trải qua những thay đổi mang tính nền tảng về mức độ tương thích cao với tiêu chuẩn web và việc tăng cường các tính năng tích hợp sẵn
  • Việc áp dụng hệ thống module và các mẫu bất đồng bộ hiện đại như ESM (ES Modules), tiền tố node:, Top-level await giúp viết mã trực quan và an toàn hơn
  • Fetch API, AbortController, Web Streams giúp giảm sự phụ thuộc vào các thư viện bên ngoài trước đây, đồng thời nhiều chức năng nay đã được hỗ trợ bằng API tích hợp sẵn
  • Các công cụ phát triển tích hợp như test runner, chế độ Watch, hỗ trợ file môi trường giúp cải thiện đáng kể sự thuận tiện khi làm việc và năng suất
  • Với việc tăng cường hạ tầng bảo mật và triển khai như kiểm soát quyền hạn, kênh chẩn đoán, cho tới triển khai dưới dạng tệp thực thi đơn, Node.js hiện đại đang tiến hóa thành một nền tảng chuyên nghiệp và đa dụng

Sự thay đổi và phát triển của Node.js

  • Node.js đang chuyển mình từ cấu trúc thiên về callback, xoay quanh CommonJS ở giai đoạn đầu thành một môi trường phát triển được chuẩn hóa hơn ngày nay
  • Sự thay đổi này không chỉ là thay đổi bề ngoài, mà còn là sự thay đổi trong toàn bộ mô hình phát triển của JavaScript phía máy chủ

1. Hệ thống module: Chuẩn hóa ES Modules

  • CommonJS là cách làm đã được dùng lâu dài trong Node.js, nhưng có những hạn chế như phân tích tĩnh, tree shaking và sự không tương thích với tiêu chuẩn web
  • Cách tiếp cận ESM (ES Modules) đã trở thành tiêu chuẩn mới của Node.js
    • Sử dụng cú pháp import, export
    • Áp dụng tiền tố node: để phân biệt rõ module tích hợp sẵn
      • Ví dụ: import { readFile } from 'node:fs/promises'
      • Việc phân biệt module tích hợp sẵn với gói npm trở nên rõ ràng hơn
  • Nhờ hỗ trợ Top-level await, có thể dùng await ngay ở cấp cao nhất của module
    • Không cần bọc bằng hàm bất đồng bộ tự thực thi nữa
    • Mã nguồn trở nên tuyến tính và dễ hiểu hơn

2. Web API tích hợp sẵn: Giảm phụ thuộc bên ngoài

  • Fetch API đã được tích hợp vào Node.js, cho phép gửi yêu cầu HTTP mà không cần phụ thuộc bên ngoài như Axios hay node-fetch
  • Fetch mặc định hỗ trợ timeout và hủy tác vụ (AbortSignal.timeout())
    • Có thể xử lý lỗi nhất quán mà không cần thư viện timeout riêng
  • Với AbortController, có thể triển khai mẫu hủy trong nhiều tác vụ bất đồng bộ như tệp và mạng
    • Cung cấp cách làm chuẩn hóa cho ngắt từ người dùng hoặc quá thời gian chờ

3. Kiểm thử tích hợp sẵn: Môi trường test chuyên nghiệp

  • Không còn nhất thiết phải dùng các framework bên ngoài như Jest hay Mocha; test runner tích hợp sẵn của Node.js có thể đáp ứng phần lớn nhu cầu
    • Viết test trực quan với node:testnode:assert
  • Các tính năng tiện lợi cho phát triển như chế độ Watch cho testbáo cáo coverage cũng được tích hợp sẵn
    • Tự động chạy lại test mỗi khi sửa mã
    • Node.js 20 trở lên cung cấp tính năng coverage ở trạng thái thử nghiệm

4. Các mẫu bất đồng bộ đã tiến hóa

  • async/await được dùng rộng rãi, Node.js hiện đại nhấn mạnh việc tận dụng các mẫu thực thi song song và xử lý lỗi tinh vi hơn
    • Dùng Promise.all() để chạy song song, và xử lý lỗi trong một khối try/catch duy nhất có kèm thông tin ngữ cảnh
  • Việc tận dụng AsyncIterator giúp xử lý sự kiện tuần tự và điều khiển luồng dễ dàng hơn

5. Tính năng stream nâng cao và tương thích tiêu chuẩn web

  • API stream nay đã đạt được mức tương thích với tiêu chuẩn web (Streams API)
    • Với Readable.fromWebReadable.toWeb, có thể chuyển đổi stream giữa Node.js và trình duyệt
  • Hàm pipeline (dựa trên Promise) cho phép xây dựng pipeline stream trực quan và an toàn

6. Worker Threads: Xử lý song song cho tác vụ nặng CPU

  • Dùng WorkerThreads để vượt qua giới hạn đơn luồng của JS và tận dụng đa lõi
  • Có thể xử lý các phép tính phức tạp hoặc dữ liệu lớn mà không chặn vòng lặp chính

7. Đổi mới trong trải nghiệm phát triển

  • Cờ --watch cho phép phát hiện thay đổi mã và tự động chạy lại mà không cần nodemon
  • Cờ --env-file giúp không cần dotenv, có thể dùng biến môi trường ngay lập tức
  • Việc thiết lập môi trường phát triển trở nên đơn giản và nhanh hơn

8. Tích hợp sẵn bảo mật và giám sát hiệu năng

  • Với Permission Model ở trạng thái thử nghiệm, có thể giới hạn quyền của ứng dụng như truy cập tệp hoặc mạng
    • Có lợi cho việc hiện thực nguyên tắc đặc quyền tối thiểu và tuân thủ bảo mật
  • perf_hooks cho phép đo hiệu năng tích hợp sẵn, tự động phân tích và ghi lại các tác vụ chậm

9. Hiện đại hóa triển khai và đóng gói

  • Hỗ trợ SEA (Single Executable Application) cho phép triển khai Node.js và ứng dụng thành một binary duy nhất
    • Có thể triển khai/cài đặt dễ dàng ngay cả trong môi trường không có Node.js

10. Xử lý lỗi và chẩn đoán hiện đại

  • Với các lớp lỗi có cấu trúc, có thể chứa thông tin ngữ cảnh và chẩn đoán phong phú, đồng thời truyền đối tượng lỗi nhất quán
  • diagnostics_channel cho phép truyền dữ liệu chẩn đoán dựa trên sự kiện theo nhu cầu và tự động hóa giám sát

11. Sự phát triển của phân giải module và quản lý gói

  • Với Import Maps, có thể quản lý đường dẫn nội bộ dưới các namespace riêng
    • Giúp tăng sự thuận tiện khi tách module nội bộ và refactor
  • dynamic import cho phép tải mã trong thời gian chạy và code splitting tùy theo môi trường hoặc cấu hình

Tóm tắt cốt lõi và triển vọng tương lai

  • Với Node.js, việc tuân thủ tiêu chuẩn web, tận dụng tối đa công cụ tích hợp, và áp dụng các mẫu bất đồng bộ hiện đại là rất quan trọng
  • Nền tảng này đang phát triển thành một môi trường dành cho chuyên gia với xử lý song song hiệu năng cao như Worker Threads cùng các tính năng chẩn đoán/bảo mật
  • Những tính năng mới như triển khai tệp thực thi đơnnamespace cho module giúp tăng mạnh sự thuận tiện trong vận hành
  • Các mẫu này có thể được đưa vào dần dần mà vẫn giữ tương thích với mã hiện có
  • Sau năm 2025, Node.js vẫn sẽ tiếp tục tiến hóa, và những mẫu hiện đại được giới thiệu ở đây sẽ trở thành nền tảng cho các ứng dụng hướng tới tương lai

3 bình luận

 
sanori 2025-08-07

Khi bắt đầu tạo project bằng Deno, tôi đã nghĩ kiểu như “ồ, cả chuyện này cũng làm được à”, hóa ra node.js cũng đang thay đổi theo hướng tương tự.

 
dnltmdwhd 2025-08-05

Ồ, giờ không cần dùng axios nữa, có thể dùng thẳng fetch luôn rồi

 
GN⁺ 2025-08-04
Ý kiến trên Hacker News
  • Thay đổi lớn nhất không phải là ESM mà là việc fetchAbortController đã được tích hợp sẵn trong Node; có thể bỏ axios hoặc node-fetch, giảm kích thước bundle Lambda và rút ngắn độ trễ cold start khoảng 100ms. Nếu bạn là người có thói quen npm i axios, thì các bản phát hành Node năm 2025 là lúc nên dừng lại
    • Tôi thích dùng ts-rest trên toàn bộ stack để bao quát cả gọi API lẫn kiểm chứng hợp lệ; trong số các thư viện dựa trên zod/json schema, nó nhẹ nhất mà vẫn cung cấp type safety rất vững chắc. Bạn cũng có thể cắm HTTP client mình muốn vào (trên bun, engine node thì tôi chọn fastify); dù có overhead, việc chuyển type safety lên giai đoạn biên dịch vẫn hoàn toàn xứng đáng. Không biết mọi người có lựa chọn hay ý kiến nào tốt hơn không; tôi đã tìm gần như mọi thứ có thể tìm được, nhưng chỉ ts-rest mới cân bằng được cả tính gọn nhẹ lẫn type safety
    • Tôi không thích lắm cú pháp fetch và việc phải xử lý ngoại lệ bổ sung như await response.json; dùng axios trực quan hơn nhiều. Ngay cả trong mã ví dụ, axios chỉ cần xử lý đơn giản với response.data, còn fetch thì phải tự kiểm tra status rồi parse JSON nên phiền hơn
    • Với tư cách là tác giả thư viện, việc áp dụng ESM thực ra khó khăn và đau đầu hơn nhiều, nhưng đó vẫn là một nâng cấp rất đáng giá; bản thân fetch đã rất tốt, nhưng nhờ ESM mà chúng tôi thực sự đạt được rất nhiều thứ
    • node fetch tốt hơn vì đơn giản và dễ hơn axios rất nhiều; tôi còn không biết là vẫn có người tiếp tục dùng axios
    • Tôi rất háo hức với Undici, thư viện request tích hợp sẵn; xem trang chính thức của undici
  • Giờ có thể chạy chương trình theo kiểu giới hạn quyền truy cập hệ thống tệp hoặc mạng như sau
    # Ví dụ giới hạn truy cập hệ thống tệp
    node --experimental-permission \
      --allow-fs-read=./data --allow-fs-write=./logs app.js
    
    # Ví dụ giới hạn mạng
    node --experimental-permission \
      --allow-net=api.example.com app.js
    
    Có vẻ được truyền cảm hứng từ Deno; đây là một tính năng thực sự tuyệt vời, xem tài liệu về quyền hạn của Deno
  • Giờ đã có thể tự style văn bản mà không cần cài chalk hay picocolors
    const { styleText } = require('node:util');
    
    Xem tài liệu chính thức về styleText
  • Tôi đã biết thêm nhiều thứ có thể áp dụng ngay
    1. Node đã có test tích hợp sẵn nên không nhất thiết phải dùng jest
    2. Node cũng có sẵn tính năng watch nên không còn cần nodemon
    • Tôi vẫn thích jest hơn, vì có thể dùng jest-extended
    • Tôi nghĩ hệ thống test tích hợp sẵn của Node có chất lượng kém; chỉ cần dùng thực tế vài tuần là sẽ hiểu tại sao, và ngay cả khi nêu issue thì team Node cũng không mấy quan tâm
  • Theo Matteo Collina, node fetch nội bộ sử dụng fetch của undici; vì phải tạo WHATWG web stream nên về bản chất nó chậm hơn cách request của undici,
    video YouTube được nhắc tới,
    bài blog về cách undici hoạt động
    • Với ai tò mò thì benchmark có thể xem ở đây; gần đây tôi đã test trên MacBook Pro M3 Max trong cả môi trường local lẫn mạng, và undici là tốt nhất ở local, nhưng trên mạng thì Axios lại cho kết quả nhanh hơn. Tôi không rõ chính xác lý do, nhưng trải nghiệm dùng undici trong suốt 1 năm rưỡi qua là rất xuất sắc. Nó đủ ổn định để dùng trong production, nhưng nếu muốn khai thác tối đa hiệu năng vượt trội thì nhất định phải cân nhắc theo từng bối cảnh
  • Nhờ native TypeScript transpiler của Node mà những người dùng TS giảm được rất nhiều độ phức tạp
    • Thực ra nó chỉ strip type chứ không phải transpile; những thứ như TS enum không hoạt động đúng
    • Vẫn chưa đủ để dùng thực tế; tôi không quá bận tâm đến enum, nhưng vẫn không thể import file local mà không có phần mở rộng, và cũng không thể định nghĩa class property trong constructor
    • Giờ cũng không còn cần cờ --experimental-strip-types
  • Tôi thường tình cờ biết các tính năng mới theo kiểu này; có cảm giác mơ hồ kiểu “vì nó là bản mới nhất” như khi dùng trình duyệt. Hồi trước khi chỉ làm C#, tôi rất hào hứng đọc giới thiệu các tính năng ngôn ngữ mới, nhưng giờ làm song song nhiều ngôn ngữ nên ngay cả việc theo sát một ngôn ngữ cũng không dễ. Gần như toàn là học ngẫu nhiên qua blog hoặc ảnh hưởng từ xung quanh
    • Tôi rất quan tâm tin tức về Node (V8), nên cứ 2–3 tháng lại đọc release note để theo dõi các tính năng kiểu này; đôi khi tôi cũng đọc ECMA proposals, và rất mong pipeline operator sẽ được đưa vào
  • Sau một thời gian xa rời hệ sinh thái Node rồi quay lại, tôi thấy thực sự đã có rất nhiều tính năng mới thú vị; tôi cho rằng đó là kết quả của việc Deno và Bun làm rung chuyển thị trường, khiến đội ngũ phát triển Node nỗ lực hơn hẳn
  • Node đang dần trở thành một đối thủ không hề dễ xem nhẹ trong cuộc cạnh tranh với Bun.js, Deno và các nền tảng khác; sự cạnh tranh qua lại như vậy là điều tích cực cho sự phát triển của các JS runtime
    • Thay đổi thì chậm nhưng chắc chắn và đáng mừng; dù vậy tôi vẫn nhớ hàm shell $ của Bun, vì dùng JS như một ngôn ngữ script thực sự rất tiện, và tôi không muốn phải cài cả hai runtime trên cùng một server
  • Tôi nghĩ các tính năng mới của Node, giống như trên trình duyệt, cũng có thể chia thành hai loại
    1. Công nghệ hoàn toàn mới
    2. Lớp “trang trí” được đắp lên trên những gì đã có sẵn
      Cũng thú vị khi nhìn xem mọi người đặt nặng bên nào hơn
    • Thứ là “lớp trang trí” với người này có thể lại là usability/ergonomics với người khác