Turbopack Dev is Now Stable

Bài tóm tắt Vercel 2024 4. Điều chỉnh Độ khó: Khó

Vercel · 2024 · 4. Điều chỉnh · Độ khó: Khó — bài gốc

Vercel vừa làm framework Next.js vừa bán nền tảng chạy nó; nhận định về sản phẩm của họ trong trang này đều là "theo Vercel". Bài phát hành tính năng nhưng có phần kiến trúc dài; giữ phần kiến trúc.

Bối cảnh

  • Sau 8 năm, webpack (nền bundling của Next.js) không theo kịp: chờ route biên dịch, chờ thay đổi code hiện lên, chờ build. Theo Vercel, họ đã bỏ nhiều công tối ưu webpack nhưng lợi ích giảm dần, và cần nền mới cho Server Components.
  • Yêu cầu đặt ra cho bundler mới: ít breaking change, hỗ trợ cả App và Pages Router, nhanh cho mọi cỡ codebase, dev gần với production, tối ưu production nâng cao (tree shaking trong module), một đồ thị module cho nhiều môi trường (Node.js và browser), quan sát được toàn bộ.
  • Đo trên vercel.com (app Next.js lớn, theo Vercel): khởi động server dev nhanh hơn tới 76,7%, Fast Refresh nhanh hơn tới 96,3%, biên dịch route lần đầu (không cache đĩa) nhanh hơn tới 45,8%.

Thay đổi chính

  • Một compiler cho nhiều môi trường: với webpack, Next.js chạy ít nhất hai compiler (server rồi browser, vì phải biên dịch server trước để tìm các "use client"), nên có chi phí phối hợp và parse cùng code hai lần. Turbopack coi "chuyển môi trường" (server ↔ browser) là một transition ngay trong đồ thị nên bundle cả Server Component, Client Component và Server Function trong một lượt.
  • Song song theo CPU: webpack dùng nhiều object JS lớn khó chia sẻ giữa thread (serialize tốn kém), nên chỉ biến đổi SWC chạy song song; Turbopack viết bằng Rust, thiết kế song song từ đầu.
  • Fast Refresh theo kích thước thay đổi, không theo kích thước app: theo Vercel, với webpack, tới khoảng 30.000 module thì mỗi lần sửa luôn mất ít nhất 1 giây (đổi màu một file CSS cũng vậy) vì phải duyệt đồ thị và sinh output cho cả module không đổi. Thư viện nền Turbo Engine làm tính toán gia tăng tự động, theo nhu cầu (demand-driven) để cập nhật trong vài chục mili giây.
  • Quan sát được: vì khó tái hiện lỗi hiệu năng của người dùng (không chia sẻ được code), Turbopack có instrumentation từng hàm, ghi cả cấp phát và giải phóng bộ nhớ; chỉ cần một file trace (không chứa code ứng dụng) và một trace viewer riêng là điều tra được chậm hay tốn RAM.
  • Dev gần production: thời gian biên dịch route dao động chỉ vài phần trăm (webpack lúc 10 giây lúc 20 giây); CSS luôn xuất ra file (webpack dev dùng style-loader gây flash), source map không dùng eval mà dùng section source map để sinh và cache theo từng phần.
  • Phạm vi stable và đánh đổi: chỉ next dev --turbo; production build chưa; cache đang nằm trong RAM nên mỗi lần restart phải dựng lại (nhiều giây với app lớn), cache đĩa là mục tiêu tiếp theo. Bỏ cấu hình webpack() (hỗ trợ một tập loader), .babelrc không tự biến đổi (mặc định SWC), một số tính năng CSS Modules ít dùng khi chuyển PostCSS sang Lightning CSS. Mất 2 năm từ alpha, chủ yếu vì phải qua 6.599 test của Next.js.
  • Lộ trình tối ưu production: minify JS/CSS xong; tree shaking còn hạn chế với dynamic import, CommonJS, barrel file; scope hoisting và chunking tối ưu cho production chưa làm.

Vì sao

  • Theo Vercel, chỉ port webpack sang Rust sẽ dễ hơn nhưng không đem lại lợi ích mong muốn; kiến trúc phải đổi từ gốc (một đồ thị đa môi trường, tính toán gia tăng chi tiết, đo đạc có sẵn).

Bài học cho SWE

  • Latency vòng lặp dev quyết định năng suất; thiết kế để chi phí sửa tỉ lệ với kích thước thay đổi, không phải kích thước dự án.
  • Thêm cache vào kiến trúc không được thiết kế cho nó rất khó (bài trích "caching là một trong hai việc khó"); Turbopack chọn dựng nền gia tăng từ đầu.
  • Công cụ phải thu được dữ liệu chẩn đoán gọn (trace không chứa code người dùng) vì không thể xin được codebase của người báo lỗi.

Liên quan