代码拆分和服务器端呈现(未定义React)

时间:2016-05-03 22:30:07

标签: reactjs webpack react-router babeljs koa

我正在构建一个带有代码分割的同构/通用React应用程序。即使我设法通过webpack编译客户端包没有问题,服务器也无法呈现页面,在执行函数renderToString时抛出错误。

运行服务器时,堆栈跟踪如下:

ReferenceError: React is not defined
    at /xx/src/server/server.js:84:16
    at /xx/node_modules/react-router/lib/match.js:65:5
    at /xx/node_modules/react-router/lib/createTransitionManager.js:118:11
    at done (/xx/node_modules/react-router/lib/AsyncUtils.js:79:19)
    at /xx/node_modules/react-router/lib/AsyncUtils.js:85:7
    at /xx/src/routes/About/index.js:12:7
    at Function.require.ensure (/xx/src/routes/About/index.js:5:10)
    at Object.getComponent (/xx/src/routes/About/index.js:11:13)
    at getComponentsForRoute (/xx/node_modules/react-router/lib/getComponents.js:62:16)
    at /xx/node_modules/react-router/lib/getComponents.js:74:5
---------------------------------------------
    at Application.callback (/xx/node_modules/koa/lib/application.js:129:47)
    at Application.listen (/xx/node_modules/koa/lib/application.js:64:43)
    at Object.<anonymous> (/xx/src/server/server.js:103:8)
    at Module._compile (module.js:413:34)
    at loader (/xx/node_modules/babel-register/lib/node.js:158:5)
    at Object.require.extensions.(anonymous function) [as .js] (/xx/node_modules/babel-register/lib/node.js:168:7)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)

服务器文件server.js包含:

import Koa from 'koa'
import convert from 'koa-convert'
import webpack from 'webpack'
import webpackMiddleware from 'webpack-dev-middleware'
import config from '../../webpack.config'

import ReactDOM from 'react-dom/server';
import { Provider } from 'react-redux'
import { createMemoryHistory, RouterContext, match } from 'react-router';
import { IntlProvider } from 'react-intl'
import { trigger } from 'redial'

import localeMessages from '../locales/en'
import configureStore from '../store/configureStore'


function createPage(html, scriptTag) {
  return `
    <!doctype html>
    <html>
      <body>
        ${html}

        ${scriptTag}
      </body>
    </html>
  `
}

const is_developing = process.env.NODE_ENV == 'development'
const port = process.env.PORT || 5000
const server = new Koa()

server.use((req, res) => {
  const store = configureStore()
  const history = createMemoryHistory(req.path)
  const routes = require('../routes')
  const { dispatch, getState } = store

  match({ routes, history }, (error, redirectLocation, renderProps) => {
    // Get array of route handler components:
    const { components } = renderProps;

    // Define locals to be provided to all lifecycle hooks:
    const locals = {
      path: renderProps.location.pathname,
      query: renderProps.location.query,
      params: renderProps.params,

      // Allow lifecycle hooks to dispatch Redux actions:
      dispatch
    };

    const content = ReactDOM.renderToString(
      <Provider store={store}>
        <IntlProvider locale="en"
                      feedbacks={localeMessages}>
          <RouterContext {...renderProps} />
        </IntlProvider>
      </Provider>
    );

    // Wait for async data fetching to complete, then render:
    trigger('fetch', components, locals)
      .then(() => {
        const state = getState();
        const content = ReactDOM.renderToString(
          <Provider store={store}>
            <IntlProvider locale="en"
                          feedbacks={localeMessages}>
            <RouterContext {...renderProps} />
            </IntlProvider>
          </Provider>
        );
        const html = createPage(content, scriptTag)
        resolve({ html, state })
      })
      .catch(e => console.log(e))
  })
})

server.listen(port, '0.0.0.0', () => {
  console.info(`Listening on port ${port} (0.0.0.0)`)
})

server.on('error', (err, ctx) => {
  console.log('error', err, ctx)
})

module.exports = server

整个例程似乎正常工作:从getState()派生的状态看起来很好,并且不同的路由符合预期(无论我在浏览器上键入的内容与循环中的正确路由相关联)。

我正在关注react-router异步路由(如本example中所述)。在此特定问题中,routes/About/index.js的内容为:

// Polyfill (require for server side)
if (typeof require.ensure !== 'function') require.ensure = (d, c) => c(require)

module.exports = {
  path: 'about',
  getComponent(nextState, cb) {
    require.ensure([], (require) => {
      cb(null, require('./components/About').default)
    })
  }
}

我还仔细检查了不同的组件,确保它们都导入了React库(即import React from 'react')。再次,当我运行webpack来编译整个应用程序时,没有问题。

1 个答案:

答案 0 :(得分:2)

您还必须在server.js文件上导入React,因为在转换了以下内容后

const content = ReactDOM.renderToString(
  <Provider store={store}>
    <IntlProvider locale="en"
                  feedbacks={localeMessages}>
      <RouterContext {...renderProps} />
    </IntlProvider>
  </Provider>
);

看起来像这样

var content = ReactDOM.renderToString(React.createElement(
  Provider,
  { store: store },
  React.createElement(
    IntlProvider,
    { locale: "en",
      feedbacks: localeMessages },
    React.createElement(RouterContext, renderProps)
  )
));