rozek / svelte-device-info

informs about a device's form factor and pointing accuracy (not only for Svelte)
MIT License
23 stars 1 forks source link

Does not work with SvelteKit #1

Open Wombosvideo opened 1 year ago

Wombosvideo commented 1 year ago

Description

This module does not work with SvelteKit due to navigator not being present server-side.

Log messages

ReferenceError: navigator is not defined
    at DeviceIsMobile (../src/svelte-device-info.ts:13:2021)
    at get isMobile [as isMobile] (../src/svelte-device-info.ts:294:29)

Possible Solution

Create a writable store for isMobile and update it onMount.

Sample Module

This is an example how the module could be updated:

import { derived, writable } from 'svelte/store';
import { onMount, onDestroy } from 'svelte';

const initialized = writable(false);
const mobile = writable(false);

/**** DeviceIsMobile ****/
// see https://stackoverflow.com/questions/11381673/detecting-a-mobile-browser
function DeviceIsMobile() {
  return (a =>
    /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a) ||
    /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(a.substring(0, 4))
  )(navigator.userAgent || navigator.vendor || (window as Window & {opera?: string}).opera || '');
}

export default derived([initialized, mobile], ([$initialized, isMobile]) => {
  if (!$initialized) {
    onMount(() => {
      initialized.set(true);
      mobile.set(DeviceIsMobile());
    });
    onDestroy(() => {
      initialized.set(false);
      mobile.set(false);
    });
  }
  return { isMobile };
});

This code also replaces the function syntax with an arrow function, replaces deprecated substr(...) with substring(...), and removes the Result variable from the original DeviceIsMobile() function. It also implements correct typing and removes unnecessary \ escape characters in front of the - hyphens.

If you want to save this code as a module, store it in a device-info.ts file or similar.

It could then be used like this:

import Device from "./device-info";
{#if $Device.isMobile}
  You are using a mobile device.
{#else}
  You are using a desktop device.
{/if}
sebastianbonilla commented 11 months ago

Same issue, not working with Sveltekit.

Error thrown:

ReferenceError: navigator is not defined at DeviceIsMobile (file:///Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/node_modules/svelte-device-info/dist/svelte-device-info.esm.js:10:27) at get isMobile [as isMobile] (file:///Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/node_modules/svelte-device-info/dist/svelte-device-info.esm.js:236:29) at /Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/src/routes/pos/+page.svelte:115:45 at Object.$$render (/Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/node_modules/svelte/src/runtime/internal/ssr.js:156:16) at Object.default (/Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/.svelte-kit/generated/root.svelte:44:41) at eval (/Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/src/routes/+layout.svelte:59:270) at Object.$$render (/Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/node_modules/svelte/src/runtime/internal/ssr.js:156:16) at /Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/.svelte-kit/generated/root.svelte:43:40 at $$render (/Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/node_modules/svelte/src/runtime/internal/ssr.js:156:16) at Object.render (/Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/node_modules/svelte/src/runtime/internal/ssr.js:164:17

sebastianbonilla commented 11 months ago

@Wombosvideo I tried your approach but doesn't seem to work. It does correctly detects it's not a mobile browsers when I access my web app from my laptop, but does not detect it correctly when I access it from my iPhone, it keeps saying "this device is not mobile" when printing: console.log('this device is ' + (Device.isMobile ? '' : 'not') + ' mobile')

Wombosvideo commented 11 months ago

I no longer use this solution. I switched to a JavaScript based solution where the viewport width is used using a media query watcher. This way I can have the same solution to detect dark mode and mobile devices.

Blankeos commented 3 months ago

You're probably getting that because of SSR?

My workaround is doing this:

const isServer = typeof window === 'undefined';

let canHover = false;

if (!isServer) {
  const { default: Device } = await import('svelte-device-info');
  canHover = Device.canHover;
}

export { canHover };