Hot Reload — је технологија при којој се промене у изворном коду примењују на апликацију која ради без пуног поновног учитавања странице и без губитка тренутног стања. За разлику од Live Reload-а, који једноставно освежава целу страницу, вруће поновно учитавање замењује само измењене модуле у лету. Према Webpack, 2024, Hot Module Replacement (HMR) скраћује време развојног циклуса до 80% захваљујући очувању стања компонената.
Главно
Hot Reload — је механизам развоја при којем се промене у изворним датотекама одмах одражавају у апликацији која ради без њеног поновног покретања. Програмер мења код у уређивачу, чува датотеку, и резултат је одмах видљив у прегледачу или емулатору.
Кључна карактеристика технологије је очување стања апликације. Променљиве у меморији, подаци у формуларима, тренутна навигација — све остаје на свомом месту. Програмер не мора да понавља секвенцу акција да би се вратио на потребан екран.
У веб развоју, Hot Reload се имплементира кроз механизам Hot Module Replacement (HMR). Бандлер прати промене датотека, одређује који модули су погођени и шаље ажурирани код у прегледач путем WebSocket. Прегледач замењује само те модуле без поновног учитавања странице.
Популарност Hot Reload-а је порасла са ширењем једностраничних апликација (SPA), где пуно поновно учитавање странице уништава целокупно стање клијентске апликације. React, Vue, Angular и други фрејмворкови препоручују HMR као основни начин развоја.
Механизам HMR се састоји из четири фазе. Бандлер на страни сервера компилира измењени модул, креира JSON закрпу са новом верзијом кода и шаље је у прегледач путем WebSocket везе. Браузерски HMR runtime прима закрпу, замењује стари модул новим и обавештава претплатнике модула.
Webpack Dev Server користи WebSocket за комуникацију са клијентом. При промени датотеке, бандлер креира hot-update.js и hot-update.json са манифестом промена. Клијент аутоматски учитава ове датотеке путем JSONP.
// webpack.config.js - HMR podešavanje
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
devServer: {
hot: true,
liveReload: false
},
plugins: [new HtmlWebpackPlugin()]
};
HMR runtime у прегледачу проверава да ли модул који се замењује подржава accept. Ако је модул декларисао module.hot.accept(), runtime га замењује на лицу места и покреће повратни позив ажурирања. Ако accept није декларисан, HMR пада на виши ниво, ка родитељском модулу.
У React Fast Refresh-у ова логика је уграђена на нивоу фрејмворка — није потребно ручно писати module.hot.accept у свакој датотеци. Babel-plugin react-refresh/babel додаје код који безбедно замењује компоненте без губитка стања.
Ова три термина се често мешају, али се коренито разликују у понашању. Live Reload поново учитава целу страницу при свакој промени — целокупно стање се губи. Full Reload се дешава при потпуном поновном покретању развојног сервера са губитком не само клијентског, већ и серверског стања.
| Тип | Поновно учитавање странице | Очување стања | Брзина |
|---|---|---|---|
| Hot Reload (HMR) | Не | Да | Тренутно |
| Live Reload | Да | Не | 1-3 сек |
| Full Reload | Да | Не | 3-10 сек |
Избор између Hot и Live директно утиче на брзину развоја. Код HMR-а, циклус «променио сам код → видио сам резултат» траје 50-200 ms. Код Live Reload-а — 1-3 секунде пљус време за обнову контекста. Током радног дана, разлика износи десетине минута уштеденог времена.
React Fast Refresh — званична имплементација Hot Reload-а оптимизована за React компоненте. Заменила је стари механизам React Hot Loader, који је био нестабилан и захтевао ручну конфигурацију. Fast Refresh је уграђен у Create React App, Next.js, Vite и Webpack путем react-refresh/babel.
Fast Refresh исправно чува стање функционалних компонената при промени њиховог кода. Ако мењате само JSX ознаке — useState и други hook-ови задржавају своје вредности. Ако се логика hook-а мења — долази до поновног монтирања компоненте.
// Primer - stanje očuvano kada se JSX menja
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
Fast Refresh не чува стање ако нови код садржи грешку компилације. Ако се компонента не извози подразумевано (default export), већ поименично (named export), стање се такође може изгубити. Препоручује се коришћење default export за компоненте и умотавање извоза у memo ако је потребно гарантовати очување стања.
Модерни бандлери пружају HMR. Webpack — пионир HMR-а са флексибилном конфигурацијом кроз devServer.hot. Vite користи нативни ESM и esbuild за тренутни HMR без бандловања. Parcel — HMR без конфигурације. Turbopack — нови бандлер од Vercel-а са HMR-ом на Rust-у.
| Алат | Тип HMR | Конфигурација | Екосистем |
|---|---|---|---|
| Webpack 5 | HMR путем WebSocket | devServer.hot: true | React, Vue, Angular |
| Vite | Native ESM HMR | Из кутије | React, Vue, Svelte |
| Parcel 2 | Zero-config HMR | Није потребно | React, Vue, TS |
| Turbopack | Incremental HMR | Из кутије | Next.js |
Vite се истиче по брзини — HMR у Vite-у ради путем нативних ES модула прегледача. При промени датотеке, Vite шаље само тај модул путем import(), без поновне компилације целог пројекта. Webpack компилира сваки модул у целини, што у великим пројектима успорава HMR.
Размотримо подешавање HMR-а за различите бандлере. У Webpack-у потребно је поставити hot: true у devServer и додати react-refresh/babel. У Vite-у HMR ради из кутије са било којим пресетом. У Next.js-у Fast Refresh је подразумеван путем турбокомпилатора.
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
hmr: {
port: 3001
}
}
});
// webpack.config.js
const ReactRefreshWebpackPlugin =
require('@pmmmwh/react-refresh-webpack-plugin');
module.exports = {
mode: 'development',
devServer: { hot: true },
plugins: [new ReactRefreshWebpackPlugin()],
module: {
rules: [
{
test: /\.jsx?$/u,
use: 'babel-loader'
}
]
}
};
HMR не ради исправно у свим сценаријима. CSS модули са динамичким класама могу да се не примене. Глобалне променљиве и синглони (Redux store, router) могу да се ресетују при поновном учитавању. Тешке библиотеке при HMR-у понекад генеришу цурење меморије због замене модула без GC.
Решење проблема HMR-а — изоловати врући код у чисте компоненте без нуспоредних ефеката. Нуспоредни ефекти (WebSocket претплате, тајмери) треба да се чисте у useEffect-у. За Redux се препоручује persister који чува стање у sessionStorage. CSS решења попут CSS Modules или styled-components раде исправно са HMR-ом без додатне конфигурације.
Још једно ограничење — отклањање грешака у производњи: HMR је намерно искључен у производној компилацији. Изворни код је минификован, и врућа замена у производњи је немогућа. За отклањање грешака у производњи користе се source maps и логовање, али не HMR.
Често постављана питања
Hot Reload замењује само измењени модул без поновног учитавања странице и чува стање. Live Reload поново учитава целу страницу — стање се губи, апликација покреће изнова са почетног екрана.
У пројектима на Create React App и Vite HMR је подразумеван. У Webpack-у треба додати devServer: { hot: true } и @pmmmwh/react-refresh-webpack-plugin. У Next.js-у Fast Refresh ради без подешавања.
Разлог — грешка компилације у новом коду, named export уместо default, промена потписа hook-а или директна мутација стања. React Fast Refresh безбедно ресетује компоненту само када је то потребно за исправан рад.
Да, сви модерни бандлери подржавају HMR са TypeScript. Vite користи esbuild за транспилацију TS. Webpack — ts-loader или babel са @babel/preset-typescript. Fast Refresh исправно ради са типизованим компонентама.
Проверите конзолу прегледача за грешке WebSocket везе. Осигурајте се да је devServer.hot: true укључен. За Vite проверите HMR порт. Ако се проблем не ријешава — извршите пуно поновно учитавање странице (F5) и проверите конзолу бандлера.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође