jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Vite · Part 5 — HMR Deep Dive

How Hot Module Replacement swaps a single module without losing state: the import.meta.hot API, HMR boundaries and propagation, why some edits trigger a full reload, and framework Fast Refresh. With an HMR boundary lab.

4 MIN READ

Khoảnh khắc kỳ diệu với Vite là sửa một component và thấy thay đổi xuất hiện trong khi form vẫn điền và counter giữ giá trị. Đó là Hot Module Replacement, và không phải phép thuật — là một API nhỏ học được.

Tích lũy state counter, rồi sửa các module khác nhau để cảm nhận HMR vs reload đầy đủ:


1. HMR vs live reload

Công cụ cũ dùng live reload: file đổi → refresh cả trang → mất hết state. HMR là phẫu thuật: nó chỉ thay module đã đổi trong app đang chạy, để mọi thứ khác — và state — nguyên vẹn.

Dev server đẩy cập nhật tới trình duyệt qua WebSocket. Khi bạn lưu, Vite xác định chính xác module nào đổi và chỉ gửi cái đó.


2. import.meta.hot — API

Một module tham gia HMR qua import.meta.hot (chỉ có khi dev):

export const add = (a: number, b: number) => a + b;

if (import.meta.hot) {
  // "I can handle my own updates — don't reload the page"
  import.meta.hot.accept((newModule) => {
    console.log("new version:", newModule?.add);
  });

  // clean up side effects before the old version is discarded
  import.meta.hot.dispose(() => {
    /* clear timers, remove listeners */
  });
}
Phương thứcMục đích
accept()chấp nhận tự cập nhật, không reload
accept(dep, cb)chấp nhận cập nhật từ module import cụ thể
dispose(cb)dọn dẹp trước khi thay
invalidate()""tôi không xử lý được” → đẩy lên boundary
datagiữ state qua các cập nhật của cùng module

3. Ranh giới HMR & lan truyền

Khái niệm then chốt: module gọi accept() là một ranh giới HMR. Khi một file đổi:

  1. Nếu module tự chấp nhận, thay tại chỗ. Xong.
  2. Nếu không, cập nhật lan lên tới các importer, tìm cái chấp nhận.
  3. Nếu tới entry mà không có boundary chấp nhận, Vite rơi về reload trang đầy đủ.

Đây là vì sao sửa component lá thì hot-update, nhưng sửa utils.ts dùng chung mà không ai chấp nhận thì reload. Demo cho thấy cả ba đường.


4. Bạn hiếm khi tự viết

Tin tốt: plugin framework lo HMR cho bạn.

  • bật Fast Refresh: sửa component và nó re-render với state hook được giữ.
  • làm tương tự cho SFC.
  • luôn hot-swap không reload (CSS vốn không tác dụng phụ khi thay).

Bạn chỉ chạm import.meta.hot trực tiếp cho module ngoài framework có tác dụng phụ — một store, event bus toàn cục, một instance chart thủ công.


5. Lưu ý Fast Refresh

Fast Refresh giữ state chỉ khi file xuất component React gọn gàng. Nó rơi về reload nếu:

  • File trộn export component với export không-component (chuyển hằng/util sang file riêng).
  • Dùng default export ẩn danh — đặt tên cho component.

Các luật này là vì sao “một component mỗi file, có tên” làm HMR đáng tin hơn.


6. Bài tập

1. Khác biệt giữa live reload và HMR, và vì sao HMR giữ state form?

Lời giải

Live reload refresh cả trang (mất state). HMR chỉ thay module đã đổi trong app đang chạy, nên state không liên quan sống sót.

2. Bạn sửa utils.ts dùng chung được nhiều file import và cả trang reload thay vì hot-update. Vì sao?

Lời giải

Không module nào trong chuỗi import gọi accept() cho nó, nên cập nhật lan tới entry không có boundary → reload đầy đủ.

3. Component React của bạn mất state mỗi lần sửa dù Fast Refresh đang bật. Nguyên nhân có khả năng?

Lời giải

File trộn export component và không-component, hoặc dùng default export ẩn danh — cả hai làm Fast Refresh rơi về reload. Tách export và đặt tên component.

Nâng cao:trong lab, tăng counter, sửa CSS (giữ state), sửa component lá (giữ state), rồi sửa utils.ts (mất state) — và ánh xạ từng cái với luật lan truyền ở trên.


Điểm chính

  • HMR thay một module; live reload refresh tất cả.
  • Module gọi import.meta.hot.accept() là một ranh giới HMR.
  • Cập nhật lan lên tới khi một boundary chấp nhận; không boundary → reload đầy đủ.
  • Plugin framework (React Fast Refresh, Vue) lo HMR tự động.
  • Một component có tên mỗi file làm Fast Refresh đáng tin.

Tiếp theo

Phần 6 — Xử lý CSS: CSS Modules, PostCSS, preprocessor (Sass/Less), ?inline, CSS tách code, và cách Vite xử lý style khi dev vs build.