搬運
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作匹配 執行特定的組件邏輯