Skip to content

Throwing "ReferenceError: window is not defined" on Next.js with SSR #14

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

Open
ivanproskuryakov opened this issue May 22, 2024 · 13 comments
Labels
wontfix This will not be worked on

Comments

@ivanproskuryakov
Copy link

The library fails to work with the Next.js framework ("next": "^12.1.6") while SSR.

The issue is caused by the missing window object within the file node_modules/@twa-dev/sdk/dist/sdk.js, and it occurs at the time of import.
Ref: https://github.com/twa-dev/SDK/blob/master/src/sdk.ts

Transpiled file

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebApp = void 0;
require("./telegram-web-apps");
var telegramWindow = window; // Seems to be the line causing the problem
exports.WebApp = telegramWindow.Telegram.WebApp;
//# sourceMappingURL=sdk.js.map

Demo app:

import WebApp from '@twa-dev/sdk'; // Happens at the time of import

const MiniApp = () => {
  return (
    <div>
      ...
      <button onClick={() => WebApp.showAlert(`Hello World!`)}>
        Show Alert
      </button>
    </div>
  );
};

export default MiniApp;

Console output

Uncaught ReferenceError: window is not defined
    at <unknown> (file:///Users/ivan/code/communa/frontend/node_modules/@twa-dev/sdk/dist/telegram-web-apps.js:248:5)
    at Object.<anonymous> (file:///Users/ivan/code/communa/frontend/node_modules/@twa-dev/sdk/dist/telegram-web-apps.js:274:3)
    at Module._compile (node:internal/modules/cjs/loader:1364:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1422:10)
    at Module.load (node:internal/modules/cjs/loader:1203:32)
    at Module._load (node:internal/modules/cjs/loader:1019:12)
    at Module.require (node:internal/modules/cjs/loader:1231:19)
    at require (node:internal/modules/helpers:177:18)
    at Object.<anonymous> (file:///Users/ivan/code/communa/frontend/node_modules/@twa-dev/sdk/dist/sdk.js:4:1)
    at Module._compile (node:internal/modules/cjs/loader:1364:14)
Screenshot 2024-05-22 at 17 47 28
@ivanproskuryakov ivanproskuryakov changed the title Fails to work using Next.js and SSR throwing "ReferenceError: window is not defined" Throwing "ReferenceError: window is not defined" on Next.js with SSR May 22, 2024
@kevcube
Copy link

kevcube commented May 23, 2024

@ivanproskuryakov I am experiencing the same, let me know if you find a good fix.

I am able to use Next's Script tag to load the TWA script and then do the JS there, but I would like to use this SDK.

@ivanproskuryakov
Copy link
Author

@kevcube Sure, I'll open a PR with a patch.
Meanwhile, can you post your workaround for this error, please?

@kevcube
Copy link

kevcube commented May 23, 2024

@ivanproskuryakov

"use client";
import Script from "next/script";

import { Telegram } from "@twa-dev/types";

declare global {
  interface Window {
    Telegram: Telegram;
  }
}

export default function Page() {
  return (
    <Script
      id="TelegramWebApp"
      src="https://telegram.org/js/telegram-web-app.js"
      onReady={() => {
        window.Telegram.WebApp.MainButton.setParams({
          text: `Hello`,
          is_visible: true,
        });
      }}
    />
  );
}

I'm using Next 14, this can go in layout or other imported files to auto load on all pages of your app.

@EliusHHimel
Copy link

@ivanproskuryakov

"use client";
import Script from "next/script";

import { Telegram } from "@twa-dev/types";

declare global {
  interface Window {
    Telegram: Telegram;
  }
}

export default function Page() {
  return (
    <Script
      id="TelegramWebApp"
      src="https://telegram.org/js/telegram-web-app.js"
      onReady={() => {
        window.Telegram.WebApp.MainButton.setParams({
          text: `Hello`,
          is_visible: true,
        });
      }}
    />
  );
}

I'm using Next 14, this can go in layout or other imported files to auto load on all pages of your app.

It didn't work for me. Anyone faced the issue and find a solution other than this?

@kevcube
Copy link

kevcube commented Jul 14, 2024

@ivanproskuryakov

"use client";

import Script from "next/script";

import { Telegram } from "@twa-dev/types";

declare global {

interface Window {

Telegram: Telegram;

}

}

export default function Page() {

return (

<Script
  id="TelegramWebApp"
  src="https://telegram.org/js/telegram-web-app.js"
  onReady={() => {
    window.Telegram.WebApp.MainButton.setParams({
      text: `Hello`,
      is_visible: true,
    });
  }}
/>

);

}

I'm using Next 14, this can go in layout or other imported files to auto load on all pages of your app.

It didn't work for me. Anyone faced the issue and find a solution other than this?

Just use telegram-mini-apps/twa.js and join @devs on telegram

@sramezani
Copy link

Just check if window is exist, like this:

if (typeof window !== "undefined") {
     // Your code here
}

something like this:

import WebApp from '@twa-dev/sdk'; // Happens at the time of import

const MiniApp = () => {

 const onClick = () => {
     if (typeof window !== "undefined") {
         WebApp.showAlert(`Hello World!`)
    }   
 }

  return (
    <div>
      ...
      <button onClick={onClick}>
        Show Alert
      </button>
    </div>
  );
};

export default MiniApp;

@n8m
Copy link

n8m commented Aug 21, 2024

still the same issue i faced. No PR with fix merged ?

@podrabinek
Copy link

The issue is still there!

@bytemtek
Copy link

bytemtek commented Nov 3, 2024

Still same +

@joe888777
Copy link

I meet this issue, and currently the workaround I used is to dynamic import the component which use import WebApp from '@twa/sdk'.
e.g:

import WebApp from "@twa-dev/sdk";
const Foo = () => {
    const foo = () => {WebApp....}
}
export default Foo;

dynamic import the component:

import dynamic from 'next/dynamic';
import Foo from "@/components/foo";
const Foo = dynamic(() => import("foo"), { ssr: false });
const Page = () => {
    return (
        <div>
            <Foo/>
        </div>
    )
}

@bytemtek
Copy link

I meet this issue, and currently the workaround I used is to dynamic import the component which use import WebApp from '@twa/sdk'. e.g:

import WebApp from "@twa-dev/sdk";
const Foo = () => {
    const foo = () => {WebApp....}
}
export default Foo;

dynamic import the component:

import dynamic from 'next/dynamic';
import Foo from "@/components/foo";
const Foo = dynamic(() => import("foo"), { ssr: false });
const Page = () => {
    return (
        <div>
            <Foo/>
        </div>
    )
}

You can use @telegram-apps/sdk-react without any problem.

@GrayJyyyyy
Copy link

I meet this issue, and currently the workaround I used is to dynamic import the component which use import WebApp from '@twa/sdk'. e.g:

import WebApp from "@twa-dev/sdk";
const Foo = () => {
    const foo = () => {WebApp....}
}
export default Foo;

dynamic import the component:

import dynamic from 'next/dynamic';
import Foo from "@/components/foo";
const Foo = dynamic(() => import("foo"), { ssr: false });
const Page = () => {
    return (
        <div>
            <Foo/>
        </div>
    )
}

You can use @telegram-apps/sdk-react without any problem.

But some methods do not work with @telegram-apps/sdk-react

@ArthurStam ArthurStam added the wontfix This will not be worked on label Jan 4, 2025
@LimaTechnologies
Copy link

I was having the same issue but with client component, wich as supposed to work, the problem is that next apparently import the packages as ssr by default as you can see in the base errors in the screenshot "at (ssr)"

Image

then I just imported the library this way, as I noted the issue on the error was that next was rendering the library at the server sidem then i came to the library and it was trying to access window, so it was nextjs fault, and this import worked to me

let WebApp: any;
if (typeof window !== "undefined") {
	WebApp = require("@twa-dev/sdk").default;
}

Full code provider that I was using after the changes

"use client";

import {
	createContext,
	useContext,
	useEffect,
	useMemo,
	useState,
	ReactNode,
} from "react";
import crypto from "crypto";

let WebApp: any;
if (typeof window !== "undefined") {
	WebApp = require("@twa-dev/sdk").default;
}

export interface ITelegramContext {
	isOnTelegram: boolean;
}

const TelegramContext = createContext<ITelegramContext>({
	isOnTelegram: false,
});

export const TelegramProvider: React.FC<{ children: ReactNode }> = ({
	children,
}) => {
	const [isOnTelegram, setIsOnTelegram] = useState(false);
	const [isValid, setIsValid] = useState("invalid");
	const [initDataUnsafe, setInitDataUnsafe] = useState<any>();
	const [initData, setInitData] = useState<any>();

        //Make a api url for this function its not supposed to be here 
	const verifyInitData = (telegramInitData: string): boolean => {
		const urlParams = new URLSearchParams(telegramInitData);
	
		const hash = urlParams.get('hash');
		urlParams.delete('hash');
		urlParams.sort();
	
		let dataCheckString = '';
		for (const [key, value] of urlParams.entries()) {
			dataCheckString += `${key}=${value}\n`;
		}
		dataCheckString = dataCheckString.slice(0, -1);
	
		const secret = crypto.createHmac('sha256', 'WebAppData').update("bot_key");
		const calculatedHash = crypto.createHmac('sha256', secret.digest()).update(dataCheckString).digest('hex');
	
		return calculatedHash === hash;
	}

	useEffect(() => {

		if (WebApp.initDataUnsafe.user) {
			setIsOnTelegram(true);
			setInitDataUnsafe(JSON.stringify(WebApp.initDataUnsafe.user));

			const { hash, ...rest } = WebApp.initDataUnsafe.user;
		}

		if (WebApp?.initData) {
			setIsOnTelegram(true);
			setInitData(JSON.stringify(WebApp.initData));

			
			setIsValid(verifyInitData(WebApp.initData) ? "valid" : "invalid");
		}

	}, []);

	const value = useMemo(
		() => ({ isOnTelegram }),
		[isOnTelegram],
	);

	return (
		<TelegramContext.Provider value={value}>
			IsValid
			{isValid}
			<br />
			Unsafe
			{initDataUnsafe}
			<br />
			Data
			{initData}
			{children}
		</TelegramContext.Provider>
	);
};

export const useTelegram = (): ITelegramContext => useContext(TelegramContext);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Development

No branches or pull requests