ElMassimo / iles

๐Ÿ The joyful site generator
https://iles.pages.dev
MIT License
1.07k stars 31 forks source link

client:visible hydration results in removal of element from DOM post hydration #172

Closed manish-butterpaper closed 2 years ago

manish-butterpaper commented 2 years ago

Description ๐Ÿ“–

Whenever a hydration directive is used for a component within a "page", the component gets perfectly rendered and server side rendered, but as soon as the component is hydrated, the DOM element goes blank.

We keep getting following error in console:

runtime-core.esm-bundler.js:38 [Vue warn]: Component <Anonymous>: setup function returned a promise, but no <Suspense> boundary was found in the parent component tree. A component with async setup() must be nested in a <Suspense> in order to be rendered. 
  at <Counter > 
  at <Island: Counter>

Reproduction ๐Ÿž

The root index.vue page has as following component:

  <Suspense>
    <template #default>
      <Counter client:visible>
        <h1>Hello, Vue!</h1>
      </Counter>
    </template>
    <template #fallback>
      <span>Loading...</span>
    </template>
  </Suspense>

And the counter.vue component is simple as well:

<template>
  <h1 class="font-bold">Admins:</h1>
  <h1>Posts: {{ posts }}</h1>
</template>

<script setup lang="ts">
import fetch from 'cross-fetch';

const res = await fetch('https://jsonplaceholder.typicode.com/posts')
const posts = await res.json();
</script>

Interestingly, if the above counter component is nested within another component which was client:visible hydrated, the SSR and client side hydration both works.

Default dependencies used _Run `npx iles info` and `pnpm list` (or `npm list`) and provide the output:_ `npx iles info` ``` iles v0.8.2 vite v3.0.3 ``` `pnpm list` ``` dependencies: @headlessui/vue 1.6.7 @iconify/vue 3.2.1 @nanostores/vue 0.5.5 @rollup/plugin-graphql 1.1.0 animejs 3.2.1 cross-fetch 3.1.5 graphql 16.5.0 graphql-ws 5.9.1 nanostores 0.5.12 vite-plugin-windicss 1.8.7 devDependencies: iles 0.8.2 typescript 4.7.4 vue-tsc 0.38.9 ```

Logs ๐Ÿ“œ

If not providing a reproduction:

Output _Run `DEBUG=iles:* npm run dev` or `DEBUG=iles:* npm run build` and provide the output:_ ``` ```

Screenshots ๐Ÿ“ท

Provide console or browser screenshots of the problem.

ElMassimo commented 2 years ago

Hi there!

Seems like it's a Vue usage problem, the warning you are getting is hinting:

A component with async setup() must be nested in a in order to be rendered.

The only reason you can async setup outside islands, is that for convenience, รฎles wraps the entire app in Suspense, but that's no longer the case once the site is built.

Since each island will be its own independent app, it won't have a wrapping Suspense, so you shouldn't use await res.json() in script setup of an island component.

If you need it, you could explicitly add Suspense inside the island, wrapping another component which is async.

Feel free to reopen it if it's something else.

manish-butterpaper commented 2 years ago

@ElMassimo got it working with your suggestions! Thanks. Off topic but another thing I wanted to ask was regarding authentication. I understand the output of build is complete SSG, but Astro also gives the options to configure server side configs like cookie reads etc.

Can we get a deeper integration with Vercel where we can use their Edge functions for authentication/SSR/ISR and other advanced use cases?

ElMassimo commented 2 years ago

At the moment รฎles only targets SSG.

I have considered adding support for SSR at some point, but at the moment I don't have a need for it, and Nuxt 3 is already a great option if you need that.

manish-butterpaper commented 2 years ago

I evaluated Nuxt but then we loose the partial hydration/islands based architecture. The entire shift towards Astro/Iles is because of 0 JS ship feature. Isn't it?