Development: what hot reloads and what restarts
Development: what hot reloads and what restarts in the Dusk guide.
npx dusk dev starts the development server. Saving a file updates the page or restarts the server according to the file type.
| You edit | The open page | State | The server |
|---|---|---|---|
A component (.tsx) |
Updates in place, no reload | The edited component's own state starts again; its parent and siblings keep theirs | Nothing to do |
| A plain stylesheet | Updates in place | None | Nothing to do |
A CSS module (*.module.css) |
Updates in place | None | Nothing to do |
| A class in a component, for example a Tailwind utility | Updates in place: the stylesheets are sent with the component | The edited component's state starts again | Nothing to do |
A layout (routes/_layout.tsx) |
The layout updates in place | The page under the layout is built again, so its state starts again | Nothing to do |
| A route page (its component) | Updates in place | The page's own state starts again | Nothing to do |
A route's loader |
Reloads once; the new loader runs on the reload | The page loads again | Nothing to do |
A route's metadata (head) |
Reloads once; the new title is shown after it | The page loads again | Nothing to do |
| A module that several pages import | Every page that imports it updates in place | The edited components start again | Nothing to do |
| A server function called from a component | The next call runs the new code | The component's state starts again when its module updates | Nothing to do |
| A server function a loader calls | Reloads once | The page loads again | Nothing to do |
An API route (routes/api/*.ts) |
No page involved | None | The next request runs the new code |
Handler middleware (middleware in src/entry-server.ts) |
No page involved | None | The next request runs the new middleware |
A route-level _middleware.ts |
No page involved | None | The next request runs the new chain, and so does the next navigation into its folder |
| A new route file | Reloads once; the new route answers | The page loads again | Nothing to do; the route appears without a restart |
| A deleted route file | Reloads once; its URL answers 404 | The page loads again | Nothing to do |
| A renamed route file or folder | Reloads once | The page loads again | Nothing to do |
A dynamic route page ([id].tsx) |
Updates in place | The page's own state starts again | Nothing to do |
A dynamic route's param folder ([id] to [slug]) |
Reloads once | The page loads again | Nothing to do |
.env, .env.local, .env.[mode] |
Reloads once after the restart | The page loads again | Vite restarts the server and prints ... changed, restarting server...; the new values are read by the restarted server |
dusk.config.ts |
Reloads once after the restart | The page loads again | Restarts by itself and prints dusk.config.ts changed, restarting the dev server. |
vite.config.ts |
Reloads once after the restart | The page loads again | Vite restarts by itself |
A save that adds a syntax error shows Vite's error overlay, with the file and the line; the page keeps its last good version until the file is fixed, and the fix removes the overlay. A page that cannot be rendered on the server answers a 500 page with the message and the stack. The 500 page loads Vite's client, so the page loads again by itself when the server code is fixed.
Limitations
- A layout edit builds the page under the layout again, so that page's state starts over. Children do not keep state across a layout edit: the router renders the routed page inside the layout's render, and a re-render disposes it. Keeping it would need the outlet to own the page outside that render, which is not built yet. The nearest behavior is this rebuild without a reload (BRW-HMR-07 checks it).
- A
loaderorheadchange reloads the page, because those exports live in the route's module, which the browser does not replace in place. The reload runs the new code at once. A head change is not applied in place yet (BRW-HMR-23 checks the reload). - Each development request first brings the generated route tree up to date with the routes folder, so a request never loads a tree that names a file already removed (a 500). The routes folder is read on each request; the cost grows with the number of route files.
- A class change updates the stylesheets only when the edited file is JSX or TSX and sets a
classorclassName. Other edits leave the stylesheets alone. - A route-level
_middleware.tsmakes each navigation into its folder ask the server first (see Routing). In development that check is one more request per navigation. Handler middleware insrc/entry-server.tshas no such check.
Troubleshooting
- Port in use. Without
--strictPort, Vite tries the next free port and the banner shows the one it used. With--strictPort,dusk devexits with code 1 and saysPort <n> is already in use. - A tab that did not reload after a restart. The open tab reloads by itself once the server answers again. If it shows the old app, reload it.
- A broken config file. The error is printed with the file name. The server keeps the configuration it had until the file is fixed, and the next valid save restarts it again.
- The error overlay stays. It goes when the file that caused it is fixed and saved.
dusk dev takes these flags (the port and the host also come from the PORT and HOST variables and from server in
vite.config.ts, in that order of precedence):
npx dusk dev --port 4000 # listen on port 4000
npx dusk dev --host # listen on all interfaces; --host 127.0.0.1 for one address
npx dusk dev --strictPort # fail with exit code 1 instead of trying the next port
npx dusk dev --open # open the app in the default browser