I'm creating a universal React application with Google sign in capabilities. Unfortunately, Google doesn't have a universal Google API ( gapi
) library that I can use on both client and server.
What I am really trying to do here is run my server code and have Babel recompile my code automatically when I make changes, and have it automatically restart the server (like nodemon does, but with a compilation step). I found a npm package called babel-watch
that will do just this, however it doesn't integrate with webpack.
In my template index.html file, I have the following code in the HTML <head>
:
index.html
<script type="text/javascript">
window.gapiPromise = new Promise(resolve => window.gapiLoadedCallback = () => resolve(gapi))
</script>
<script src="https://apis.google.com/js/platform:auth2.js?onload=gapiLoadedCallback" async defer></script>
The above creates a new Promise
which is resolved with the value of gapi
when platform.js
is loaded. However, since this is only loaded on the client, gapi
and gapiPromise
do not exist on the server.
I also have a Google Sign In React component that uses the global gapiPromise
variable to do the button rendering when gapi
is ready to be used:
GoogleSignIn.jsx
import React from 'react'
// should only run on client
if (gapiPromise !== false) {
gapiPromise.then(gapi => {
gapi.auth2.init({
client_id: '[removed]'
})
})
}
class GoogleSignIn extends React.Component {
constructor(props) {
super(props)
}
componentDidMount() {
// should only run on client
if (gapiPromise !== false) {
gapiPromise.then(gapi => gapi.signin2.render('g-signin2', {
'scope': 'email',
'width': 160,
'height': 50,
'theme': 'light',
'onsuccess': this.props.onSuccess,
'onfailure': this.props.onFailure
}))
}
}
render() {
return (
<div className="google-sign-in">
<div id="g-signin2"></div>
</div>
)
}
}
export default GoogleSignIn
This works fine on the client, but when I try to render it on the server, Node complains that:
/Users/jreznik/Sites/my-app/dist/server.js:3568
if (gapiPromise !== false) {
^
ReferenceError: gapiPromise is not defined
at Object.defineProperty.value (/Users/jreznik/Sites/my-app/dist/server.js:3568:6)
at __webpack_require__ (/Users/jreznik/Sites/my-app/dist/server.js:20:30)
at Object.defineProperty.value (/Users/jreznik/Sites/my-app/dist/server.js:3408:22)
at __webpack_require__ (/Users/jreznik/Sites/my-app/dist/server.js:20:30)
at Object.defineProperty.value (/Users/jreznik/Sites/my-app/dist/server.js:3354:24)
at __webpack_require__ (/Users/jreznik/Sites/my-app/dist/server.js:20:30)
at Object.defineProperty.value (/Users/jreznik/Sites/my-app/dist/server.js:194:21)
at __webpack_require__ (/Users/jreznik/Sites/my-app/dist/server.js:20:30)
at Object.<anonymous> (/Users/jreznik/Sites/my-app/dist/server.js:59:16)
at Object.<anonymous> (/Users/jreznik/Sites/my-app/dist/server.js:131:31)
I have tried prefixing gapiPromise
in this file with global.
(ie global.gapiPromise
), and then defining global.gapiPromise = false
in my server's entry file ( server.js
), but then Node complains:
/Users/jreznik/Sites/my-app/dist/server.js:3569
global.gapiPromise.then(function (gapi) {
^
TypeError: Cannot read property 'then' of undefined
Finally, I was able to get it to work using webpack's DefinePlugin
:
webpack.server.config.js
...
plugins: [
new webpack.DefinePlugin({
'window': {},
'gapiPromise': false
})
]
...
But if I do this then I can't use the babel-watch
npm package to automatically recompile and restart the server.
How can I get Node to stop complaining about these undefined global variables?
It is a client library , which means that it is for use only with the DOM from the browser. It is actually equivalent to window.gapiPromise
. And the window
object represents an open window in a browser .
Ok after messing around with this for hours, I found a solution an hour after posting this question.
From my GoogleSignIn.jsx file, I moved the code out...
// should only run on client
if (gapiPromise !== false) {
gapiPromise.then(gapi => {
gapi.auth2.init({
client_id: '[removed]'
})
})
}
... and into the template:
<script type="text/javascript">
window.gapiPromise = new Promise(resolve => window.gapiLoadedCallback = () => {
gapi.auth2.init({
client_id: '[removed]'
})
resolve(gapi)
})
</script>
<script src="https://apis.google.com/js/platform:auth2.js?onload=gapiLoadedCallback" async defer></script>
Not totally sure why Node doesn't complain about the extra gapiPromise
s in the componentDidMount()
method, but it's not. Also I changed the if-statement to check gapiPromise
to:
if (typeof gapiPromise !== 'undefined') {
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.