Skip to content

Commit 88110a7

Browse files
committed
Use ServeDir for fullstack dev static assets
**Without this patch, simply instantiating the Jumpstart template in fullstack mode and making _any_ hot-patch change results in a 404 on fetch and a client WASM panic.** This changes the fullstack server static asset routing so that, in debug builds, the `public` tree (including `/wasm`) is served via `tower_http::services::ServeDir` instead of being eagerly expanded into a fixed set of routes at startup. Today `dioxus_server::DioxusRouterExt::serve_static_assets` walks the `public` directory once at launch via `serve_dir_cached`, registering a separate route for every file it sees. That works fine for pre-baked assets, but it breaks down when dx/subsecond writes new files into `public` during a dev session. In a fullstack web app, wasm hot patches are emitted as timestamped files like `public/wasm/lib<name>-patch-<ts>.wasm`; the CLI tells the browser to fetch `/wasm/lib<name>-patch-<ts>.wasm` immediately, but the fullstack server never registered a route for that path, so the fetch returns 404 even though the file already exists on disk. Non-fullstack dev builds do not have this problem because the dx devserver serves `public` directly using `ServeDir`, which consults the filesystem at request time. Fullstack dev, by contrast, proxies asset requests to the inner server, and that server only knows about whatever was in `public` at the moment its router was built. This change narrows the gap by making `serve_static_assets` use `ServeDir` in debug builds while preserving the behaviour of `serve_dir_cached` elsewhere: - For debug builds (`cfg(debug_assertions)`), `serve_static_assets` now returns `self.nest_service("/", ServeDir::new(public_path))`. This means `/wasm`, `/assets`, and any other subpaths are backed by a live directory listing, so new files like wasm patch modules and freshly emitted hashed CSS become immediately visible without restarting the fullstack server or rebuilding its router. - For non-debug builds, the previous behaviour is preserved: `serve_static_assets` continues to call `serve_dir_cached`, which recurses and registers one route per discovered file, still using `ServeFile::precompressed_br()` and `cache_response_forever` for hashed, cache-busted filenames. This is a no-op for release builds, but in debug fullstack it's necessary for wasm hot patches and other dynamically-created assets that could 404 until the server happened to be restarted. It also aligns fullstack dev behaviour more closely with the plain web devserver, which already uses `ServeDir` for the `public` tree.
1 parent b084432 commit 88110a7

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

packages/fullstack-server/src/server.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,22 @@ impl DioxusRouterExt for Router<FullstackState> {
151151
return self;
152152
};
153153

154-
// Serve all files in public folder except index.html
155-
serve_dir_cached(self, &public_path, &public_path)
154+
// In dev builds, serve the entire `public` tree dynamically with
155+
// ServeDir so new assets (like wasm patch modules) are visible
156+
// immediately without rebuilding the fullstack server router.
157+
#[cfg(debug_assertions)]
158+
{
159+
use tower_http::services::ServeDir;
160+
return self.nest_service("/", ServeDir::new(public_path));
161+
}
162+
163+
// In release builds, use cached, per-file routing so
164+
// hashed assets can be marked immutable.
165+
#[cfg(not(debug_assertions))]
166+
{
167+
// Serve all files in public folder except index.html
168+
serve_dir_cached(self, &public_path, &public_path)
169+
}
156170
}
157171

158172
fn serve_api_application<M: 'static>(

0 commit comments

Comments
 (0)