2015-06-03 40 views
29

我试图为我的反应应用程序设置服务器端渲染,我试图使用伟大的react-router模块来允许它处理非js情况(一些爬虫,当用户由于某种原因关闭了js)。但是,我遇到了麻烦。我一直在使用https://stackoverflow.com/a/28558545/3314701这个伟大的响应作为指导,但我得到了奇怪的错误。尝试使用react.renderToString()时,我得到持续的Syntax Error。我是否设置了错误的服务器端渲染,丢失了明显的东西,还是其他的东西?服务器端渲染与反应,react-router和express

我的设置:

很基本的Express服务器

require('babel/register'); 

var app = express(); 


// misc. express config... 

var Router = require('react-router'), 
    routes = require('../jsx/app').routes, 
    React = require('react'); 


app.use(function(req, res, next) { 
    var router = Router.create({location: req.url, routes: routes}); 
    router.run(function(Handler, state) { 
    console.log(Handler); 
    var html = React.renderToString(<Handler/>); 
    return res.render('react_page', {html: html}); 
    }); 
}); 

顶级反应<App/>组件

// Shims 
require('intl'); 
require('es5-shim'); 

var React = require('react/addons'), 
    Router = require('react-router'), 
    Nav = require('./nav'), 
    injectTapEventPlugin = require("react-tap-event-plugin"), 


    window.React = React; // export for http://fb.me/react-devtools 

// Intl 
var ReactIntl = require('react-intl'), 
    IntlMixin = ReactIntl.IntlMixin; 

var Route = Router.Route, 
    DefaultRoute = Router.DefaultRoute, 
    NotFoundRoute = Router.NotFoundRoute, 
    RouteHandler = Router.RouteHandler; 


var App = React.createClass({ 
     mixins: [IntlMixin], 

     getInitialState: function() { 
     return { 
      connected: false, 
      loaded: false, 
      user: true 
     }; 
     }, 
     render: function() { 
      return ( 
      <div className="container-fluid"> 
       <Nav/> 
       <RouteHandler/> 
       <Footer/> 
      </div> 
    ); 
    } 

}); 

var routes = (
<Route name="Home" path="/" handler={App}> 
    <DefaultRoute name="Welcome " handler={Welcome}/> 
    <Route name="Bar" path="/bar" handler={Bar}> 
    <Route name="foo" path="/foo" handler={Foo}></Route> 
</Route> 
); 

Router.run(routes, Router.HistoryLocation , function(Handler) { 
    React.render(<Handler/>, document.getElementById('app')); 
}); 

module.routes = routes; 

输出:

flo-0,1,2 (err):  <div className="progressbar-container" > 
flo-0,1,2 (err):  ^
flo-0,1,2 (err): SyntaxError: Unexpected token < 
flo-0,1,2 (err):  at exports.runInThisContext (vm.js:73:16) 
flo-0,1,2 (err):  at Module._compile (module.js:443:25) 
flo-0,1,2 (err):  at Module._extensions..js (module.js:478:10) 
flo-0,1,2 (err):  at Object.require.extensions.(anonymous function) [as .js] (/Users/user/Code/foobar/apps/flo/node_modules/babel/node_modules/babel-core/lib/babel/api/register/node.js:161:7) 
flo-0,1,2 (err):  at Module.load (module.js:355:32) 
flo-0,1,2 (err):  at Function.Module._load (module.js:310:12) 
flo-0,1,2 (err):  at Function.<anonymous> (/Users/user/.nvm/versions/node/v0.12.4/lib/node_modules/pm2/node_modules/pmx/lib/transaction.js:62:21) 
flo-0,1,2 (err):  at Function.cls_wrapMethod (/Users/user/Code/foobar/apps/bar/node_modules/newrelic/lib/shimmer.js:230:38) 
flo-0,1,2 (err):  at Function.<anonymous> (/Users/user/Code/foobar/apps/bar/node_modules/pmx/lib/transaction.js:62:21) 
flo-0,1,2 (err):  at Module.require (module.js:365:17) 
flo-0,1,2 (err):  at require (module.js:384:17) 
+0

错误似乎并没有涉及到您发布的代码,更像是你忘了包含一个JSX pa rser的地方 – David

+0

