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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BTabs does not work in SSR due to window access #187

Closed
kikuomax opened this issue Jan 28, 2024 · 4 comments · Fixed by #196
Closed

BTabs does not work in SSR due to window access #187

kikuomax opened this issue Jan 28, 2024 · 4 comments · Fixed by #196
Assignees
Labels
bug Something isn't working
Milestone

Comments

@kikuomax
Copy link
Collaborator

Overview of the problem

Buefy version: [0.1.3-2f266cfe49988cf13ffdd360a4da48d00a1c13c5]
Vuejs version: [3.4.14]
OS/Browser: macOS/Safari

Description

<b-tabs> failed with the following error when I tried it in server side rendering (SSR) on Nuxt 3.

[nuxt] [request error] [unhandled] [500] window is not defined
  at makeUniqueId (./node_modules/.pnpm/@ntohq+buefy-next@0.1.3-2f266cfe49988cf13ffdd360a4da48d00a1c13c5_vue@3.4.15/node_modules/@ntohq/buefy-next/dist/cjs/TabbedChildMixin-dt_xg6R8.js:134:3)  
  at _default (./node_modules/.pnpm/@ntohq+buefy-next@0.1.3-2f266cfe49988cf13ffdd360a4da48d00a1c13c5_vue@3.4.15/node_modules/@ntohq/buefy-next/dist/cjs/TabbedChildMixin-dt_xg6R8.js:154:18)  
  at resolvePropValue (./node_modules/.pnpm/@vue+runtime-core@3.4.15/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4185:53)  
  at setFullProps (./node_modules/.pnpm/@vue+runtime-core@3.4.15/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4161:20)  
  at initProps (./node_modules/.pnpm/@vue+runtime-core@3.4.15/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4012:3)  
  at setupComponent (./node_modules/.pnpm/@vue+runtime-core@3.4.15/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7507:3)  
  at renderComponentVNode (./node_modules/.pnpm/@vue+server-renderer@3.4.15_vue@3.4.15/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:635:15)  
  at renderVNode (./node_modules/.pnpm/@vue+server-renderer@3.4.15_vue@3.4.15/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:767:14)  
  at renderVNodeChildren (./node_modules/.pnpm/@vue+server-renderer@3.4.15_vue@3.4.15/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:783:5)  
  at renderVNode (./node_modules/.pnpm/@vue+server-renderer@3.4.15_vue@3.4.15/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:755:7)

Steps to reproduce

The following is the Vue component I tried:

<script setup lang="ts">
const activeTab = ref(0)
</script>

<template>
  <div>
    <b-tabs v-model="activeTab">
      <b-tab-item label="Tab1">
        Tab1 content
      </b-tab-item>
      <b-tab-item label="Tab2">
        Tab2 content
      </b-tab-item>
      <b-tab-item label="Tab3">
        Tab3 content
      </b-tab-item>
    </b-tabs>
  </div>
</template>

Please refer to this discussion for how to use Buefy-next on Nuxt 3.

Expected behavior

<b-tabs> is rendered in SSR without errors.

Actual behavior

<b-tabs> was not rendered in SSR. See description.

@kikuomax kikuomax added the bug Something isn't working label Jan 28, 2024
@kikuomax
Copy link
Collaborator Author

The function makeUniqueId caused the error tried to generate a random value, but depending on randomly generated values is also bad for SSR.
https://vuejs.org/guide/scaling-up/ssr.html#hydration-mismatch

@kikuomax kikuomax self-assigned this Feb 16, 2024
@kikuomax
Copy link
Collaborator Author

We could use uid instead of a random number. uid is a member of ComponentInternalInstance. Wrap value in a computed value, like uniqueValue, and use it instead of directly accessing value:

computed: {
  uniqueValue() {
    return this.value ?? this.$.uid
  }
}

@kikuomax
Copy link
Collaborator Author

PoC worked!

@kikuomax
Copy link
Collaborator Author

I think this issue should be solved together with:

