AgoraIO-Community / AgoraWebSDK-NG

The Next Generation of Agora Web SDK
https://agoraio-community.github.io/AgoraWebSDK-NG/
161 stars 75 forks source link

Cannot using SDK with Next.js for `window is not defined` #21

Closed matamatanot closed 4 years ago

matamatanot commented 4 years ago

Reproduce Repo: https://github.com/matamatanot/agoraTest Deleted I used the official template and simply added 2 lines in index.js.

import AgoraRTC from "agora-rtc-sdk-ng";
console.log(AgoraRTC);
ReferenceError: window is not defined

This error happened while generating the page. Any console logs will be displayed in the terminal window.

If you can, please consider adding example code snippet to the official Next.js example folder. There are many examples that use external js libraries.

disoul commented 4 years ago

Thanks for your feedback.

This SDK is a browser only SDK because it has some WebRTC polyfill codes(webrtc-adapter) that will run automatically when it has been imported.

The Next.js is an SSR framework so it will run some codes in Node.js. The window is not defined error shows Next.js wants to import and run SDK in Node.js (There is no window object in Node.js).

If you want to use SDK with SSR frameworks such as Next.js, you should ensure that when you importing and running the SDK, these codes will be executed in the real browser, not the Node.js.

disoul commented 4 years ago

I find a solution to avoid this error in Next.js, here is my diff file with your Repo (https://github.com/matamatanot/agoraTest)

diff --git a/pages/_document.js b/pages/_document.js
new file mode 100644
index 0000000..365123a
--- /dev/null
+++ b/pages/_document.js
@@ -0,0 +1,23 @@
+import Document, { Html, Head, Main, NextScript } from 'next/document'
+
+class MyDocument extends Document {
+  static async getInitialProps(ctx) {
+    const initialProps = await Document.getInitialProps(ctx)
+    return { ...initialProps }
+  }
+
+  render() {
+    return (
+      <Html>
+        <Head />
+        <body>
+          <Main />
+          <script src="https://download.agora.io/sdk/web/AgoraRTC_N-0.1.9.js"></script>
+          <NextScript />
+        </body>
+      </Html>
+    )
+  }
+}
+
+export default MyDocument
\ No newline at end of file
diff --git a/pages/index.js b/pages/index.js
index f05277e..efbdc37 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -1,8 +1,12 @@
 import Head from "next/head";
-import AgoraRTC from "agora-rtc-sdk-ng";
-console.log(AgoraRTC);
+import { useEffect } from "react";

-const Home = () => (
+const Home = () => {
+  useEffect(() => {
+    console.log("AgoraRTC", window.AgoraRTC);
+  }, []);
+
+  return (
   <div className="container">
     <Head>
       <title>Create Next App</title>
@@ -197,7 +201,7 @@ const Home = () => (
         box-sizing: border-box;
       }
     `}</style>
-  </div>
-);
+  </div>);
+}

 export default Home;
andyfangaf commented 4 years ago

Is there any way to import Agora only on certain pages? That way it doesn't increase the bundle size of pages that don't use Agora. I can confirm @disoul's solution works though.

matamatanot commented 4 years ago

@fandy

How about this?

pages/index

import dynamic from "next/dynamic";

const DynamicAgoraComponentWithNoSSR = dynamic(
  () => import("../components/AgoraComponent").then((mods) => mods.AgoraComponent),
  {
    ssr: false,
  }
);

export default () => {
  return (
      <DynamicAgoraComponentWithNoSSR />
  );
};
andyfangaf commented 4 years ago

@matamatanot yes that works, I guess that's the only option. There doesn't seem to be a way to just import the library on the browser. I suppose wrapping it in a component is a fine workaround. 🙂