我已经在一些例子[这里](https://github.com/goatslacker/isomorphic-react-examples)使用alt和iso与反应路由器,希望它可以有用 –

回答

40

所以,我最终自己解决了这个问题。我得到的错误是来自未呈现的嵌套组件,这就是为什么js引擎在抱怨随机发生的char。

现在以我的快速设置。对于那些不知道如何使用服务器端渲染的反应的人来说,这很简单:Node或io.js可以用来在组件上调用React的renderToString()方法,然后将它发送给请求客户端。你可能听说过这种方法已经带来的好处,但对于那些谁不知道:

  1. 你获得更多的SEO友好,尽管谷歌已经可以在它的爬虫执行JS;这几乎只是一个更安全的赌注
  2. 非js情况下的回退。如果您的应用程序脚本加载速度较慢,则仍然可以将实际页面呈现给客户端,而不会让他们在等待空白屏幕时等待。这也允许在浏览器上禁用JS的用户仍然可以与应用进行大部分交互;链接仍然有效,表单仍然可以提交,& c。
  3. 您可以从客户端和服务器之间获得代码共享的额外好处。除了复杂性降低之外,没有什么必然令人难以置信,因此,您将获得降低复杂性的所有好处(可能耦合度更低,维护更简单,结构更简单,同构性更强)
  4. 另一个好处是可以使用react-router的html5历史API,而不必使用恼人的散列片段。

你甚至可以用这种方法疯狂并为加载或提供缓慢加载状态的其他反馈机制(加载时的Facebook)处理应用程序的占位符等内容。

的基本方法以下面的方式大致操作:

  1. 在自举时,节点的应用程序实例化基于routes.jsx
  2. 索取反应路由器实例前进到服务器,该服务器然后使用快速req.path为反应路由器提供一个路由字符串来处理。
  3. React路由器然后匹配提供的路由并尝试渲染相应的组件以便快速发回。
  4. React向下发送html响应,并且无论应用程序脚本的速度如何,您的客户端都可以绘制某些内容。我们通过一个伟大的CDN为我们提供服务,但即使采用最佳分配和压缩速度,缓慢的网络仍然会让人们暂时屏蔽掉黑屏。
  5. 在加载了所需的应用程序脚本后,React可以使用相同的routes.jsx文件接管并从此生成带有react-router的html。这里的另一个好处是你的应用程序代码可以被缓存,并且未来的交互有希望甚至不需要依赖另一个呼叫。

还有一点值得注意的是:我使用webpack捆绑我的反应代码,现在browser.jsx是入口点。在重构服务器端渲染之前,它先前是app.jsx;您可能需要重新配置您的结构以适应在什么地方渲染。 :)

乐代码:

Browser.jsx

const React = require('react'); 
const Router = require('react-router').Router; 
const hist = require('history'); 
const routes = require('./routes'); 

const newHistory = hist.createHistory(); 

React.render(<Router history={newHistory}>{routes}</Router>, window.document); 

App.js(Express服务器)

//...other express configuration 

const routes = require('../jsx/routes'); 
const React = require('react'); 
const {RoutingContext, match} = require('react-router'); 
const hist = require('history'); 

app.use((req, res, next) => { 
    const location = hist.createLocation(req.path); 
    match({ 
    routes: routes, 
    location: location, 
    }, (err, redirectLocation, renderProps) => { 
    if (redirectLocation) { 
     res.redirect(301, redirectLocation.pathname + redirectLocation.search); 
    } else if (err) { 
     console.log(err); 
     next(err); 
     // res.send(500, error.message); 
    } else if (renderProps === null) { 
     res.status(404) 
     .send('Not found'); 
    } else { 
     res.send('<!DOCTYPE html>' + React.renderToString(<RoutingContext {...renderProps}/>)); 
    } 
    }); 
}); 

    //...other express configuration 

Routes.jsx

<Route path="/" component={App}> 
    <DefaultRoute component={Welcome}/> 
    <Route path="dashboard" component={Dashboard}/> 
    <Route path="login" component={Login}/> 
</Route> 

App.jsx

<html> 
<head> 
    <link rel="stylesheet" href="/assets/styles/app.css"/> 
</head> 
    <body> 
    <Navigation/> 
    <RouteHandler/> 
    <Footer/> 
    <body/> 
</html> 

有用的链接:

+5

我的荣幸 - 将再次更新某些时候很快会有更新的反应路由器API更改 – markthethomas

+1

@markthethomas您是如何在app.js服务器脚本中使用JSX的? –

+0

你也可以检查我的启动器REDX,REDX-传奇,react-router v4 https://github.com/gzoreslav/react-redux-saga-universal-application –