Có một sự im lặng kỳ lạ trong căn phòng đầy những lập trình viên đang chờ đợi quá trình build hoàn tất. Ánh mắt họ lơ đãng nhìn sang màn hình phụ. Ngón tay lướt điện thoại. Ai đó đứng dậy đi lấy một tách cà phê mà thực ra họ chẳng hề muốn. Nếu bạn từng dành thời gian làm việc với một codebase JavaScript hiện đại, bạn sẽ hiểu khoảng lặng này. Đó không phải là một lúc nghỉ ngơi. Đó là một lỗ hổng trong luồng tư duy của bạn.

Chúng ta nói rất nhiều về các framework. React, Vue, Svelte, và bất cứ thứ gì sắp ra mắt vào tuần tới đều thu hút mọi sự chú ý. Các hội thảo luôn cháy vé nhờ những thông báo về framework mới. Các bài viết trên blog mổ xẻ về syntax sugar. Nhưng đằng sau tất cả những ồn ào hướng tới người dùng đó, nền tảng đang thay đổi theo cách sẽ thực sự thay đổi cách bạn viết code. Cuộc cách mạng không đến từ một frontend framework. Nó đang diễn ra ở lớp công cụ (tooling layer), và nó đang được viết bằng Rust và Go.

Trong nhiều năm, các công cụ JavaScript được xây dựng bằng chính JavaScript. Điều đó hoàn toàn hợp lý. Babel đã dạy cả một thế hệ cách viết cú pháp của tương lai ngay từ hôm nay. Webpack đóng gói các phần code tách biệt của chúng ta thành thứ mà trình duyệt có thể xử lý được. ESLint bắt lỗi trước khi chúng ta commit chúng. Những công cụ này được thiết kế cho một web quy mô nhỏ hơn. Chúng giả định chỉ có vài trăm module, chứ không phải mười nghìn. Chúng giả định các repo đơn lẻ, chứ không phải các monorepo nơi mà một thay đổi trong một package UI dùng chung có thể gây ảnh hưởng dây chuyền đến hàng tá ứng dụng khác.

Rồi các ứng dụng lớn dần lên. Các codebase nở rộ thành những kho lưu trữ khổng lồ. Các công cụ vẫn giữ nguyên, và độ trễ bắt đầu len lỏi vào. Một lần hot reload vốn chỉ mất hai giây đã trở thành mười hai giây, rồi ba mươi giây. Việc chạy toàn bộ bộ test trước giờ ăn trưa trở thành một điều xa xỉ. Các linter thì vấp váp trên những file mà chúng đã kiểm tra hàng nghìn lần. Trên lý thuyết, mỗi sự chậm trễ đều có vẻ nhỏ. Nhưng thực tế, những khoảng dừng này làm tan vỡ sự tập trung. Chúng rèn luyện bạn thói quen gom nhóm công việc, khiến bạn do dự trước khi kiểm tra xem một bản sửa lỗi đã hoạt động chưa, và khiến bạn tránh né việc thử nghiệm vì chi phí nhận phản hồi quá cao.

Thế hệ công cụ tiếp theo giải quyết độ trễ đó bằng cách đơn giản là không còn cản trở JavaScript nữa.

Buồng máy mới

Hãy nhìn vào cách các tác vụ cụ thể đang được giành lại quyền kiểm soát.

Transformation trước đây đồng nghĩa với Babel. Nó là bộ tiền xử lý vạn năng, chuyển đổi JSX và các đề xuất stage-3 thành ES5 thuần túy. Nó vẫn là một phần mềm ấn tượng, nhưng nó là JavaScript đơn luồng đang phân tích chính JavaScript. Hãy làm quen với OXC, một bộ công cụ dựa trên Rust. Nó xử lý các tác vụ tương tự như Babel, nhưng các kết quả benchmark cho thấy nó nhanh hơn khoảng 40 lần trong khi tiêu thụ ít hơn 70% bộ nhớ. Đó không phải là một sự cải tiến nhỏ giọt. Đó là sự khác biệt giữa một công cụ mà bạn nhận thấy sự hiện diện và một công cụ mà bạn quên mất là nó đang chạy.

