我正在创建一个具有Google登录功能的通用React应用程序。很遗憾,Google没有可在客户端和服务器上使用的通用Google API(gapi
)库。
我真正想要做的就是运行我的服务器代码并让Babel在我做出更改时自动重新编译我的代码,让它自动重启服务器(就像nodemon一样,但是有一个编译步骤)。我找到了一个名为babel-watch
的npm包,它会执行此操作,但它不会与webpack集成。
在我的模板index.html文件中,我在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>
上面创建了一个新的Promise
,在加载gapi
时使用platform.js
的值解析。但是,由于仅在客户端上加载,因此服务器上不存在gapi
和gapiPromise
。
我还有一个Google Sign In React组件,当gapiPromise
准备好使用时,它使用全局gapi
变量进行按钮渲染:
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
这在客户端上工作正常,但当我尝试在服务器上呈现它时,Node抱怨:
/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)
我尝试使用gapiPromise
(即global.
)在此文件中添加前缀global.gapiPromise
,然后在我的服务器的条目文件(global.gapiPromise = false
)中定义server.js
,但随后Node抱怨:
/Users/jreznik/Sites/my-app/dist/server.js:3569
global.gapiPromise.then(function (gapi) {
^
TypeError: Cannot read property 'then' of undefined
最后,我能够使用webpack的DefinePlugin
:
webpack.server.config.js
...
plugins: [
new webpack.DefinePlugin({
'window': {},
'gapiPromise': false
})
]
...
但如果我这样做,那么我就不能使用babel-watch
npm包自动重新编译并重启服务器。
如何让Node停止抱怨这些未定义的全局变量?
答案 0 :(得分:0)
它是客户端库,这意味着它仅用于浏览器中的DOM。它实际上相当于window.gapiPromise
。 window
对象代表浏览器中的打开窗口。
答案 1 :(得分:0)
好了几个小时后,我发现这个问题一个小时后找到了一个解决方案。
从我的 GoogleSignIn.jsx 文件中,我将代码移出...
// should only run on client
if (gapiPromise !== false) {
gapiPromise.then(gapi => {
gapi.auth2.init({
client_id: '[removed]'
})
})
}
...并进入模板:
<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>
不完全确定为什么Node不会在gapiPromise
方法中抱怨额外的componentDidMount()
,但事实并非如此。我还更改了if语句以检查gapiPromise
:
if (typeof gapiPromise !== 'undefined') {