Use ServeDir for fullstack dev static assets (#4983)
Without this patch, simply instantiating the Jumpstart template in fullstack mode and making _any_ hot-patch change would result in a 404 on fetch and a client WASM panic. This changes the fullstack server static asset routing so that, in debug builds, directories under the `public` tree (including `/wasm`) are 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` dynamic for directories in debug builds while preserving the existing behaviour elsewhere: - For debug builds (`cfg(debug_assertions)`), `serve_dir_cached` now uses `ServeDir::new(&path)` when it encounters a directory. This means `/wasm`, `/assets`, and any other subdirectories 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_dir_cached` continues to recurse and register 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.
This commit is contained in:
1 parent
8b427ddf16
commit
8c1911c268
1 file changed
+14
-2
@@ -403,7 +403,7 @@ fn serve_dir_cached<S>(mut router: Router<S>, public_path: &Path, directory: &Pa
|
||||
where
|
||||
S: Send + Sync + Clone + 'static,
|
||||
{
|
||||
use tower_http::services::ServeFile;
|
||||
use tower_http::services::{ServeDir, ServeFile};
|
||||
|
||||
let dir = std::fs::read_dir(directory)
|
||||
.unwrap_or_else(|e| panic!("Couldn't read public directory at {:?}: {}", &directory, e));
|
||||
@@ -426,7 +426,19 @@ where
|
||||
);
|
||||
|
||||
if path.is_dir() {
|
||||
router = serve_dir_cached(router, public_path, &path);
|
||||
// In debug builds, serve directories dynamically so new files (like
|
||||
// wasm patch modules) are immediately visible without rebuilding
|
||||
// the router. In release, keep the previous cached traversal
|
||||
// behaviour.
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
router = router.nest_service(&route, ServeDir::new(&path));
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
router = serve_dir_cached(router, public_path, &path);
|
||||
}
|
||||
} else {
|
||||
let serve_file = ServeFile::new(&path).precompressed_br();
|
||||
// All cached assets are served at the root of the asset directory. If we know an asset
|
||||
|
||||
Reference in new issue
Block a user