通用React app中的全局变量,Node抛出ReferenceError

时间:2016-10-05 02:08:16

标签: javascript node.js reactjs

我正在创建一个具有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的值解析。但是,由于仅在客户端上加载,因此服务器上不存在gapigapiPromise

我还有一个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停止抱怨这些未定义的全局变量?

2 个答案:

答案 0 :(得分:0)

它是客户端库,这意味着它仅用于浏览器中的DOM。它实际上相当于window.gapiPromisewindow对象代表浏览器中的打开窗口。

答案 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') {