Search code examples
next.jspolkadot-js

An Reference Error is occured at "@polkadot/extension-dapp/bundle.js"


  1. I tried to implement a simple UI for smart contracts using polkadot.js in the next.js framework.
  2. The content of the WEB UI is a simple one that calls the Flipper contract, which is famous for the sample contract of the substrate.
  3. When compiling, the following error is output. Can you tell me how to solve it?

Souce Code:

import { useEffect, useState } from "react";
import {
  web3Accounts,
  web3Enable,
  web3FromSource,
} from "@polkadot/extension-dapp";
import { InjectedAccountWithMeta } from "@polkadot/extension-inject/types";

const Home = () => {
  const [allAccount, setAllAccount] = useState<InjectedAccountWithMeta[]>([]);

  const getAccounts = async () => {
    const extensions = await web3Enable("my cool dapp");
    if (extensions.length === 0) {
      return;
    }
    const allAccounts = await web3Accounts();
    setAllAccount(allAccounts);
  };

  useEffect(() => {
    getAccounts();
  }, []);

  return (
    <>
      <div>
        {typeof allAccount !== "undefined"
          ? allAccount.map((account) => {
              return (
                <div key={account.address}>
                      <div className="font-bold mb-2 text-white">
                        {account.address}
                      </div>
                </div>
              );
            })
          : ""}{" "}
      </div>
    </>
  );
};

export default Home;

Error Information:

> Build error occurred
ReferenceError: window is not defined
    at file:///Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/@polkadot/extension-dapp/bundle.js:10:13
    at ModuleJob.run (node:internal/modules/esm/module_job:175:25)
    at async Loader.import (node:internal/modules/esm/loader:178:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15) {
  type: 'ReferenceError'
}

Solution

    1. This issue occurs because next.js is a framework for server-side rendering.
    2. In order to avoid this problem, it is necessary to control not to execute server-side rendering for the relevant part.
    3. Componentize the part that gets account information from the relevant Extension.
    4. Adopt dynamic import when using this component and set server-side rendering to off.

    component sample code:

    import { useEffect, useState } from "react";
    import { web3Accounts, web3Enable } from "@polkadot/extension-dapp";
    import { InjectedAccountWithMeta } from "@polkadot/extension-inject/types";  
    
    const Extention = () => {
      const [allAccount, setAllAccount] = useState<InjectedAccountWithMeta[]>([]);
    
      const getAccounts = async () => {
        const extensions = await web3Enable("my cool dapp");
        if (extensions.length === 0) {
          return;
        }
        const allAccounts = await web3Accounts();
        setAllAccount(allAccounts);
      };
    
      useEffect(() => {
        getAccounts();
      }, []);
    
      return (
        <>
          <div>
            {typeof allAccount !== "undefined"
              ? allAccount.map((account) => {
                  return (
                    <div key={account.address}>
                      <div className="font-bold mb-2 text-white">
                        {account.address}
                      </div>
                    </div>
                  );
                })
              : ""}{" "}
          </div>
        </>
      );
    };
    
    export default Extention;
    

    Calling component sample code:

    import dynamic from "next/dynamic";
    import { useState } from "react";
    
    const Extention = dynamic(() => import("../component/extention"), {
      ssr: false,
    });
    
    const Home = () => {
      const [showExtention, setShowExtention] = useState(false);
      return (
        <>
          <button onClick={() => setShowExtention(true)}>show extention</button>
          {showExtention == true && <Extention></Extention>}
        </>
      );
    };
    
    export default Home;