2016-05-03 7 views
1

Ich baue eine isomorphe/universelle React App mit Code-Splitting. Obwohl es mir gelingt, das Client-Bundle ohne Probleme über das Webpack zu kompilieren, kann der Server keine Seite rendern, was beim Ausführen der Funktion renderToString einen Fehler verursacht.Code-Aufteilung und serverseitiges Rendering (React ist nicht definiert)

Der Stack-Trace ist die folgende, wenn der Server ausgeführt wird:

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) 

Die Server-Datei server.js enthält:

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 

Die ganze Routine scheint richtig zu arbeiten: der Staat, die von getState() sieht gut aus und die verschiedenen Routen stimmen mit den Erwartungen (was auch immer ich im Browser tippe) mit der richtigen Route innerhalb der Schleife überein.

Ich befolge die asynchronen Routen des React-Routers (wie in dieser example beschrieben). In dieser speziellen Frage, der Inhalt des routes/About/index.js ist:

// 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) 
    }) 
    } 
} 

Ich habe auch doppelt überprüft die verschiedenen Komponenten sicherstellen, dass sie alle das Reagieren importieren Bibliothek (dh import React from 'react'.). Auch wenn ich Webpack zum Kompilieren der gesamten Anwendung verwende, gibt es keine Probleme.

Antwort

1

Sie müssen auch Reagieren Sie auf Ihre server.js Datei importiert werden, weil nach transpiling folgende

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

sieht wie folgt aus

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