vue-telegram-login icon indicating copy to clipboard operation
vue-telegram-login copied to clipboard

Nuxt SSR Support

Open Aztriltus opened this issue 5 years ago • 2 comments

  • vue-telegram-login version: 2.1.0
  • node version: 12.8.1
  • npm (or yarn) version: yarn 1.17.3

Relevant code or config

<template>
<div>
<!-- ... -->
<vue-telegram-login 
        mode="callback"
        telegram-login="botname"
        @callback="telegramLogin" />
</div>
</template>

<script>
import { vueTelegramLogin } from 'vue-telegram-login'

export default {
  components: { vueTelegramLogin },
  methods: {
    telegramLogin(user) { }
  }
</script>

What you did: I'm using Nuxt 2.0.0 and I tried using this plugin in one of my pages component.

What happened:

window is not defined

!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var r=t();for(var n in r)("object"==typeof exports?exports:e)[n]=r[n]}}(window,function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(n,i,function(t){return e[t]}.bind(null,i));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";r.r(t);var n={name:"vue-telegram-login",props:{mode:{type:String,required:!0,validator:function(e){return["callback","redirect"].includes(e)}},telegramLogin:{type:String,required:!0,validator:function(e){return e.endsWith("bot")||e.endsWith("Bot")}},redirectUrl:{type:String,default:""},requestAccess:{type:String,default:"read",validator:function(e){return["read","write"].includes(e)}},size:{type:String,default:"large",validator:function(e){return["small","medium","large"].includes(e)}},userpic:{type:Boolean,default:!0},radius:{type:String}},methods:{onTelegramAuth:function(e){this.$emit("callback",e)}},mounted:function(){var e=document.createElement("script");e.async=!0,e.src="https://telegram.org/js/telegram-widget.js?3",e.setAttribute("data-size",this.size),e.setAttribute("data-userpic",this.userpic),e.setAttribute("data-telegram-login",this.telegramLogin),e.setAttribute("data-request-access",this.requestAccess),this.radius&&e.setAttribute("data-radius",this.radius),"callback"===this.mode?(window.onTelegramAuth=this.onTelegramAuth,e.setAttribute("data-onauth","window.onTelegramAuth(user)")):e.setAttribute("data-auth-url",this.redirectUrl),this.$refs.telegram.appendChild(e)}},i=function(){var e=this.$createElement;return(this._self._c||e)("div",{ref:"telegram"})};i._withStripped=!0;var o=function(e,t,r,n,i,o,u,a){var s=typeof(e=e||{}).default;"object"!==s&&"function"!==s||(e=e.default);var l,d="function"==typeof e?e.options:e;if(t&&(d.render=t,d.staticRenderFns=r,d._compiled=!0),n&&(d.functional=!0),o&&(d._scopeId=o),u?(l=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),i&&i.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(u)},d._ssrRegister=l):i&&(l=a?function(){i.call(this,this.$root.$options.shadowRoot)}:i),l)if(d.functional){d._injectStyles=l;var c=d.render;d.render=function(e,t){return l.call(t),c(e,t)}}else{var f=d.beforeCreate;d.beforeCreate=f?[].concat(f,l):[l]}return{exports:e,options:d}}(n,i,[],!1,null,null,null);o.options.__file="src/vue-telegram-login.vue";var u=o.exports;r.d(t,"vueTelegramLogin",function(){return u})}])});

Problem description: Seems like the window issue is caused by the client/server configuration. window is only available on the client side and the error is likely caused by the server rendering (which has no window)

Any idea how to solve this?

Aztriltus avatar Dec 17 '19 09:12 Aztriltus

You should wrap you code with nuxt’s client-only component

shlima avatar Jul 08 '20 19:07 shlima

You should wrap you code with nuxt’s client-only component

It doesn't work because it crashes during import

"dependencies": {
    "@nuxt/typescript-runtime": "^2.0.0",
    "@nuxtjs/axios": "^5.12.2",
    "core-js": "^3.6.5",
    "nuxt": "^2.14.5",
    "vue-telegram-login": "^2.1.0"
  }

I followed and official FAQ suggestion:

<template>
  <client-only placeholder="Loading...">
    <vue-telegram-login
      mode="callback"
      telegram-login="TrembolGameBot"
      @callback="yourCallbackFunction"
    />
  </client-only>
</template>

<script>
let vueTelegramLogin
if (process.client) {
  vueTelegramLogin = require('vue-telegram-login').vueTelegramLogin
  console.log(vueTelegramLogin)
} else {
  vueTelegramLogin = null
}

export default {
  name: 'TelegramLogin',
  components: {
    vueTelegramLogin,
  },
  methods: {
    yourCallbackFunction(user) {
      // gets user as an input
      // id, first_name, last_name, username,
      // photo_url, auth_date and hash
      console.log(user)
    },
  },
}
</script>

NikitaKolesov avatar Oct 02 '20 19:10 NikitaKolesov

For nuxt you can directly use telegram's widget with Script tag.

Example:

<ClientOnly>
  <Script async src="https://telegram.org/js/telegram-widget.js?22"
   data-telegram-login="samplebot" data-size="large"
   data-auth-url="https://domain.com" data-request-access="write"/>
</ClientOnly>

If you need validate user on server side, you can create endpoint for that, create a folder inside server/api/auth/index.ts (learn more here about it)

import crypto from 'node:crypto';

export default defineEventHandler((event) => {
    const query = getQuery(event);
    const bot_token = process.env.BOT_TOKEN;
    const secret = crypto.createHash('sha256').update(bot_token).digest();
    let array = [];
    for (let key in query) {
        if (key != 'hash') {
            array.push(key + '=' + query[key]);
        }
    }
    const check_hash = crypto
        .createHmac('sha256', secret)
        .update(array.sort().join('\n'))
        .digest('hex');
    return check_hash == query.hash;
})

Validating data in front-end:

if (route.query.id && route.query.hash && route.query.first_name) {
    console.log(`${querystring.stringify(route.query)}`);
    const { data, pending, error, refresh } = await useFetch(`/api/auth?${querystring.stringify(route.query)}`)
    console.log(data.value);
}

halitsever avatar Dec 11 '23 00:12 halitsever