use-ink/useink

Fix "window not found" error for SSR / NextJS apps

Opened this issue · 3 comments

Feature Request

Currently users must dynamically import useink because extensionJS requires window to be in scope. This does not work on SSR. Life would be so much better if we did not have to lazy load...

Suggestion

To anyone willing to pick this up, please offer suggestions in the chat here.

@DoubleOTheven would a Context that wraps and exposes useink be sufficient?
I have not looked into if possible to work around this via extensionJS

Here a pseudo/workable code that should direct the conversation towards a working solution.

I use this on a rather complicated landscape of apps and libs, and it works quite well.

import { createContext, FC, useEffect, useState } from 'react';

declare type UseInkType = typeof import('useink/types/mod');

interface IUseInkContext extends React.HTMLAttributes<'div'>, UseInkType {}

export const UseInkContext = createContext<IUseInkContext>(
  {} as IUseInkContext
);

export const UseInkContextProvider: FC<
  React.HTMLAttributes<'div'> & { dapp: string; provider: string }
> = ({ children, dapp, provider }) => {
  const [useInkInstance, setUseInkInstance] = useState<UseInkType | null>(null);
  useEffect(() => {
    const init = async () => {
      const useinkLibrary = await import('useink');

      setUseInkInstance(useinkLibrary);
    };
    init();
  }, []);

  if (!useInkInstance) {
    // FIXME: This is a workaround to avoid SSR errors (e.g. "window is not defined") until useink is available
    // Fix using this context is to move the context as far down the render pipeline as possible.
    return <></>;
  }

  const InternalUseInkProvider = useInkInstance.UseInkProvider;

  return (
    <UseInkContext.Provider value={useInkInstance}>
      <InternalUseInkProvider
        config={{
          // Name that shows in the wallet extensions that connect
          dappName: dapp,

          // The chain
          // ex.: providerUrl: 'wss://rococo-contracts-rpc.polkadot.io',
          providerUrl: provider,
        }}
      >
        {children}
      </InternalUseInkProvider>
    </UseInkContext.Provider>
  );
};

@felixpolimec There are rules of hooks. One of them is that the must be called on every render. If you have an if statement that returns if a condition if false then any hooks after this will break that rule. talisman-connect might have a solution to this. I'm currently working on integrating it to useink

Hi there! Any updates on this fix?