Bundling là nơi nỗi đau hiện rõ nhất. Webpack đã là tiêu chuẩn trong một thập kỷ, nhưng cấu trúc bên trong của nó được xây dựng cho một quy mô khác. Turbopack, người kế nhiệm bằng Rust của nó, không chỉ biên dịch lại nhanh hơn. Nó dựa vào cơ chế memoization mạnh mẽ để hiểu chính xác những gì đã thay đổi và chỉ xây dựng lại phần đó. Trong một ứng dụng lớn, việc thay đổi một component duy nhất không nên khiến bạn phải tốn công duyệt lại toàn bộ đồ thị. Với Turbopack, quá trình build tiến gần đến mức tức thì. Thanh tiến trình biến mất vì chẳng còn gì để chờ đợi.

Testing cũng mang lại sự trì trệ riêng. Jest đã định nghĩa lại việc kiểm thử JavaScript, nhưng trong chế độ watch, nó có cảm giác như đang phải học lại codebase của bạn sau mỗi lần nhấn phím. Vitest tiếp cận theo một hướng kiến trúc khác. Vì nó tái sử dụng đồ thị module của Vite thay vì tự xây dựng cây phụ thuộc từ đầu, nó báo cáo tốc độ nhanh hơn khoảng 8,5 lần so với Jest trong chế độ watch. Chiến thắng ở đây không chỉ là tốc độ thuần túy. Đó là sự nhất quán. Trình chạy test và máy chủ phát triển (dev server) của bạn cuối cùng cũng thống nhất về cấu trúc dự án của bạn.

Linting cũng chịu sự quá tải tương tự. Sự linh hoạt của ESLint chính là siêu năng lực của nó; các quy tắc của nó chỉ là các hàm JavaScript hoạt động trên một AST. Sự linh hoạt đó tiêu tốn tài nguyên. Oxlint, được viết bằng Rust, thu hẹp phạm vi vào các trường hợp phổ biến và chạy cực nhanh. Nó chạy nhanh hơn từ 50 đến 100 lần so với ESLint. Hiệu quả thực tế là việc linting sẽ hoàn tất trước cả khi hiệu ứng lưu file của trình soạn thảo kết thúc. Bạn sẽ không còn phải chịu đựng những đường gạch chân đỏ cứ lởn vởn trong vài giây sau khi bạn đã sửa xong lỗi.

Có lẽ sự chuyển dịch mang tính biểu tượng nhất đang diễn ra trong việc kiểm tra kiểu (type checking). Microsoft hiện đang viết lại trình biên dịch TypeScript bằng ngôn ngữ Go. Các kết quả đo lường hiệu năng (benchmark) ban đầu rất ấn tượng: VS Code tải nhanh hơn khoảng 8 lần với bản triển khai mới, và bản thân việc kiểm tra kiểu cũng nhanh hơn xấp xỉ 10 lần. Hãy cân nhắc ý nghĩa của điều đó. TypeScript là một câu chuyện thành công của JavaScript. Nó là một ngôn ngữ biên dịch sang JavaScript, được dùng để kiểm tra kiểu cho các hệ sinh thái JavaScript, và giờ đây chính trình biên dịch của nó đang chuyển sang một ngôn ngữ hệ thống (native systems language) vì JavaScript không thể đáp ứng được hiệu năng mà hệ sinh thái yêu cầu. Công cụ này đang tự phá vỡ giới hạn của chính mình để đạt được tốc độ.

Không điều nào trong số này thay thế React. Nó không khai tử Next.js hay làm cho TypeScript trở nên lỗi thời. Các framework vẫn định nghĩa mô hình component và routing của bạn. Những công cụ mới này đơn giản là làm cho mọi thứ bên dưới chạy nhanh hơn. Chúng là con đường, không phải là chiếc xe.

Khi Tốc độ Thay đổi Hành vi

Các cuộc thảo luận về công cụ thường bị mắc kẹt trong các biểu đồ benchmark. Các con số thì dễ so sánh. Nhưng tác động thực sự nằm ở hành vi của con người.