@kikuomax kikuomax added this to the v0.1.3 milestone Feb 22, 2024
kikuomax added a commit that referenced this issue Mar 8, 2024
…ed issue (#194) (#196)

* feat(lib): make Dropdown stop using ProviderParentMixin

- `Dropdown` stops mixing in `ProviderParentMixin` but just `provide`s
  its instance associated with `DROPDOWN_INJECTION_KEY` because
  `Dropdown` does not use any funcitionalities of `ProviderParentMixin`.
- `DropdownItem` stops mixing in `InjectedChildMixin` but just `inject`s
  the instance of `Dropdown` associated with `DROPDOWN_INJECTION_KEY`.
- `DROPDOWN_INJECTION_KEY` is a unique `Symbol`.
- Updates also the spec.

* feat(lib): make Progress stop using ProviderParentMixin

- `Progress` stops mixing in `ProviderParentMixin` but `provide`s its
  instance associated with `PROGRESS_INJECTION_KEY` because `Progress`
  does not use any functionalities of `ProviderParentMixin`.
- `ProgressBar` stops mixin in `InjectedChildMixin` but `inject`s the
  instance of `Progress` associated with `PROGRESS_INJECTION_KEY`.
- `PROGRESS_INJECTION_KEY` is a unique `Symbol`.
- Updates the spec for `ProgressBar`. It also introduces a new test case
  that tests `ProgressBar` reads `max` from the parent `Progress`.
  Refreshes the spec snapshot.

* fix(lib): BTabs did not work in SSR, and BCarousel

- The issue that `BTabs` did not work in Server Side Rendering (SSR)
  due to `window` access. `window` was necessary to generate a random
  number to initialize `value` prop of `BTabItem` with a unique value
  when `value` is omitted. Before Vue 3 migration, it used to use
  `this._uid` internal field to initialze `value`. However, `this` is no
  longer available during the prop initialization on Vue 3. So I came up
  with the idea of random numbers. Since random numbers also won't work
  well with SSR, we had to give up random numbers anyway. A new approach
  is to avoid direct use of `value` prop but computed `uniqueValue`
  which becomes `value` if it is non-null, otherwise `this.$.uid`
  internal field. Definitions of `value` and `uniqueValue` are hoisted
  to `InjectedChildMixin` which `BTabs` mixes in through
  `TabbedChildMixin` because there was another problem with
  `CarouselItem` (see below).

- `CarouselItem` is another component that mixes in
  `InjectedChildMixin`. There was a bug that `CarouselItem` was not able
  to be correctly removed from the parent `Carousel`. This bug is also
  fixed by defining `value` and `uniqueValue` in `InjectedChildMixin`.

- `ProviderParentMixin`, `TabbedMixin`, `TabbedChildMixin`, `Tabs`,
  `Steps`, and `CarouselItem` use `uniqueValue` instead of `value`
  whenever the identity of the child matters.

- `Carousel` introduces `activeChildIndex` that `CarouselItem` uses to
  determine the item is active, because `activeChild` of `Carousel` is
  an index in the array that `Carousel` locally holds and may not match
  the `index` that `CarouselItem` recognizes.

- `utils/make-unique-id.js` no longer necessary.

- Introduces new test cases for `TabItem`, `StepItem`, and
  `CarouselItem` that make sure `uniqueValue` and `order` work.
  Refreshes the spec snapshot of `CarouselItem`.

* feat(docs): add CarouselItem show/hide

- `ExFull` example for `Carousel` introduces a new switch to show/hide a
  certain slide in `Carousel`. This makes sure that `order` prop of
  `CarouselItem` works.

* style(docs): fix lint error

* feat(docs): introduce order prop

- Examples of `Carousel`, `Steps`, and `Tabs` explain how to use `order`
  prop.

* docs: update CHANGELOG

- `CHANGELOG` explains `order` prop of `CarouselItem`, `StepItem`, and
  `TabItem`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: ✅ Done
Development

Successfully merging a pull request may close this issue.

1 participant