搬运
http://www.javashuo.com/article/p-mxfmiscw-cc.htmljavascript
同构就是但愿前端 后端都使用同一套逻辑 同一套代码
Nodejs出现后 这一设计方式的实现更加容易了 后端一样能够根据路径来加载js文件渲染指定的页面 而React又拥有renderToString 以及 renderToStaticMarkup方法
能够将react组建渲染成html字串html
renderToString VS renderToStaticMarkup
这二者都是将 React元素变成原始的HTML, 且都是服务端在使用, 不一样的是renderToStaticMarkup不会建立出额外的React的属性 好比 data-react-id等 主要是用于建立一个纯粹的静态页, 这样能够节省不少带宽前端
就是但愿服务器在响应某个请求所调用的逻辑
客户端对于该路径的处理也是使用同一套逻辑 (客户端对于路径处理 指的是运用了Hash或者Histroy State的SPA页面 对不一样路径的处理)
更通俗一点的说法, 客户端和服务端对于同一个路径所做出的响应会使用到共同的文件(但并不表示对于同一个路径 他们处理的逻辑彻底相同)java
关于react-router的browserHistroynode
若是你设置某个页面的router为 / 的话
访问这个页面的路径应该是 domian.xx:port/
以前没有理解browserHistroy 目标app是在一个很深的路径下
当时使用这个路径去访问
localhost/ReactStudy/RouterStudy/
天然就会出现 Location / Not matchreact
咱们知道Server端对于一个请求的处理, 就是根据不一样的路径作出不一样的响应 因此Server端的响应应该是一个完整的页面 以后在页面上发生的任何路径的改变, 都应该交给react route处理 Server再也不参与后续的任务webpack
这里Server使用koa来实现 服务端的路径处理使用koa-routerweb
let app = koa(); let router = koaRouter(); router.get(['/', '/home'], function*() { // 执行view插件 // 调用render方法 this是app的context // 因此调用的this.render 也就是 this.body = this.render('Home', { microdata: microdata, mydata: { nick: 'server render body' } },1); }); app.use(router.routes()).use(router.allowedMethods());
能够看到整个响应体this.body的渲染由一个render方法完成
这个render调用了一个文件专门渲染服务端的页面 这个页面请求一个js文件 这个js文件就是整个客户端的逻辑segmentfault
可能这个页面的一些渲染就是由和客户端通的组件获得的 可是并不必定会有共同的部分
这样服务器能够直接将一些信息渲染到页面中 解决了SEO的问题
可是这个过程很是的慢后端
慢的缘由是由于这个render须要根据路径动态的require一些组件 而后解析等等
这些被require的组件若是是采用了ES6的方式编写 须要用 'babel-register' 来处理
它是一个Hook, 能够在require一个组件的时候作一些处理, 将ES6编译成ES5
因为这里是动态的处理这个编译的过程 这个服务端的响应就更加慢了
render() { // 对象的解构赋值 const { microdata, title, children } = this.props; return ( <html> <head> <meta charSet='utf-8' /> <meta httpEquiv='X-UA-Compatible' content='IE=edge' /> <meta httpEquiv='Cache-Control' content='no-siteapp' /> <meta name='renderer' content='webkit' /> <meta name='keywords' content='demo' /> <meta name='description' content='demo' /> <meta name='viewport' content='width=device-width, initial-scale=1' /> <title>{title}</title> </head> <body> {children} {this.renderScripts()} </body> </html> ); }
须要注意的是, 并非有了babel-loader 全部的ES6均可以顺利的变成ES5, Babel Online上能够看到关于ES6的语法有不一样的presets的设置 默认状况下 class 的static 不能直接经过babel-loader编译 解决方案在这里http://jsrocks.org/2016/01/configuring-babel-6-for-node-js/
须要参数 你能够在.babelrc中加入下面的配置或者在webpack.config.js中添加params参数{ "plugins": ["es2015", "stage-0"] }
客户端最终的结果是一个OR多个js文件, 它包含了全部的页面上的逻辑以及页面之间的跳转(这里用的是react-router)
服务端生成了页面以后, 能够将一些参数(好比路径的参数) 直接写在页面中, 而后客户端从页面中获取这些参数值而后执行,
客户端主要逻辑
render() { let { isServer, mydata } = this.props; return ( <Router history={browserHistory}> <Route path="/" component={Nav}> <Route path="/device/:deviceID" component={DeviceView}/> </Route> </Router> ); }
等客户端的逻辑一开始执行 就会根据当前的url作匹配 执行特定的组件逻辑