0
0
Lập trình
Thaycacac
Thaycacac thaycacac

Hướng Dẫn Chi Tiết Về Cách Hoạt Động Của Kỹ Thuật Hot Module Replacement (HMR)

Đăng vào 3 tuần trước

• 3 phút đọc

Hot Module Replacement (HMR) Là Gì?

Hot Module Replacement (HMR) là một kỹ thuật hiện đại trong phát triển ứng dụng web, cho phép các lập trình viên cập nhật mã nguồn của ứng dụng mà không cần phải làm mới toàn bộ trang. Điều này mang lại nhiều lợi ích về trải nghiệm sử dụng cho các lập trình viên, đặc biệt là khi so sánh với các framework truyền thống như JavaEE, nơi mà việc thay đổi một dòng mã có thể mất tới 5 phút chỉ để biên dịch và triển khai.


Cơ Chế Hoạt Động Của HMR

HMR hoạt động thông qua sự phối hợp giữa server và client. Cơ chế này giúp phát hiện các thay đổi trong mã nguồn và áp dụng chúng ngay lập tức vào ứng dụng mà không mất thời gian tải lại trang. Quá trình này gồm có những bước chính sau:

  1. File Watcher: Server bắt đầu một dịch vụ (Chokidar) để giám sát các thay đổi trong các tệp (JS, CSS, HTML, ...).
  2. Phát Hiện Thay Đổi: Khi một tệp có sự thay đổi, Chokidar sẽ phát hiện và tạo một request để cập nhật module.
  3. Truyền Tải Cập Nhật: Server gửi bản cập nhật module cho client thông qua Websocket.
  4. Xử Lý Tại Client: Client có một Hashmap chứa tất cả các module, giúp client xác định được module cần cập nhật khi nhận dữ liệu từ server.
  5. Callback Chấp Nhận: Mỗi module có thể định nghĩa một callback chấp nhận, hàm này sẽ thực hiện cập nhật module và cập nhật lại cây DOM mà không cần tải lại toàn bộ trang.

Thực Hiện Demo HMR 💪

Trong phần demo này, chúng ta sẽ tạo một ứng dụng NodeJS đơn giản lắng nghe trên cổng 8080 với đường dẫn /. Khi truy cập từ trình duyệt, ứng dụng sẽ trả về tệp index.html, trong đó sẽ gọi các module như main.js, app.js, và child.js.

1. Phía Client

Tệp index.html sẽ có nội dung đơn giản như sau:

html Copy
<body>
  <h1>Hello!</h1>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>

Tiếp theo, trong tệp main.js, chúng ta sẽ import module app:

javascript Copy
import { mount } from "./app.js";

mount();

Tiếp theo là app.js, nói lên thời gian hiện tại và append nội dung từ module con Child:

javascript Copy
import { Child } from "./child.js";

export function mount() {
  const $app = document.querySelector("#app");
  const now = new Date().toLocaleTimeString();
  $app.innerText = `Hello, it is ${now}\n\n`;
  $app.appendChild(Child());
}

Cuối cùng, trong child.js, chúng ta sẽ triển khai demo Hot Module Replacement:

javascript Copy
if (import.meta.hot) {
  console.log("IN HERE");
  import.meta.hot.accept((newModule) => {
    if (newModule) {
      console.log(`Handling hot reload accept for ${import.meta.url}`);
      document.querySelector("#child").replaceWith(newModule.Child());
    }
  });
}

export function Child() {
  const $el = document.createElement("div");
  $el.id = "child";
  $el.textContent = `Hello my ID is ${(Math.random() * 100).toFixed(0)}`;
  return $el;
}

2. Phía Server

Chúng ta sẽ bắt đầu bằng tệp server.js, nơi thiết lập một ứng dụng NodeJS đơn giản:

javascript Copy
const app = express();
const server = http.createServer(app);

Tiếp theo, khởi tạo Websocket:

javascript Copy
const ws = new WebSocketServer({
  server,
});
let socket;

ws.on("connection", (_socket) => {
  console.log("Connected...");
  socket = _socket;
});

Chúng ta sẽ tạo một instance của chokidar để giám sát các tệp .js trong thư mục src:

javascript Copy
const watcher = chokidar.watch("src/*.js");
watcher.on("change", (file) => {
  const normalizedFile = file.replace(/\\/g, '/');
  console.log("File changed: ", normalizedFile);
  const payload = JSON.stringify({
    type: "file:changed",
    file: `/${normalizedFile}`,
  });
  socket.send(payload);
});

Cuối cùng, ta sẽ tạo một middleware hmrMiddleware cho phép import module client.js và append nội dung này vào phản hồi trước khi gửi về trình duyệt:

javascript Copy
const hmrMiddleware = async (req, res, next) => {
  if (!req.url.endsWith(".js")) {
    return next();
  }

  let client = await fs.readFile(path.join(__dirname, "client.js"), "utf8");
  let content = await fs.readFile(path.join(__dirname, req.url), "utf8");

  content = `
  ${client}

  hmrClient(import.meta)

  ${content}
  `;

  res.type(".js");
  res.send(content);
};

Kết Luận

Như vậy, với kỹ thuật Hot Module Replacement, chúng ta chỉ cần lưu file là mọi thay đổi đã được áp dụng ngay lập tức mà không cần phải tải lại toàn bộ trang. Hy vọng bài viết này giúp bạn hiểu rõ hơn về HMR và ứng dụng của nó trong phát triển web. Hẹn gặp lại trong các bài viết tiếp theo nhé! 😊
source: viblo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào