핫 모듈 교체 (HMR) 는 전체 페이지 새로고침 없이 실행 중인 애플리케이션에서 모듈을 업데이트할 수 있게 해줍니다. 이는 애플리케이션 상태를 유지하고 개발 경험을 개선합니다.
NOTE
HMR 은 Bun 의 풀스택 개발 서버를 사용할 때 기본적으로 활성화됩니다.import.meta.hot API 참조
Bun 은 Vite 의 import.meta.hot API 를 모델로 한 클라이언트 측 HMR API 를 구현합니다. if (import.meta.hot) 로 확인하여 프로덕션에서 트리 쉐이킹할 수 있습니다.
if (import.meta.hot) {
// HMR API 를 사용할 수 있습니다.
}하지만 Bun 은 프로덕션 빌드에서 모든 HMR API 호출을 데드 코드 제거하므로 이 확인은 종종 필요하지 않습니다.
// 이 전체 함수 호출은 프로덕션에서 제거됩니다!
import.meta.hot.dispose(() => {
console.log("dispose");
});NOTE
HMR API 는 아직 진행 중인 작업입니다. 일부 기능은 누락되었습니다. HMR 은 `Bun.serve` 에서 development 옵션을 `{ hmr: false }` 로 설정하여 비활성화할 수 있습니다.API 메서드
| 메서드 | 상태 | 참고 |
|---|---|---|
hot.accept() | ✅ | 핫 업데이트를 부드럽게 교체할 수 있음을 나타냄. |
hot.data | ✅ | 모듈 평가 간에 데이터 유지. |
hot.dispose() | ✅ | 모듈이 교체되기 직전에 실행될 콜백 함수 추가. |
hot.invalidate() | ❌ | |
hot.on() | ✅ | 이벤트 리스너 첨부 |
hot.off() | ✅ | on 에서 이벤트 리스너 제거. |
hot.send() | ❌ | |
hot.prune() | 🚧 | 참고: 콜백이 현재 호출되지 않음. |
hot.decline() | ✅ | Vite 의 import.meta.hot 과 일치하도록 no-op |
import.meta.hot.accept()
accept() 메서드는 모듈이 핫 교체될 수 있음을 나타냅니다. 인수 없이 호출되면 이 모듈은 파일을 다시 평가하여 교체될 수 있음을 나타냅니다. 핫 업데이트 후 이 모듈의 임포터는 자동으로 패치됩니다.
// index.ts
import { getCount } from "./foo.ts";
console.log("count is ", getCount());
import.meta.hot.accept();
export function getNegativeCount() {
return -getCount();
}이것은 index.ts 가 가져오는 모든 파일에 대한 핫 리로딩 경계를 생성합니다. 즉, foo.ts 또는 해당 종속성이 저장될 때마다 업데이트가 index.ts 까지 버블링되어 다시 평가됩니다. index.ts 를 가져오는 파일은 새로운 getNegativeCount() 버전을 가져오도록 패치됩니다. index.ts 만 업데이트되면 하나의 파일만 다시 평가되고 foo.ts 의 카운터는 재사용됩니다.
이는 import.meta.hot.data 와 결합하여 이전 모듈에서 새 모듈로 상태를 전송하는 데 사용될 수 있습니다.
콜백과 함께
하나의 콜백을 제공하면 import.meta.hot.accept 는 Vite 에서 작동하는 방식으로 작동합니다. 이 모듈의 임포터를 패치하는 대신 새 모듈과 함께 콜백을 호출합니다.
export const count = 0;
import.meta.hot.accept(newModule => {
if (newModule) {
// newModule 은 SyntaxError 가 발생했을 때 undefined 입니다
console.log("업데이트됨: count 는 이제 ", newModule.count);
}
});다른 모듈 허용
import { count } from "./foo";
import.meta.hot.accept("./foo", () => {
if (!newModule) return;
console.log("업데이트됨: count 는 이제 ", count);
});종속성의 모듈을 허용할 수 있음을 나타냅니다. 종속성이 업데이트되면 새 모듈과 함께 콜백이 호출됩니다.
여러 종속성과 함께
import.meta.hot.accept(["./foo", "./bar"], newModules => {
// newModules 는 각 항목이 업데이트된 모듈에 해당하는 배열입니다
// 또는 해당 모듈에 오류가 있으면 undefined
});여러 종속성의 모듈을 허용할 수 있음을 나타냅니다. 이 변형은 종속성 배열을 허용하며 콜백은 업데이트된 모듈과 오류가 있는 경우 undefined 를 받습니다.
import.meta.hot.data
import.meta.hot.data 는 핫 교체 중 모듈 인스턴스 간에 상태를 유지하여 이전 버전에서 새 버전으로 데이터 전송을 가능하게 합니다. import.meta.hot.data 에 쓰기가 발생하면 Bun 은 이 모듈이 자체 허용 가능한 것으로 표시합니다 (import.meta.hot.accept() 호출과 동일).
import { createRoot } from "react-dom/client";
import { App } from "./app";
const root = (import.meta.hot.data.root ??= createRoot(elem));
root.render(<App />); // 기존 root 재사용프로덕션에서 data 는 {} 로 인라인되므로 상태 홀더로 사용할 수 없습니다.
import.meta.hot.dispose()
on-dispose 콜백을 첨부합니다. 이는 다음 시점에 호출됩니다:
- 모듈이 다른 사본으로 교체되기 직전 (다음이 로드되기 전)
- 모듈이 분리된 후 (이 모듈에 대한 모든 가져오기 제거,
import.meta.hot.prune()참조)
const sideEffect = setupSideEffect();
import.meta.hot.dispose(() => {
sideEffect.cleanup();
});promise 를 반환하면 모듈이 처리될 때까지 모듈 교체가 지연됩니다. 모든 dispose 콜백은 병렬로 호출됩니다.
import.meta.hot.prune()
on-prune 콜백을 첨부합니다. 이는 이 모듈에 대한 모든 가져오기가 제거되었지만 모듈이 이전에 로드되었을 때 호출됩니다.
이는 모듈이 로드될 때 생성된 리소스를 정리하는 데 사용할 수 있습니다. import.meta.hot.dispose() 와 달리 accept 및 data 와 더 잘 쌍을 이루어 상태가 있는 리소스를 관리합니다. WebSocket 을 관리하는 전체 예제:
import { something } from "./something";
// WebSocket 연결 초기화 또는 재사용
export const ws = (import.meta.hot.data.ws ??= new WebSocket(location.origin));
// 모듈의 가져오기가 제거되면 WebSocket 연결을 정리합니다.
import.meta.hot.prune(() => {
ws.close();
});import.meta.hot.on() 및 off()
on() 및 off() 는 HMR 런타임에서 이벤트를 수신하는 데 사용됩니다. 이벤트 이름은 플러그인이 서로 충돌하지 않도록 접두사가 붙습니다.
import.meta.hot.on("bun:beforeUpdate", () => {
console.log("핫 업데이트 전");
});파일이 교체되면 모든 이벤트 리스너가 자동으로 제거됩니다.
내장 이벤트
| 이벤트 | 발생 시기 |
|---|---|
bun:beforeUpdate | 핫 업데이트가 적용되기 전. |
bun:afterUpdate | 핫 업데이트가 적용된 후. |
bun:beforeFullReload | 전체 페이지 새로고침이 발생하기 전. |
bun:beforePrune | prune 콜백이 호출되기 전. |
bun:invalidate | 모듈이 import.meta.hot.invalidate() 로 무효화될 때 |
bun:error | 빌드 또는 런타임 오류가 발생할 때 |
bun:ws:disconnect | HMR WebSocket 연결이 끊어졌을 때. 개발 서버가 오프라인일 수 있음을 나타냄. |
bun:ws:connect | HMR WebSocket 이 연결되거나 재연결될 때. |
NOTE
Vite 와의 호환성을 위해 위의 이벤트는 `bun:*` 접두사 대신 `vite:*` 접두사로도 사용할 수 있습니다.