vue-telegram-login
vue-telegram-login copied to clipboard
Nuxt SSR Support
vue-telegram-loginversion: 2.1.0nodeversion: 12.8.1npm(oryarn) 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?
You should wrap you code with nuxt’s client-only component
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>
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);
}