hello.js icon indicating copy to clipboard operation
hello.js copied to clipboard

hello.js not compatible with ssr and static site generators

Open berkeleycole opened this issue 5 years ago • 4 comments

Hello,

I am rebuilding a client's website with a static site generator (in this case Gatsby js). They are using hello.js but this library depends window being available, which does not exist at build time. I have an idea for a fix, just adding a conditional to ensure the existence of window before running the program, but I wanted to file an issue here first to see if anyone has already worked on this, fixed this, etc..

Does anyone have workarounds for this?

Thanks, Alyssa

berkeleycole avatar Mar 13 '19 17:03 berkeleycole

I'm experimenting this problem too, what I do is to load it dynamically. For this I created a HOC called WithHelloJS:

function WithHelloJS({ children }) {
  const [hello, setHello] = useState(undefined);
  useEffect(() => {
    import('hellojs').then(mod => {
      setHello(() => mod.default);
    });
  }, []);
  return children({ hello });
}

// then use it

function App() {
  return <div>
    <WithHelloJS>
      {({ hello }) => hello ? <Buttons hello={hello} /> : <></>}
    </WithHelloJS>
  </div>
}

// button uses hellojs
function Buttons({ hello }) {
  useEffect(() => {
    hello.init({ facebook: 'YOUR_APP_ID' });
  }, []);

  const connectToFB = () => {
    hello('facebook')
      .login({
        scope: 'manage_pages,publish_pages',
      }).then(() => {
        alert('Logged-in with Facebook)
      }, () => {
        alert('error');
      });
  };

  const connectToTwitter = () => {
    hello('twitter')
      .login()
      .then(() => {
        alert('Logged-in with Twitter)
      }, () => {
        alert('error');
      });
  };

  return (
    <>
      <button onClick={connectToFB}>Conectar a Facebook</button>
      <button onClick={connectToTwitter}>Conectar a Twitter</button>
    </>
  );
}

Hope it helps.

carloslfu avatar May 19 '19 23:05 carloslfu

I found the most flexible way is to use a custom hook:

// hello.jsx

import React from 'react';

const HelloContext = React.createContext(undefined);

export function useHello() {
  const context = React.useContext(HelloContext);
  if (!context) {
    throw new Error(`useHello must be used within a HelloProvider`);
  }
  return context;
}

export function HelloProvider(props) {
  const [hello, setHello] = React.useState(undefined);

  React.useEffect(() => {
    import('hellojs').then(mod => {
      setHello(() => mod.default);
    });
  }, []);

  const value = React.useMemo(() => ({ hello }), [hello]);

  return <HelloContext.Provider value={value} {...props} />;
}

// App.js

import React from 'react'
import { HelloProvider } from './hello'
import Page from './Page'

export default () => <HelloProvider>
  <Page />
</HelloProvider>

// Page.js

import React from 'react'
import { useHello } from './hello'

function App() {
  const { hello } = useHello()

  return <div>
    {hello && <Buttons hello={hello} />}
  </div>
}

// button uses hellojs

function Buttons({ hello }) {
  useEffect(() => {
    hello.init({ facebook: 'YOUR_APP_ID' });
  }, []);

  const connectToFB = () => {
    hello('facebook')
      .login({
        scope: 'manage_pages,publish_pages',
      }).then(() => {
        alert('Logged-in with Facebook)
      }, () => {
        alert('error');
      });
  };

  const connectToTwitter = () => {
    hello('twitter')
      .login()
      .then(() => {
        alert('Logged-in with Twitter)
      }, () => {
        alert('error');
      });
  };

  return (
    <>
      <button onClick={connectToFB}>Conectar a Facebook</button>
      <button onClick={connectToTwitter}>Conectar a Twitter</button>
    </>
  );
}

carloslfu avatar May 20 '19 07:05 carloslfu

thanks @carloslfu! I don't know if it will help you, but I also created a pull request to this repo to add conditionals around all references to "document.window" so that we can hopefully just use it as a normal npm package and import it at build time. Don't know if it will be merged yet, but right now I'm using my forked version of this library instead of the official one: https://github.com/berkeleycole/hello.js

Here is the PR I created in case you want to take a look and see if it will help you: https://github.com/MrSwitch/hello.js/pull/600

berkeleycole avatar May 20 '19 15:05 berkeleycole

Great, many thanks @berkeleycole!

carloslfu avatar May 20 '19 17:05 carloslfu