Hot Reload Development Server: Setup Cepat

by Marcus Chen
Hot Reload Development Server: Setup Cepat

Kamu lagi ngoding, ubah satu baris CSS, terus harus buka terminal, Ctrl+C, jalanin ulang server, refresh browser. Ulang lagi. Ulang lagi. Setelah 40 kali dalam satu sesi, itu bukan coding — itu ritual siksaan.

Hot reload development server hadir buat ngakhirin loop itu. Setiap kali kamu save file, server otomatis detect perubahan dan reload — browser langsung update tanpa kamu sentuh apa-apa. Artikel ini bahas cara setup-nya di beberapa stack umum yang dipakai developer Indonesia, plus gotcha yang gue temuin langsung di lapangan.


Apa Sebenarnya yang Terjadi di Balik Hot Reload

Sebelum setup, penting ngerti bedanya tiga istilah yang sering ketuker:

  • Live reload — browser refresh penuh setiap ada perubahan file.
  • Hot reload — hanya modul yang berubah yang di-replace, state aplikasi dipertahankan.
  • HMR (Hot Module Replacement) — versi lebih canggih dari hot reload, dipakai di Webpack, Vite, dll.

Kalau kamu pakai React dan lagi isi form panjang, hot reload bakal jagain isi form itu waktu kamu ubah styling komponen. Live reload? Semua hilang, form kosong lagi. Ini yang bikin HMR jadi standar di frontend modern.

Di sisi backend (Node.js, Python, Go), istilahnya biasanya "file watcher" yang trigger restart proses — lebih mirip live reload, tapi tetap jauh lebih cepat dari manual.


Setup Hot Reload untuk Node.js / Express

Ini stack paling umum di kalangan junior dev dan indie hacker lokal. Dulu solusinya nodemon, sekarang ada pilihan lebih modern.

Pakai nodemon (klasik, reliable)

npm install --save-dev nodemon

Tambah script di package.json:

{
  "scripts": {
    "dev": "nodemon src/index.js"
  }
}

Jalanin:

npm run dev

Setiap kamu save file .js di dalam project, nodemon restart server otomatis. Simpel.

Gotcha #1: Nodemon by default watch semua file, termasuk folder logs/ atau file .env yang sering berubah karena proses lain. Server jadi restart mulu tanpa sebab jelas. Fix-nya, bikin file nodemon.json di root project:

{
  "watch": ["src"],
  "ext": "js,json",
  "ignore": ["src/logs/*", "*.test.js"]
}

Pakai --watch bawaan Node.js 18+

Kalau kamu sudah di Node 18 ke atas, ada flag --watch native tanpa install apa-apa:

node --watch src/index.js

Atau di package.json:

{
  "scripts": {
    "dev": "node --watch src/index.js"
  }
}

Lebih ringan dari nodemon karena nggak ada dependency tambahan. Tapi fiturnya lebih terbatas — belum bisa ignore pattern sekompleks nodemon config.


Setup Hot Reload untuk Frontend: Vite

Kalau kamu bikin project React, Vue, atau Svelte dari 2022 ke atas, kemungkinan besar sudah pakai Vite. HMR-nya out-of-the-box dan cepat banget.

npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev

Output-nya:

  VITE v5.x.x  ready in 312 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: http://192.168.1.x:5173/

Buka browser, ubah komponen apapun, lihat update langsung tanpa full refresh.

Gotcha #2: HMR Vite kadang "stuck" kalau kamu edit file di luar folder src/ — misalnya config di root. Solusinya restart dev server manual sekali. Ini by design, bukan bug.

Gotcha #3: Di WSL2 (Windows Subsystem for Linux), file watcher Vite sering nggak detect perubahan karena masalah inotify cross-filesystem. Fix:

// vite.config.js
export default {
  server: {
    watch: {
      usePolling: true,
      interval: 300
    }
  }
}

usePolling: true bikin Vite polling filesystem setiap 300ms alih-alih pakai native file events. Lebih boros CPU sedikit, tapi works di WSL2 dan Docker volume.


Setup di dalam Docker Container

Ini yang paling sering bikin frustrasi. Kamu setup hot reload, jalan di local, terus pindah ke Docker dan tiba-tiba nggak jalan lagi.

Masalahnya sama: Docker volume mount di Linux pakai inotify, tapi kalau host-nya macOS atau Windows, event-nya nggak propagate dengan benar.

Contoh docker-compose.yml untuk Node.js dev dengan hot reload:

version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
    command: npm run dev

Dockerfile.dev:

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
EXPOSE 3000

Dan nodemon.json dengan legacy watch untuk Docker:

{
  "watch": ["src"],
  "ext": "js,json",
  "ignore": ["node_modules"],
  "legacyWatch": true
}