Khi phản hồi giảm từ giây xuống mili giây, bạn không chỉ hoàn thành công việc nhanh hơn. Bạn hoàn thành chúng theo một cách khác. Bạn ngừng tích trữ các thay đổi. Bạn viết một dòng code, xem kết quả, rồi điều chỉnh. Bạn chạy test vì chúng diễn ra tức thì, chứ không phải vì pull request yêu cầu. Bạn thử nghiệm việc refactor mà có thể không hiệu quả vì việc hoàn tác (undo) chẳng tốn chút chi phí nào. Bạn duy trì sự tập trung vào vấn đề thay vì phải chờ đợi máy móc cho phép bạn quay trở lại.

Đây là điều mà các nhà tâm lý học gọi là trạng thái "flow" (dòng chảy). Nó đòi hỏi một vòng lặp chặt chẽ giữa hành động và hệ quả. Một tay guitar không thể chơi nhạc nếu chiếc amp làm trễ mọi nốt nhạc. Một họa sĩ không thể pha màu nếu cây cọ cập nhật chậm nửa giây. Các nhà phát triển cũng không ngoại lệ. Độ trễ không chỉ là một sự phiền toái. Nó là một loại "thuế" đánh vào tư duy.

Do đó, sự gia tăng năng suất không chỉ thuần túy về mặt kỹ thuật. Nó mang tính thói quen. Công cụ nhanh rèn luyện bạn cách thử nghiệm. Công cụ chậm rèn luyện bạn cách do dự. Qua một năm, sự khác biệt đó sẽ tích tụ thành những phần mềm hoàn toàn khác biệt. Đội ngũ có phản hồi tức thì sẽ triển khai (ship) sản phẩm tự tin hơn. Họ chia nhỏ công việc vì chi phí cho việc thử nghiệm là bằng không. Các đợt code review của họ ngắn lại vì lỗi được phát hiện ngay tại thời điểm đó, chứ không phải trong CI hai mươi phút sau đó.

Công việc Vô hình

Đây là lý do tại sao các tiêu đề báo chí thường gây hiểu lầm. Các framework rất dễ để viết về chúng. Chúng có logo, có API và có cả những drama trên Twitter. Cơ sở hạ tầng (infrastructure) được thiết kế để vô hình. Bạn không thức dậy với sự hào hứng để cấu hình một bundler. Bạn muốn nó biến mất. Nhưng biến mất chính xác là những gì một cơ sở hạ tầng tốt thực hiện. Nó gánh vác sức nặng để lớp hiển thị có thể luôn nhẹ nhàng.

Nếu bạn đang dẫn dắt một đội ngũ hoặc duy trì một codebase cũ (legacy), điều này nên được đưa vào các ưu tiên của bạn. Chuyển đổi từ React sang Vue có thể định hình lại cây component của bạn. Chuyển đổi từ Webpack sang Turbopack hoặc từ Babel sang OXC có thể định hình lại toàn bộ ngày làm việc của bạn. Vế sau là một câu chuyện khó thuyết phục ban quản lý hơn vì không có bản demo trang chủ mới nào cả. Chỉ có một đội ngũ không còn thở dài trước màn hình terminal khi build nữa thôi.

Hãy kiểm tra xem điều gì thực sự đang làm chậm bạn. Nếu bạn đang chạy một monorepo hiện đại trên một bộ công cụ (toolchain) được xây dựng từ năm 2015, bạn không phải đang thận trọng đâu. Bạn đang phải trả một loại "thuế ma sát" hàng ngày. Cách khắc phục không phải là học một mô hình frontend mới. Mà là thay thế động cơ.

Các framework sẽ tiếp tục xuất hiện. Chúng sẽ tiếp tục nhận được các tweet và các bài diễn thuyết tại hội nghị. Nhưng sự chuyển dịch thực sự trong cảm giác khi viết JavaScript đang diễn ra ở bên dưới lớp vỏ, trong các ngôn ngữ biên dịch vốn coi thời gian của bạn là vô giá. Đó mới là cuộc cách mạng. Không phải là một cách mới để render một danh sách, mà là một bộ công cụ đủ nhanh để không cản trở bạn và để bạn có thể tập trung tư duy.