5

I was trying to determined UserAgent and Retina info inside Nuxt application. But the application is throwing an error and showing navigatior / window is undefined. How can i get these info inside nuxt application?

const userAgent = navigator.userAgent.toLowerCase()
const isAndroid = userAgent.includes('android')
isRetina() {
  let mediaQuery
  if (typeof window !== 'undefined' && window !== null) {
    mediaQuery =
      '(-webkit-min-device-pixel-ratio: 1.25), (min--moz-device-pixel-ratio: 1.25), (-o-min-device-pixel-ratio: 5/4), (min-resolution: 1.25dppx)'
    if (window.devicePixelRatio > 1.25) {
      return true
    }
    if (window.matchMedia && window.matchMedia(mediaQuery).matches) {
      return true
    }
  }
  return false
}
kissu
  • 40,416
  • 14
  • 65
  • 133
Tanvir Rahman
  • 651
  • 1
  • 11
  • 31
  • Hi for some reason even after following the steps you have mentioned it does not seem to work and I am getting `document is not defined` error. I have posted my question here can you please help me out with this? https://stackoverflow.com/q/69814456/7584240 – BATMAN_2008 Nov 02 '21 at 20:20

1 Answers1

14

This is the solution to fix:

  • navigator is undefined
  • window is undefined
  • document is not defined

Here is an example on how you should wrap your logic JS code

<script>
import { jsPlumb } from 'jsplumb' // client-side library only, no SSR support

export default {
  mounted() {
    if (process.client) {
      // your JS code here like >> jsPlumb.ready(function () {})
    }
  },
}
</script>

As shown here: https://nuxtjs.org/docs/2.x/internals-glossary/context

PS: mounted + process.client are kinda redundant because mounted only runs on the client.


Also, wrapping your component into <client-only> if you want it to be only client side rendered is also a good idea.

<template>
  <div>
    <p>this will be rendered on both: server + client</p>
    
    <client-only>
      <p>this one will only be rendered on client</p>
    </client-only>
  <div>
</template>

The documentation for this one is here: https://nuxtjs.org/docs/2.x/features/nuxt-components/#the-client-only-component

PS: beware because this client-only tag will only skip the rendering, not the execution, as explained here.


Some packages do not support SSR when you import them, for that you could either:

  • use a condition with a dynamic import (if the library is meant to be used later on)
  • directly like this (if you want to load a component like vue-editor)
export default {
  components: {
    [process.client && 'VueEditor']: () => import('vue2-editor'),
  }
}
kissu
  • 40,416
  • 14
  • 65
  • 133
  • Is it possible to assign then a name to the component with this syntax? (I'm trying to use this trick with `VueTouch`, but I have to name it `v-touch` to make it work) – Joe82 May 02 '22 at 15:40
  • @Joe82 `[process.client && 'VTouch'] ...` should do the trick yeah. – kissu May 02 '22 at 16:27
  • With `[process.client && 'VTouch']` I get `Failed to mount component: template or render function not defined.`, and with `[process.client && 'VueTouch']` I get `Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.` – Joe82 May 03 '22 at 07:04
  • 1
    @Joe82 it looks like vue-touch is not compatible/maintained anymore: https://github.com/vuejs/vue-touch Are you talking about another package? Feel free to open a new question and mention this answer. I'll help you more in-depth. :) – kissu May 03 '22 at 10:09