hello.js
hello.js copied to clipboard
hello.js not compatible with ssr and static site generators
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
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.
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>
</>
);
}
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
Great, many thanks @berkeleycole!