legacyWatch: true di nodemon sama efeknya dengan usePolling di Vite — polling instead of inotify.

Gotcha #4: Jangan mount node_modules dari host ke container. Baris /app/node_modules di volumes itu anonymous volume yang override mount, jadi node_modules di container tetap hasil npm install di dalam container, bukan dari host. Kalau kamu skip ini, bisa dapat error module not found yang membingungkan.


Setup Hot Reload untuk Python / FastAPI

Buat yang backend-nya Python, FastAPI punya built-in reload via uvicorn:

pip install fastapi uvicorn[standard]

Jalanin dengan flag --reload:

uvicorn main:app --reload --host 0.0.0.0 --port 8000

Contoh main.py minimal:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"status": "ok"}

Save file, uvicorn detect perubahan, reload otomatis. Endpoint langsung pakai kode terbaru.

Gotcha #5: Flag --reload di uvicorn pakai watchfiles library di baliknya (sejak uvicorn 0.20+). Kalau kamu di environment yang nggak support inotify (Docker di macOS/Windows), install watchfiles eksplisit dan set environment variable:

pip install watchfiles
WATCHFILES_FORCE_POLLING=1 uvicorn main:app --reload

Untuk Django, equivalent-nya sudah built-in di manage.py runserver — dia auto-reload by default. Nggak perlu tambahan apa-apa.


Konfigurasi Hot Reload di Go dengan Air

Go tidak punya built-in file watcher untuk development. Tool paling populer adalah air.

Install:

go install github.com/air-verse/air@latest

Init config di root project:

air init

Ini generate file .air.toml. Konfigurasi minimal:

[build]
  cmd = "go build -o ./tmp/main ."
  bin = "./tmp/main"
  include_ext = ["go", "tpl", "tmpl", "html"]
  exclude_dir = ["assets", "tmp", "vendor"]

[log]
  time = true

Jalanin:

air

Setiap kamu save file .go, air rebuild dan restart binary otomatis. Build time Go yang cepat bikin ini terasa hampir instan untuk project kecil-menengah.

Gotcha #6: Air butuh tmp/ directory untuk taruh binary hasil build. Pastikan .gitignore kamu include tmp/:

tmp/

Kalau nggak, kamu bakal commit binary ke repo. Nggak fatal, tapi memalukan.


Satu Setup, Multi-Service: Kombinasi dengan Makefile

Kalau project kamu punya frontend Vite + backend Node.js yang harus jalan bersamaan, bikin Makefile sederhana:

.PHONY: dev

dev:
	npx concurrently \
		"npm run dev --prefix frontend" \
		"npm run dev --prefix backend"

Install concurrently dulu:

npm install --save-dev concurrently

Sekarang satu perintah make dev jalanin keduanya dengan hot reload aktif. Log dari kedua proses muncul di terminal yang sama dengan prefix berbeda supaya gampang dibedain.

Alternatif kalau nggak mau pakai Makefile, langsung di package.json root:

{
  "scripts": {
    "dev": "concurrently \"npm run dev --prefix frontend\" \"npm run dev --prefix backend\""
  }
}

Checklist Sebelum Kamu Lanjut

Sebelum deploy atau push ke repo, pastikan:

  1. Hot reload hanya aktif di development — jangan sampai --reload atau --watch ikut ke production. Set via NODE_ENV check atau separate npm script.
  2. File .env tidak trigger reload — tambah ke ignore list watcher kamu.
  3. node_modules tidak di-watch — ini makan resource dan bikin watcher lambat.
  4. Polling mode aktif kalau pakai Docker di macOS/Windows — ini satu-satunya fix yang reliable.

Yang Gue Lakuin Sekarang

Untuk setup personal gue — Express backend + Vite frontend, jalan di Docker di atas Linux VPS — gue pakai:

  • nodemon dengan config legacyWatch: false (karena host-nya Linux, inotify works fine)
  • Vite dengan config default, tanpa polling
  • docker-compose watch yang baru di Docker Compose v2.22+ sebagai eksperimen — ini basically built-in hot reload untuk container yang sync file dari host ke container secara selektif

docker-compose watch itu menarik karena kamu bisa define di compose.yml file mana yang di-sync dan action apa yang diambil (sync, rebuild, atau restart). Tapi masih agak experimental, jadi gue belum all-in.

Kalau kamu baru mulai, rekomendasi paling simpel: pakai Vite untuk frontend, nodemon untuk backend Node.js, dan tambah legacyWatch: true kalau kamu di Windows/macOS dengan Docker. Itu saja sudah cukup buat 90% kasus.

Hot reload development server yang properly configured itu bukan luxury — ini produktivitas dasar yang harusnya udah jalan dari hari pertama project.