Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(useSSRWidth): add optional support for SSR in useMediaQuery and useBreakpoints #4317

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

Merged
merged 8 commits into from
Dec 22, 2024

Conversation

Tofandel
Copy link
Contributor

@Tofandel Tofandel commented Oct 31, 2024

Before submitting the PR, please make sure you do the following

  • Read the Contributing Guidelines.
  • Read the Pull Request Guidelines.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Ideally, include relevant tests that fail without this PR but pass with it.

Description

Fixes #4102

By adding an optional ssrSize option to useBreakpoints and useMediaQuery we can mock their behavior until hydration happens to avoid mismatch error

Tests which did not exist for them could now be added thanks to this feature

Notable fixes:

  • the breakpoints are now sorted in ascending order in the current() method, this is to avoid the case of a user passing unordered breakpoints causing active to be wrong
  • the current() method now returns the list of active breakpoint in accordance with the strategy option it previously did not respect it
  • the types returned from useBreakpoints are now correct, previously active which was a function was not typed as one

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. enhancement New feature or request labels Oct 31, 2024
@Tofandel Tofandel force-pushed the patch-1 branch 3 times, most recently from f3c66ad to 3783e94 Compare December 18, 2024 11:39
@antfu
Copy link
Member

antfu commented Dec 18, 2024

Oh, that's brilliant! I was about to say that it's not possible to know the size of the client on the server side, but yeah, this feature at least provides a solution to that!

@Tofandel Tofandel force-pushed the patch-1 branch 3 times, most recently from 8c10887 to fa083a3 Compare December 18, 2024 16:57
},
{ immediate, flush: 'post' },
)
() => [targets.value, unrefElement(root as MaybeComputedElementRef), isActive.value] as const,
Copy link
Contributor Author

@Tofandel Tofandel Dec 18, 2024

Choose a reason for hiding this comment

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

Seems like there is a few lint issues that need fixing in the base, though unsure why it only started to popup now

@userquin
Copy link
Contributor

I was about to say that it's not possible to know the size of the client on the server side, but yeah, this feature at least provides a solution to that!

There is a way using HTTP Client Hints via Critical Client Hints, but only on chromium based browsers:

@Tofandel
Copy link
Contributor Author

Tofandel commented Dec 18, 2024

@userquin Yep, though it's a bit of an unreliable API in that it will only apply to future requests (unless using Critical-CH which will reload the first request), and browser support is only chromium (https://caniuse.com/mdn-http_headers_accept-ch_dpr), and also the client headers are somehow marked deprecated https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Width (seems it's in the process of being replaced with sec-ch-viewport-width) but you should be able to set the header on the nuxt server for all request and retrieve the client width using useRequestHeaders through useState and use it in the ssrWidth option

The headers from this HTTP API can be seen on https://browserleaks.com/client-hints

Maybe we should provide a small composable for the nuxt package only where we use useRequestHeaders and useState and provide it by default to all composables that need a SSR width. The core would just need a setup method to share this value everywhere, this would avoid some Content Layout Shift on the page
@antfu What do you think about adding this feature to the nuxt package?

I didn't test this yet, but it would look something like this edbad77

@antfu
Copy link
Member

antfu commented Dec 19, 2024

Yeah, Critical Client Hints would be an interesting approach for this, but I agree it's more on the framework integration scope. I think we could have this feature first and discuss if we could provide better integration for Nuxt later.

@Tofandel Tofandel requested a review from antfu December 19, 2024 12:01
@antfu antfu changed the title feat: add optional support for SSR in useMediaQuery and useBreakpoints feat(useSSRWidth): add optional support for SSR in useMediaQuery and useBreakpoints Dec 20, 2024
@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Dec 20, 2024
@antfu antfu merged commit 559653c into vueuse:main Dec 22, 2024
4 checks passed
@ashokgelal
Copy link

I'm working on getting a minimal repro example (my setup is fairly complex so trying to carve it out) but just for the time being - I upgraded to 12.1.0 and getting node_modules/@vueuse/core/index.mjs?v=d9158410' does not provide an export named 'useSSRWidth' error. This is a NuxtJS project with ssr set to false.

@ashokgelal
Copy link

Spent too much time trying to repro but what problem hasn't been solved by just deleting node_modules? 😅 No longer an issue

@xak2000
Copy link

xak2000 commented Jan 23, 2025

Any hints on how to properly use this new feature?

I tried to use it like this:

const breakpoints = useBreakpoints(breakpointsTailwind, { ssrWidth: 768 })

But the problem is that as soon as I set ssrWidth the client width is not taken into account anymore. So, if I set { ssrWidth: 768 }, then even on a large screen the result (on the client, after hydration) is { "sm": true, "md": true, "lg": false, "xl": false, "2xl": false }. If I remove { ssrWidth: 768 } parameter, then all works fine ({ "sm": true, "md": true, "lg": true, "xl": false, "2xl": false }), but obviously Hydration mistmatch problem appears.

I use @vueuse/core@npm:12.5.0, @vueuse/nuxt@npm:12.5.0.

Is it supposed to work this way? I'm just trying to understand what exactly does this feature do. The docs are scarce about this.

What exactly should happen when ssrWidth is set? I understand that it uses this width on the server rendering, but what should happen next? Should the values be "corrected" after hydration to values based on the real screen size (with jumpy layout effect)? Or ssrWidth will override the client's values even after hydration, like it does in my case?

A reproduce: https://stackblitz.com/edit/nuxt-starter-bt55593r?file=app.vue

@Tofandel
Copy link
Contributor Author

Tofandel commented Jan 24, 2025

Should the values be "corrected" after hydration to values based on the real screen size (with jumpy layout effect)?

Yes on mounted the values are corrected and yes if the values don't match you get a jump

This seems to be a reactivity issue with the object props as other methods like current() (which uses the shortcut object keys under the hood) don't have this issue

@Tofandel
Copy link
Contributor Author

Tofandel commented Jan 24, 2025

Yes this issue appears because the properties are behind a getter and reevaluated on each pass, but it uses a composable under the hood, and the composable is not meant to be called/initialized all of the time, it should only happen within the component setup, but right now it's being called every time vue rerenders, if you keep a reference to the shortcut, this does not happen

https://stackblitz.com/edit/nuxt-starter-cnydzchs?file=app.vue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

useBreakpoint and useMediaQuery cause "Hydration text mismatch" on Nuxt
5 participants