forked from 1b-agent/fieldcraft-upstream
Web: offer Reload to update when a new deployment is out (#231)
Every half hour the page fetches its own address past the browser's cache; when it loads another content-hashed build of the app than the running one, the status bar offers "Reload to update" (the page's unsaved-changes question still guards the reload). Rust only, no service worker: the browser build has no other update path and none of the desktop's download code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
7dd50a3ca4
commit
93b2ae343c
6 files changed
+145
-3
No files matched your search
@@ -18,6 +18,8 @@
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod deploy;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod storage;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@@ -45,6 +47,25 @@ fn sample_in_query(query: &str) -> Option<String> {
|
||||
})
|
||||
}
|
||||
|
||||
/// The build of the app a page loads: the content-hashed name Trunk gives its WebAssembly
|
||||
/// (`fieldcraft-web-<hash>_bg.wasm`). A new deployment loads another one.
|
||||
#[cfg_attr(not(target_arch = "wasm32"), allow(dead_code))]
|
||||
fn build_in_page(html: &str) -> Option<&str> {
|
||||
const HEAD: &str = "fieldcraft-web-";
|
||||
const TAIL: &str = "_bg.wasm";
|
||||
let mut rest = html;
|
||||
while let Some(at) = rest.find(HEAD) {
|
||||
let candidate = rest.get(at..)?;
|
||||
let hash = candidate.get(HEAD.len()..)?;
|
||||
let len = hash.bytes().take_while(u8::is_ascii_alphanumeric).count();
|
||||
if len > 0 && hash.get(len..)?.starts_with(TAIL) {
|
||||
return candidate.get(..HEAD.len() + len + TAIL.len());
|
||||
}
|
||||
rest = candidate.get(HEAD.len()..)?;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// The name a file from the computer is kept under in the page: its last path part, without
|
||||
/// characters a path would read as folders.
|
||||
#[cfg_attr(not(target_arch = "wasm32"), allow(dead_code))]
|
||||
@@ -67,6 +88,18 @@ mod tests {
|
||||
assert_eq!(sample_in_query("?samples=x"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_running_build_is_found_in_the_page() {
|
||||
let page = r#"<link rel="modulepreload" href="/fieldcraft/fieldcraft-web-1a2b3c.js"><link rel="preload" href="/fieldcraft/fieldcraft-web-1a2b3c_bg.wasm" as="fetch">"#;
|
||||
assert_eq!(build_in_page(page), Some("fieldcraft-web-1a2b3c_bg.wasm"));
|
||||
let next = page.replace("1a2b3c", "9f8e7d");
|
||||
assert_ne!(build_in_page(page), build_in_page(&next));
|
||||
// A development page (no hash) and other text: nothing to compare.
|
||||
assert_eq!(build_in_page(r#"<script src="fieldcraft-web.js"></script>"#), None);
|
||||
assert_eq!(build_in_page("fieldcraft-web-"), None);
|
||||
assert_eq!(build_in_page(""), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_names_stay_in_their_folder() {
|
||||
assert_eq!(safe_name("beam.fieldcraft"), "beam.fieldcraft");
|
||||
|
||||
Reference in new issue
Block a user