forked from 1b-agent/opencadstudio-upstream
fix: close the review findings on the restore-all/deep-links/PWA wave
Two reviewers, no blockers, three majors — all fixed. - The remembered-tab focus after a Restore-all batch fired at the message boundary, but the LAST restore's tab inserts one async round later (its OPFS recent-cache write precedes the insertion) and the insertion's own activation overwrote the selection. The focus flag now also consumes at the insertion point, so the batch focus holds in the common all-success case. - The service worker cached ANY successful in-scope navigation under the shell key — a direct navigation to a font or JSON would be served as the app shell for every offline navigation until the next online visit. Only the scope root caches as the shell now. - Local macOS builds broke: sha256sum does not exist there (shasum does) and BSD sed requires an explicit -i suffix. The wrapper picks the available hasher and uses a portable in-place edit. Also: '/app/' gets its own web app manifest (the previous commit's 'installable' claim was true only of the marketing site, whose start_url sits OUTSIDE the service worker's scope — an installed app opened offline showed an error page). The README now states the honest offline timing (assets captured on the second visit — the first visit's preloads outrun the installing worker) and the long-lived-window update behavior.
This commit is contained in:
1 parent
5f9b345ee6
commit
369e2c8b5a
8 files changed
+69
-9
No files matched your search
@@ -183,7 +183,7 @@ never go missing from the bundle):
|
||||
sh scripts/build-web.sh
|
||||
```
|
||||
|
||||
The bundle ships a service worker (`web/sw.js`, deployed at `/app/sw.js`) that caches the app shell: after one online visit the app starts fully offline and the ~55 MB wasm bundle is served from the browser cache instead of re-downloaded. `build-web.sh` stamps a hash of the finished bundle into `sw.js` as the cache version, so every deploy ships a fresh cache and stale ones are cleaned up automatically.
|
||||
The bundle ships a service worker (`web/sw.js`, deployed at `/app/sw.js`) that caches the app shell: after a first online visit registers it, the assets are captured on the following visit and the app then starts fully offline, the ~55 MB wasm bundle served from the browser cache instead of re-downloaded. A long-lived installed window keeps running its current version until all its tabs close (no mid-session disruption); the next launch picks up the update. `build-web.sh` stamps a hash of the finished bundle into `sw.js` as the cache version, so every deploy ships a fresh cache and stale ones are cleaned up automatically. `/app/` carries its own web app manifest, so the editor itself can be installed as a standalone app.
|
||||
|
||||
## Automation
|
||||
|
||||
|
||||
@@ -62,8 +62,11 @@ done
|
||||
echo "build-web.sh: dist/app/sw.js missing — is web/sw.js still listed as a copy-file link in web-app.html?" >&2
|
||||
exit 1
|
||||
}
|
||||
bundle_hash=$(find dist/app -type f ! -name sw.js -print0 | sort -z | xargs -0 sha256sum | sha256sum | cut -c 1-12)
|
||||
sed -i "s/^const CACHE_VERSION = \"[^\"]*\";/const CACHE_VERSION = \"$bundle_hash\";/" dist/app/sw.js
|
||||
# Portable hashing: macOS ships shasum (no sha256sum) and BSD sed needs an
|
||||
# explicit -i suffix — both handled so local builds work everywhere.
|
||||
if command -v sha256sum >/dev/null 2>&1; then H="sha256sum"; else H="shasum -a 256"; fi
|
||||
bundle_hash=$(find dist/app -type f ! -name sw.js -print0 | LC_ALL=C sort -z | xargs -0 $H | $H | cut -c 1-12)
|
||||
sed -i.bak "s/^const CACHE_VERSION = \"[^\"]*\";/const CACHE_VERSION = \"$bundle_hash\";/" dist/app/sw.js && rm -f dist/app/sw.js.bak
|
||||
grep -q "^const CACHE_VERSION = \"$bundle_hash\";" dist/app/sw.js || {
|
||||
echo "error: failed to stamp the cache version into dist/app/sw.js" >&2
|
||||
exit 1
|
||||
|
||||
+15
-4
@@ -1501,6 +1501,15 @@ impl OpenCADStudio {
|
||||
self.apply_display_defaults(idx);
|
||||
idx
|
||||
};
|
||||
// A Restore-all batch's LAST restore inserts its tab here — one
|
||||
// async round AFTER its settle message. The focus flag therefore
|
||||
// also fires here: the message-boundary hook alone could run
|
||||
// before this insertion and be overwritten by it.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if self.web_session_focus_pending && self.web_autosave_restore_all_remaining == 0 {
|
||||
self.web_session_focus_pending = false;
|
||||
self.select_remembered_session_tab();
|
||||
}
|
||||
|
||||
let mut recovery_report = recovery_needed.then(|| {
|
||||
crate::io::recovery::RecoveryReport::recovered(
|
||||
@@ -3556,19 +3565,19 @@ impl OpenCADStudio {
|
||||
/// from the after-message hook (`web_session_focus_pending`), so the
|
||||
/// whole settle batch — including the last tab insertion — is done.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub(super) fn select_remembered_session_tab(&mut self) {
|
||||
pub(super) fn select_remembered_session_tab(&mut self) -> Task<Message> {
|
||||
let Some(session) = self.web_session.as_ref() else {
|
||||
return;
|
||||
return Task::none();
|
||||
};
|
||||
let Some(remembered) = session.tabs.get(session.active) else {
|
||||
return;
|
||||
return Task::none();
|
||||
};
|
||||
let recovered = crate::io::web_autosave::recovered_name(remembered);
|
||||
let Some(index) = self.tabs.iter().position(|tab| {
|
||||
let name = tab.tab_display_name();
|
||||
name == remembered.as_str() || name == recovered
|
||||
}) else {
|
||||
return;
|
||||
return Task::none();
|
||||
};
|
||||
self.active_tab = index;
|
||||
// The active tab changed under the ribbon; re-sync its chips like
|
||||
@@ -3576,6 +3585,8 @@ impl OpenCADStudio {
|
||||
self.sync_ribbon_layers();
|
||||
self.sync_ribbon_styles();
|
||||
self.sync_ribbon_from_selection();
|
||||
|
||||
Task::none()
|
||||
}
|
||||
|
||||
/// Remember the open-tab list (names + active index) in localStorage —
|
||||
|
||||
@@ -297,7 +297,7 @@ impl OpenCADStudio {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if self.web_session_focus_pending {
|
||||
self.web_session_focus_pending = false;
|
||||
self.select_remembered_session_tab();
|
||||
return self.select_remembered_session_tab();
|
||||
}
|
||||
self.sync_open_command_history();
|
||||
// Close the document-level first-touch transaction started by
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="manifest" href="app.webmanifest" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="robots" content="noindex, follow" />
|
||||
@@ -46,6 +47,8 @@
|
||||
<link data-trunk rel="copy-file" href="web/locale-labels.json" />
|
||||
<link data-trunk rel="copy-file" href="web/ocs-control.js" />
|
||||
<link data-trunk rel="copy-file" href="web/sw.js" />
|
||||
<link data-trunk rel="copy-file" href="web/app.webmanifest" />
|
||||
<link data-trunk rel="copy-file" href="web/logo.svg" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="loading">
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Open CAD Studio",
|
||||
"short_name": "OCS",
|
||||
"description": "A free CAD editor for DWG and DXF drawings.",
|
||||
"start_url": "./",
|
||||
"scope": "./",
|
||||
"display": "standalone",
|
||||
"background_color": "#1e1e1e",
|
||||
"theme_color": "#1e1e1e",
|
||||
"icons": [
|
||||
{
|
||||
"src": "logo.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"purpose": "any"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<svg width="920" height="920" viewBox="0 0 920 920" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_12_11)">
|
||||
<rect width="920" height="920" fill="#1C2430"/>
|
||||
<path d="M166.001 472.8C149.001 468.7 133.301 455.5 125.001 438.4C118.801 425.7 119.001 428.6 119.001 336.7V252.7L121.801 244.4C129.001 223.7 147.401 207 168.001 202.7C173.301 201.6 182.601 201.2 205.801 201.2H236.501L236.301 228L236.001 254.7L211.001 255.2C183.801 255.7 182.901 255.9 177.301 261.9C171.301 268.1 171.501 266.1 171.501 337.3C171.501 383.2 171.801 403.6 172.601 406.3C174.201 411.5 179.001 417.1 183.901 419.3C187.501 420.9 190.801 421.2 212.201 421.2C225.501 421.2 236.501 421.5 236.701 422C236.901 422.4 236.901 434.3 236.701 448.5L236.301 474.2L203.701 474.1C181.601 474.1 169.401 473.6 166.001 472.8Z" fill="#327DE8"/>
|
||||
<path d="M250.501 473.8C250.101 473.4 250.001 458.8 250.401 428.5L250.501 421.2H274.501C300.701 421.2 303.201 420.8 308.801 415.4C310.401 413.9 312.701 410.9 313.801 408.7C316.001 404.7 316.001 404.4 316.001 338.2V271.7L313.801 267.5C312.501 265.2 310.301 262.1 308.801 260.6C303.401 255.5 301.501 255.2 275.001 255.2H250.501V228.1V201L284.301 201.4C315.601 201.8 318.501 202 324.501 204C343.501 210.3 359.801 226.8 365.801 245.7C368.001 252.7 368.001 252.8 368.001 338.2V423.7L365.301 431C358.301 450 345.101 463.7 327.001 470.9L320.001 473.7L285.501 474C266.501 474.2 250.701 474.1 250.501 473.8Z" fill="#327DE8"/>
|
||||
<path d="M631.575 473C631.275 472.2 631.175 460.9 631.275 447.7L631.575 423.7L693.075 423.2C762.275 422.6 758.575 423.1 765.675 414.9C770.475 409.2 771.275 405.6 770.875 391.1C770.575 379.4 770.375 378.3 767.875 374.4C766.375 372.2 762.975 369 760.375 367.5L755.575 364.7L719.075 364.1C690.575 363.6 681.075 363.1 675.775 361.8C652.475 356.3 632.975 337 627.575 314C625.475 305 625.475 261.1 627.575 252.7C632.875 231.7 647.675 215.5 668.875 207.4L675.575 204.8L741.575 204.2C789.775 203.8 807.875 204 808.575 204.8C809.175 205.5 809.575 215.3 809.475 230.3L809.375 254.7L751.475 255.2L693.575 255.7L689.875 258C684.775 261.2 680.375 266.5 679.175 270.9C678.575 273 678.075 279.2 678.075 284.7C678.075 296.1 679.675 300.6 685.175 305.9C691.675 312.1 692.575 312.2 729.275 312.2C753.275 312.3 764.775 312.7 770.375 313.7C790.575 317.3 810.275 332.7 818.475 351.3C823.075 361.8 824.075 369.3 824.075 393.4C824.075 419.2 823.075 425.6 817.275 437.7C809.475 453.9 796.175 465.4 778.075 471.5C771.675 473.7 770.775 473.7 701.775 474C645.075 474.2 631.975 474 631.575 473Z" fill="#F7F7F8"/>
|
||||
<path d="M450.3 472.1C439 469.1 429.7 463.7 421 455.1C412 446.2 407.2 437.9 403.6 425.6L401 416.5L401.3 336.1C401.7 256.8 401.7 255.5 403.8 249.3C410.3 230 425.1 214.9 444.9 207.2L451.6 204.6L522.4 204.3L593.1 204V229.6V255.1H533.4C497 255.1 472.2 255.5 470 256.1C465.2 257.4 458.2 263.6 456 268.5C454.3 272.4 454.1 276.6 454.1 339.1C454.1 401.6 454.3 405.8 456 409.7C458.3 414.6 464.8 420.4 470 421.9C472.7 422.8 491.1 423.1 533.5 423.1H593.1V448.6V474.1L525.4 474C462 474 457.1 473.9 450.3 472.1Z" fill="#F7F7F8"/>
|
||||
<rect x="672" y="517" width="12" height="81" fill="white"/>
|
||||
<rect x="672" y="691" width="12" height="81" fill="white"/>
|
||||
<rect x="725.5" y="650" width="12" height="93" transform="rotate(-90 725.5 650)" fill="white"/>
|
||||
<rect x="537.5" y="650" width="12" height="93" transform="rotate(-90 537.5 650)" fill="white"/>
|
||||
<rect x="649" y="616" width="58" height="57" stroke="#337CE5" stroke-width="18"/>
|
||||
<rect x="-193" y="1079.79" width="377.615" height="972" transform="rotate(-77.5907 -193 1079.79)" fill="#141D26"/>
|
||||
<rect x="-450" y="699.014" width="377.615" height="972" transform="rotate(-45 -450 699.014)" fill="#327DE8"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_12_11">
|
||||
<rect width="920" height="920" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -89,9 +89,13 @@ self.addEventListener("fetch", (event) => {
|
||||
event.respondWith(
|
||||
(async () => {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
// Only the scope root is the app shell: caching any other in-scope
|
||||
// navigation here would store e.g. a font or JSON body under the
|
||||
// shell key and serve it for every offline navigation.
|
||||
const isShell = new URL(request.url).pathname === SHELL_URL.pathname;
|
||||
try {
|
||||
const fresh = await fetch(request);
|
||||
await put(cache, SHELL_URL, fresh);
|
||||
if (isShell) await put(cache, SHELL_URL, fresh);
|
||||
return fresh;
|
||||
} catch {
|
||||
const cached = await cache.match(SHELL_URL);
|
||||
|
||||
Reference in new issue
Block a user