Skip to content

feat: implement startup splash screen and loading behavior - #1974

Open
ChrisTouo wants to merge 3 commits into
mainfrom
1958-app-loading-page-not-showing
Open

feat: implement startup splash screen and loading behavior#1974
ChrisTouo wants to merge 3 commits into
mainfrom
1958-app-loading-page-not-showing

Conversation

@ChrisTouo

Copy link
Copy Markdown
Collaborator

The splash lived in App.vue, so it could not appear until app.mount() — the
second-to-last step of Startup(). Everything slow (Dexie open, schema upgrades,
OIDC setup) ran before that against an empty #app, and the only work left after
it was initLanguage(), a local IndexedDB read on a warm cache. That can resolve
within a single animation frame, so the splash often never painted at all, while
the part of the boot that actually takes time showed a blank page.

Mounting earlier is not an option. app.use(router) starts the router's initial
navigation, and isNotAuthenticatedGuard gates on isAuthPluginInstalled, which
only setupAuth() sets — running the guard first makes a logged-in user look
logged out on a cold load.

So the splash moves out of Vue. index.html carries it as plain HTML/CSS and
paints it on first parse, with a pre-paint script that resolves the theme the way
globalConfig does (darkMode is "class", so nothing sets that class until the
first module runs). It uses /logo.svg from public/ rather than VITE_LOGO, whose
configured value is page-relative and 404s below the root. main.ts removes it
once startup finishes, after a nextTick so the app is already painted underneath
and uncovering cannot expose a blank frame.

The web/SSG build strips it in the existing rewriteWebEntry transform: that build
ships already-rendered HTML with no blank window to cover, and it boots
main.web.ts instead of main.ts, so nothing there would ever remove the overlay.

With index.html owning the splash, App.vue's copy sat under an opaque overlay for
every frame it existed, so it is removed; isAppLoading still gates the app
content, the KeepAlive and the modals.

@ChrisTouo ChrisTouo linked an issue Aug 31, 2026 that may be closed by this pull request

@johan-bell johan-bell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified this hands-on — the core is excellent: the pre-paint theme script exactly mirrors globalConfig's resolution (dark / light / else system + matchMedia), /logo.svg exists in public/ so the root-absolute path works at any route depth, the strip in rewriteWebEntry is correct, and bootSplash.spec.ts tying the three drift-prone pieces together is a really nice touch. Three things before it can go in:

  • Error path: Startup().catch calls markAppError() but never removes the splash, and the splash has no error state — a failed boot now shows an infinitely animating progress bar. The catch should swap the splash to an error message (or at least remove it). #1972 solves this with a data-render-state="error" panel + Reload button worth borrowing.
  • ?nosplash regression: isAppLoading honours it but the static splash doesn't, so consumers of the opt-out now get a splash that stays up until startup finishes. A one-line guard in the pre-paint script fixes it.
  • Collision with #1972: that PR also injects a static boot splash (inside #app, via a Vite plugin, with error/reload, nosplash and prefers-reduced-motion handling). Both cannot merge as-is — please converge on one implementation with Dirk. This PR's placement (outside #app, removed after full startup with the nextTick trick) covers the boot more completely; #1972's error panel and opt-outs are the missing half.

Minor: the hardcoded English "Loading..." is new user-visible text (the old splash was logo-only), and deployments configuring VITE_LOGO will show the default logo during boot.

@ChrisTouo
ChrisTouo force-pushed the 1958-app-loading-page-not-showing branch from fa0d1fe to 85782b6 Compare September 1, 2026 23:18
ChrisTouo added a commit that referenced this pull request Sep 2, 2026
Both this branch and #1974 add a static boot splash, so only one can land.
#1974 keeps the splash and has absorbed this branch's error panel, ?nosplash
guard and reduced-motion handling; this branch keeps the recovery work the
splash reports through — the bounded database opens, the initLanguage timeout
and the boot watchdog.

The placement assertion goes with it: #1974 renders the splash as a sibling
after #app rather than inside it, so that test can no longer hold here. The
remaining cases assert the ids, classes and data-render-state contract #1974
preserved, and need its splash deployed to run green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ChrisTouo
ChrisTouo force-pushed the 1958-app-loading-page-not-showing branch from 5fbe93d to 5ed5d71 Compare September 3, 2026 07:19
@ivanslabbert

Copy link
Copy Markdown
Contributor

Remove the "Loading..." text and make sure the graphics is intuitive enough to indicate to the user that the app is loading

@ivanslabbert

Copy link
Copy Markdown
Contributor

Check why timers are used as guardrails. There must be a better way to detect when indexedDb is unblocked

@ChrisTouo

Copy link
Copy Markdown
Collaborator Author

Why the change in database.ts

A deploy that changes the docs index bumps the IndexedDB version. IndexedDB can't apply that upgrade while other tabs still hold the old version open, so the browser fires versionchange on those tabs and blocks the upgrading one.

Dexie already handles this by closing the old connection so the upgrade can proceed, and we keep that — holding on would block the other tab indefinitely. What we add is what happens next: a background tab just closes and reopens lazily, but a visible tab is running code built for the old schema, so it reloads onto the new version instead of carrying on against a database it can no longer use.

Separately, blocked is no longer treated as an error. It means "waiting for another connection to close," which resolves on its own, so the boot waits instead of failing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

APP: Loading page not showing

3 participants