摘要:從零開始搭建同構(gòu)應(yīng)用三配置這篇文章來講解來配置,我們先從最簡單的方法開始,用的方式模擬實現(xiàn)。影響生產(chǎn)環(huán)境下執(zhí)行效率。最后權(quán)衡下,還是決定使用現(xiàn)在多一套編譯配置的方案。新建,寫入以下內(nèi)容以為例,注意不能少。
從零開始搭建React同構(gòu)應(yīng)用(三):配置SSR
這篇文章來講解來配置server side render,我們先從最簡單的方法開始,用cli的方式模擬實現(xiàn)SSR。
demo在這里
主要內(nèi)容:
添加webpack的server render配置
使用CLI的方式測試SSR輸出
添加webpack的server render配置之前我是考慮在node端直接require源碼,例如:
//hook require require("babel-register")({ babelrc: "false", presets: ["react"], plugins: [ "transform-decorators-legacy", "transform-es2015-modules-commonjs" ] }); //直接引入源碼 const IndexBundle = require("./src/index/Index.jsx"); //do server side render...
這樣少編譯一套代碼,覺得這樣維護起來更方便,但是后來實踐發(fā)現(xiàn)有幾個問題:
import "xxx.styl",引入樣式文件會報錯。
這種模式下需要使用babel-register,babel編譯速度較慢,開發(fā)模式下每次修改文件再重啟服務(wù)器耗時太長。
影響生產(chǎn)環(huán)境下執(zhí)行效率。
最后權(quán)衡下,還是決定使用現(xiàn)在多一套ssr編譯配置的方案。
在webpack.config.js添加以下代碼
let serverConfig = {}; Object.assign(serverConfig, browserConfig, { output: { path: path.join(__dirname, "build_server"), filename: "[name].bundle.js", libraryTarget: "commonjs2" //設(shè)置導出類型,web端默認是var,node需要module.exports = xxx的形式 }, module: { loaders: [ { test: /.jsx?$/, exclude: /node_modules/, loader: "babel-loader", query: { //node端的babel編譯配置可以簡化很多 babelrc: "false", presets: ["react"], plugins: [ "transform-decorators-legacy", "transform-es2015-modules-commonjs" //如果不轉(zhuǎn)換成require,import "xxx.styl"會報錯 ] } }, { test: /.(styl|css)$/, //node端不能 require("xx.css"),會報錯 loader: "null" }, ] }, plugins: [ new webpack.ProvidePlugin({ React: "react", ReactDOM: "react-dom", fetch: "isomorphic-fetch", promise: "promise" }), new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV) || JSON.stringify("development") }), ], target: "node", externals: [nodeExternals()], //不把node_modules中的文件打包 });
因為serverConfig的配置和browserConfig相似,我就使用Object.assign來復制一份,同時做下修改。
nodejs啟用 --harmony參數(shù)就可以支持絕大部分的ES6,ES7語法,如async等,因此只需要編譯JSX語法和import語法。babel的編譯速度也因此可以提高很多。babelrc: "false"是為了屏蔽項目目錄下的babel.rc文件,那是給瀏覽器端編譯使用的。
同時,在node環(huán)境不支持直接引入CSS文件的,如require("xx.css"),因此在打包的時候要忽略樣式文件和資源文件,否則會報錯。
這里我使用了webpack-node-externals插件,這個插件的原理是利用了webapck中的externals配置項,來剔除node_modules文件的,因為默認webapck會把所有用到的js文件統(tǒng)統(tǒng)打包,而我們由于是在node端,因此不需要把用到的庫也打包了。
執(zhí)行試試
npm run watch
如果不用webpack-node-externals,打包出的文件體積會大很多
測試SSR輸出其實使用React的ssr很簡單,熟悉下面兩個API即可:
React.createElement
ReactDOMServer.renderToString
React.createElement這里簡單解釋下,React.createElement把React類進行實例化,實例化后的組件就可以進行mount操作了,在瀏覽器環(huán)境我們是使用ReactDOM.render()來進行掛載操作的。
ReactDOMServer.renderToString而ReactDOMServer.renderToString則是把React實例渲染成HTML標簽。
測試這里我們先不搭建HTTP server,暫時用cli的方式模擬一下,方便大家理解。
新建cli.js,寫入以下內(nèi)容(以Index.jsx為例),注意:.defalut不能少。
/** * Created by chenchen on 2017/2/4. * * React server render 命令行測試 */ //以Index.jsx為例 const IndexBundle = require("../build_server/index.bundle.js"); const React = require("react"); const ReactDOMServer = require("react-dom/server"); let {renderToString} = ReactDOMServer; let initialData = {todoList: ["11", "22", "33"]}; let instance = React.createElement(IndexBundle.default, initialData); //.defalut不能少 let str = renderToString(instance); console.log(str);
我們添加一條npm script
"test-ssr": "node --harmony test/cli.js"
執(zhí)行后效果如圖
可以看到我們已經(jīng)成功輸出了組件渲染后的HTML文本了。
下一篇文章我將講解如何搭建一個簡單的Koa server,并結(jié)合這邊文章內(nèi)容,實現(xiàn)真正意義上的server side render ^_^。
要注意的地方 React生命周期React組件的聲明周期只會到componentWillMount,因此你不能在componentWillMount及其之前的生命周期鉤子中寫瀏覽器環(huán)境下的代碼,如$.ajax(...),會報錯。
前后端數(shù)據(jù)同步要注意瀏覽器端和服務(wù)器端的數(shù)據(jù)要一致,否則會出現(xiàn)HTML重用失敗的錯誤:
可能有人會疑惑,在瀏覽器編譯的代碼是:
//初始數(shù)據(jù),用于和server render數(shù)據(jù)同步 let initialData = window._SERVER_DATA || {}; let store = createStore(reducers, initialData, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); let App = connect(_ => _)(Layout);//用connect包裝一下,這里只用到mapStateToProps,而且不對state加以過濾 ReactDOM.render(, document.getElementById("wrap"));
而server端的編譯沒有和Redux沾邊,因為Provider和connect(...)(Layout)是functional component,本身不會多渲染出來HTML,因此可以不用Redux參與渲染。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/81385.html
摘要:從零開始搭建同構(gòu)應(yīng)用四搭建完善上一篇我們使用了的方式測試了,這篇文章來講如何在前文的基礎(chǔ)上搭建一個,實現(xiàn)真正意義上的。至此,一個簡單的框架已經(jīng)搭建完成,剩下的工作就是結(jié)合工作需要,在里面添磚加瓦啦。 從零開始搭建React同構(gòu)應(yīng)用(四):搭建Koa Server & 完善SSR 上一篇我們使用了CLI的方式測試了SSR,這篇文章來講如何在前文的基礎(chǔ)上搭建一個Koa Server,實現(xiàn)真...
摘要:它會檢測出最大靜態(tài)子樹就是不需要動態(tài)性的子樹并且從渲染函數(shù)中萃取出來。這樣在每次重渲染的時候,它就會直接重用完全相同的同時跳過比對。需要注意的是,中的操作必須是同步的,不可以存在異步操作的情況。 新增:哈哈,最近又推出了 vue 的文章,在這里放個鏈接~手把手教你從零寫一個簡單的 VUE 感謝有人看我扯技術(shù),這篇文章主要介紹最近非常火的vue2前端框架的特點和vue2+vuex2+we...
摘要:它會檢測出最大靜態(tài)子樹就是不需要動態(tài)性的子樹并且從渲染函數(shù)中萃取出來。這樣在每次重渲染的時候,它就會直接重用完全相同的同時跳過比對。需要注意的是,中的操作必須是同步的,不可以存在異步操作的情況。 新增:哈哈,最近又推出了 vue 的文章,在這里放個鏈接~手把手教你從零寫一個簡單的 VUE 感謝有人看我扯技術(shù),這篇文章主要介紹最近非?;鸬膙ue2前端框架的特點和vue2+vuex2+we...
摘要:它會檢測出最大靜態(tài)子樹就是不需要動態(tài)性的子樹并且從渲染函數(shù)中萃取出來。這樣在每次重渲染的時候,它就會直接重用完全相同的同時跳過比對。需要注意的是,中的操作必須是同步的,不可以存在異步操作的情況。 新增:哈哈,最近又推出了 vue 的文章,在這里放個鏈接~手把手教你從零寫一個簡單的 VUE 感謝有人看我扯技術(shù),這篇文章主要介紹最近非?;鸬膙ue2前端框架的特點和vue2+vuex2+we...
閱讀 2733·2023-04-25 14:21
閱讀 1167·2021-11-23 09:51
閱讀 4001·2021-09-22 15:43
閱讀 606·2019-08-30 15:55
閱讀 1550·2019-08-29 11:28
閱讀 2439·2019-08-26 11:44
閱讀 1675·2019-08-23 18:15
閱讀 2875·2019-08-23 16:42