vuejs / vitepress

Vite & Vue powered static site generator.
https://vitepress.dev
MIT License
13.29k stars 2.15k forks source link

need `onAfterPageLoad` in useRouter #4113

Closed lejunyang closed 2 months ago

lejunyang commented 3 months ago

Is your feature request related to a problem? Please describe.

I want to add document transitions when document route changes, here is my current solution using useRouter and document.startViewTransition:

const router = useRouter();
let routeResolve: (() => void) | undefined,
  transitionReady: Promise<any> | undefined
router.onBeforeRouteChange = () => {
  if (document.startViewTransition) {
    transitionReady = document.startViewTransition(async () => {
      const { promise, resolve } = Promise.withResolvers();
      routeResolve = resolve;
      return promise;
    }).ready;
  }
};
router.onAfterRouteChanged = async () => {
  if (routeResolve) {
    routeResolve();
    routeResolve = undefined;
  }
  if (transitionReady) {
    await transitionReady;
    transitionReady = undefined;
    // do the animation
  }
};

It worked very well, but then I found that it may take some time to load new page. The whole page looks stuck until new page loads, especially when network is poor. So I want to add a loading bar on top of the page and remove it before document transition.

Then I encountered the issue, If I add a loading bar in onBeforeRouteChange and remove it in onAfterRouteChanged, it didn't work at all as DOM changes were snapshotted during transition preparation, it only showed after the transition was ready.

Besides, using startViewTransition in onBeforeRouteChange is not a good option, as new page can have long loading time. Document transition will throw a timeout error if no DOM changes. The right time calling startViewTransition should be after page loads, before component updates.

Describe the solution you'd like

Therefore, I think we need onAfterPageLoad in useRouter. I could add loading bar in onBeforeRouteChange, remove it and start document transition in onAfterPageLoad, then do the animation in onAfterRouteChanged I want to make a PR for this, kindly give some inputs

Describe alternatives you've considered

No response

Additional context

No response

Validations

lejunyang commented 3 months ago

I tested with below patch for vitepress@1.3.2:

diff --git a/dist/client/app/router.js b/dist/client/app/router.js
index 3deaefe382586bdff92597fd8daf85b14bbc4f73..bb046ddf64b0a542ecda715c9453442830159f51 100644
--- a/dist/client/app/router.js
+++ b/dist/client/app/router.js
@@ -46,6 +46,7 @@ export function createRouter(loadPageModule, fallbackComponent) {
                 if (!comp) {
                     throw new Error(`Invalid route component: ${comp}`);
                 }
+                await router.onAfterPageLoad?.()
                 route.path = inBrowser ? pendingPath : withBase(pendingPath);
                 route.component = markRaw(comp);
                 route.data = import.meta.env.PROD

it worked well