Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue client app should be created with createSSRApp for efficient client hydration #149

Open
2 tasks done
maoberlehner opened this issue Jul 9, 2022 · 3 comments
Open
2 tasks done
Labels
enhancement New feature or request

Comments

@maoberlehner
Copy link
Contributor

Description 馃摉

In multiple locations createApp is used instead of createSSRApp (e.g.,

const createVueApp = import.meta.env.SSR ? createSSRApp : createClientApp
). I think this prevents efficient client-side hydration.

When re-hydrating server-side rendered HTML, createSSRApp should also be used on the client to enable efficient re-hydration. See: https://vuejs.org/guide/scaling-up/ssr.html#client-hydration

Reproduction 馃悶

This can be reproduced with every Vue powered iles app.

Logs 馃摐

Not applicable.

Screenshots 馃摲

Not applicable.

@maoberlehner
Copy link
Contributor Author

maoberlehner commented Jul 9, 2022

Fixing this issue has two benefits:

  1. better hydration performance (Vue reuses the existing DOM)
  2. It allows for a nice pattern where you don't need to inline props data for rehydration.
<script setup lang="ts">
import { defineComponent, onServerPrefetch, ref } from 'vue';

const data = ref(null);

// Load data for client-side hydration
if (typeof window !== `undefined`) {
  // Top level await makes this an async component
  await new Promise((resolve) => {
    setTimeout(() => {
      data.value = { hello: 'World' };
      resolve(null);
    }, 1000);
  })
}

// Load data on the server
onServerPrefetch(async () => {
  await new Promise((resolve) => {
    setTimeout(() => {
      data.value = { hello: 'World' };
      resolve(null);
    }, 500);
  })
});
</script>

<template>
  <div>{{ data.hello }}</div>
</template>

This can be nice if you load a lot of data from an API and you don't want to inline it for rehydration. Instead, as soon as the component is hydrated, the data will be fetched again.

Currently, you get a flash of empty content for 1000ms. When using createSSRApp you always see World because the component is only re-rendered when the data is fetched. Until then, the SSR content is shown.

@ElMassimo
Copy link
Owner

Thanks for reporting Markus! 馃槂

It makes sense to use createSSRApp in both cases when in build mode.

Need to check whether it would still be desirable to use createApp during development (for example, verify if Vue logs any warnings when using createSSRApp when the HTML has not been rendered).

PRs are welcome! 馃槂

I'll take a look during the week.

@ElMassimo ElMassimo added the enhancement New feature or request label Jul 11, 2022
@ElMassimo
Copy link
Owner

I've explored switching to createSSRApp, but it doesn't seem to be working as intended.

There are some problems when Vue components should be re-rendered which suggest that the optimizations performed by the Vue compiler don't hold with the way that the rendered HTML is inserted.

For example, running the docs site with pnpm docs, the DarkModeSwitch component is not re-rendered correctly when toggling the theme.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants