Hot Module Replacement
Hot Module Replacement(HMR)는 모듈 전체를 다시 로드하지 않고 애플리케이션이 실행되는 동안 교환, 추가 또는 제거합니다. 다음과 같은 몇 가지 방법으로 개발 속도를 크게 높일 수 있습니다.
- 전체 다시 로드 중에 손실되는 애플리케이션의 상태를 유지합니다.
- 변경된 사항만 갱신하여 귀중한 개발 시간을 절약하세요.
- 소스 코드에서 CSS/JS를 수정하면 브라우저에서 즉시 업데이트합니다. 이는 브라우저의 개발자 도구에서 직접 스타일을 변경하는 것과 거의 비슷합니다.
How It Works
HMR이 어떻게 작동하는지 정확히 이해하기 위해 몇 가지 다른 관점을 살펴보겠습니다.
In the Application
다음 단계를 통해 애플리케이션에서 모듈을 교체할 수 있습니다.
- 애플리케이션은 HMR 런타임에 업데이트된 내용이 있는지 확인하도록 요청합니다.
- 런타임에서 업데이트된 내용을 비동기적으로 다운로드받고 애플리케이션에 알립니다.
- 그런 다음 애플리케이션은 런타임에 업데이트를 요청합니다.
- 런타임은 업데이트를 동기적으로 적용합니다.
이 프로세스가 자동으로 발생하도록 HMR을 설정하거나 업데이트가 발생하기 위해 사용자 상호 작용을 요구하도록 선택할 수 있습니다.
In the Compiler
일반 애셋 외에도 컴파일러는 이전 버전에서 새 버전으로 업데이트할 수 있도록 "업데이트"를 내보내야 합니다. "업데이트"는 두 부분으로 구성됩니다.
- 업데이트된 매니페스트 (JSON)
- 하나 이상의 업데이트 된 청크 (JavaScript)
매니페스트에는 업데이트된 청크, 제거된 청크, 제거된 모듈의 ID가 나열됩니다. 각 업데이트 청크에는 업데이트된 모듈의 새 코드가 포함되며, 런타임 청크에 대한 업데이트에는 새 컴파일 해시도 함께 포함됩니다.
컴파일러는 이러한 빌드 간에 모듈 ID와 청크 ID가 일치하는지 확인합니다. watching 컴파일러는 이를 메모리에 유지하며, 이것이 개발 서버에 필요한 전부입니다. 별도의 컴파일러 실행 간에 일관성을 유지하려면 — 한 머신에서의 빌드가 다른 머신의 빌드에 적용 가능한 업데이트를 생성해야 하는 경우 — recordsPath를 사용하여 JSON 파일에 저장하세요.
In a Module
HMR은 HMR 코드가 포함된 모듈에만 영향을 미치는 선택적 기능입니다. 스타일링이 한 가지 예입니다. webpack의 내장 CSS 지원이 HMR 인터페이스를 대신 구현하므로, 스타일시트 업데이트가 도착하면 전체 페이지를 다시 로드하지 않고 기존 스타일을 새 스타일로 교체합니다.
마찬가지로 모듈에서 HMR 인터페이스를 구현할 때, 모듈이 업데이트될 때 어떤 일이 발생해야 하는지 설명할 수 있습니다. 그러나 대부분의 경우 모든 모듈에서 HMR 코드를 작성해야 하는 것은 아닙니다. 모듈에 HMR 핸들러가 없으면 업데이트가 버블링됩니다. webpack은 변경된 모듈에서 해당 모듈을 가져온 모듈들을 따라가며 변경을 수락하는 모듈을 찾습니다. 충분히 상위에 위치한 단일 핸들러가 전체 서브트리를 처리할 수 있습니다.
해당 핸들러가 무엇을 처리하는지 정확히 이해하는 것이 중요합니다. 이것이 어떤 코드가 다시 실행될지를 결정하기 때문입니다. top.js → middle.js → leaf.js 구조에서 top.js만 ./middle.js를 accept한다면, leaf.js를 수정했을 때 다음이 다시 실행됩니다.
| 모듈 | 재실행 여부 | 이유 |
|---|---|---|
leaf.js | 예 | 변경된 모듈이기 때문에 |
middle.js | 예 | 변경 지점과 핸들러 사이에 위치하기 때문에 |
middle.js가 가져오지만 변경되지 않은 모듈 | 아니오 | 모듈 캐시에 그대로 있으며 재사용됩니다 |
top.js | 아니오 | accept한 모듈이므로 계속 실행됩니다 |
top.js는 재실행되지 않으며 dispose 핸들러도 실행되지 않습니다. accept 콜백만 호출되며, 이 시점에 가져온 바인딩은 이미 새 버전을 가리킵니다. 따라서 top.js 자체의 상태는 업데이트 후에도 유지되며, 이것이 바로 이곳에서 다시 렌더링하거나 장수명 객체에 값을 교체하기에 적합한 이유입니다. 자신의 변경 시 재실행되기를 원하는 모듈은 self-accept를 사용하면 되며, 그러면 해당 모듈은 폐기되고 그 자리에서 다시 실행됩니다.
module.hot 인터페이스에 대한 자세한 내용은 HMR API 페이지를, 실제 예제는 HMR 가이드를 참고하세요.
In the Runtime
여기에서는 조금 더 기술적인 내용을 다룹니다. 내부 동작에 관심이 없다면 HMR API 페이지 또는 HMR 가이드로 이동하세요.
모듈 시스템 런타임의 경우 부모 및 자식 모듈을 추적하기 위해 추가 코드가 생성됩니다. 관리적인 측면에서 런타임은 check 그리고 apply 두 가지 방법을 지원합니다.
check는 업데이트 매니페스트를 요청합니다. 가져오는 방법은 타겟에 따라 다릅니다. 브라우저 빌드는 HTTP로 요청하고, target: 'node' 빌드는 fs.readFile로 읽습니다. 하지만 로직은 동일합니다. 요청이 실패하면 사용 가능한 업데이트가 없는 것입니다. 성공하면 업데이트된 청크 목록과 현재 로드된 청크 목록을 비교합니다. 로드된 각 청크에 해당하는 업데이트 청크가 다운로드됩니다. 모든 모듈 업데이트는 런타임에 저장됩니다. 모든 업데이트 청크가 다운로드되고 적용할 준비가 되면 런타임은 ready 상태로 전환됩니다.
apply 메서드는 업데이트된 모든 모듈을 유효하지 않은 것으로 표시합니다. 유효하지 않은 각 모듈에는 해당 모듈 또는 상위 모듈에 업데이트 핸들러가 있어야 합니다. 그렇지 않으면 유효하지 않음 플래그가 버블링되어 상위 모듈도 무효화됩니다. 각 버블링은 앱의 엔트리 포인트나 업데이트 핸들러가 있는 모듈에 도달할 때까지(둘 중 먼저 오는 쪽) 계속됩니다. 엔트리 포인트에서 버블링이 발생하면 프로세스가 실패합니다. 업데이트는 아무도 수락하지 않은 파일 이름을 알리는 메시지와 함께 중단되고, 애플리케이션은 기존 코드를 계속 실행합니다. 이것이 개발 서버가 전체 페이지 새로고침으로 전환하는 상황입니다.
그 후 모든 유효하지 않은 모듈이 (폐기 처리기를 통해) 폐기되고 언로드됩니다. 그런 다음 현재 해시가 업데이트되고 모든 accept 핸들러가 호출됩니다. 런타임은 idle 상태로 다시 전환되고 모든 것이 정상적으로 계속됩니다.
런타임은 status를 통해 해당 시퀀스에서의 위치를 보고합니다. 커스텀 HMR 클라이언트는 이를 통해 다음 업데이트를 요청해도 안전한 시점을 파악합니다.
On the wire
업데이트는 일반 출력 옆에 output.hotUpdateMainFilename과 output.hotUpdateChunkFilename으로 명명된 두 개의 파일로 구성됩니다.
[runtime].[fullhash].hot-update.json— 매니페스트로, 업데이트가 영향을 미치는 청크와 모듈 목록을 포함합니다.[id].[fullhash].hot-update.js— 업데이트된 청크마다 하나씩 생성되며, 새 모듈 코드를 담습니다.
파일 이름의 해시는 업데이트 대상 빌드의 해시가 아닌, 업데이트 출발점 빌드의 해시입니다. 이를 통해 유휴 상태의 클라이언트가 실제로 실행 중인 버전에 이어지는 업데이트를 요청할 수 있습니다. 빌드가 너무 오래되어 일치하는 업데이트 파일이 없는 클라이언트는 요청에 실패하여 전체 새로고침으로 폴백하고, 현재 번들을 가져오게 됩니다.
Get Started
HMR은 Live Reload의 대체품으로 개발에 사용할 수 있습니다. webpack-dev-server는 전체 페이지를 다시 로드하기 전에 HMR로 업데이트를 시도하는 hot 모드를 지원합니다. 자세한 내용은 Hot Module Replacement 가이드를 참고하세요.