基于React服务器端渲染的博客系统
目录
1. 开发前准备
1.1 技术选型
1.2 整体设计
1.3 构建开发
2. 技术点
2.1 react
2.2 redux, react-router
2.3 server-render
3. 总结
正文
1. 开发前准备
1. 1 技术选型
对于个人的博客系统而言,服务器计算能力往往不是需要考虑,而其中的 I/O 操作是比较复杂的,同理对前端的交互要求也是较高的,所以这次主要还是围绕 Node系 ,React系 框架进行开发。对于 2016 年后的互联网产品, React 搭建的 SPA ( single page ) 以及 React-Native 搭建的类似 hybrid 的原生应用,这样的开发模式,会引导今后 3 年产品的开发。
1.2 整体设计

图描绘的很简单,简单来说前端采用 React + React-router + Redux 以 flux 模式进行开发,后端采用了两个 Node Server 提供 React 服务器端渲染和数据提供,这里可以先看为一个服务器,为啥要采用两个,后面会提到。如果你有开发前后端分离项目的经验,你可以将提供 React 服务器端渲染这一块与前端合并,我们可以在上面书写 xtpl , ejs , jade 这些模板,开发起来更为流畅。
由于我的服务器是在华北地区,加上 React 这一系列的库又都是非常大的,即使我将 js , css 文件都打包成一个文件,访问起资源加载也是特别慢,所以 CDN 也是必不可少的。
1.3 构建开发
对工程完成大致设计后,我们需要利用前端工具做一些利于开发的构建,可以大致分为以下 3 个任务。
method1: 本地服务器的热加载
开发静态组件阶段为了提升开发效率,减少各位小白对 F5 的使用量,我们一般使用 webpack-dev-server 做本地服务,与一般的 webpack 配置文件不同之处也就在于入口点 entry 多加了点东西。
entry: {
app: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
path.resolve(__dirname, '../views/index.js')
]
}
将 webpack 中的选项传入到 webpack-dev-server (一个 express 服务器) 对象
new WebpackDevServer(webpack(webpackConfig), {
publicPath: '/',
hot: true, // 热替换开启
historyApiFallback: true, // 无刷更改url,配合react-router使用
inline: true, // 热替换开启
stats: {
colors: true
}
}).listen(PORT, FUNC);
接着启动你的服务器即可完成构建。
method2: 静态资源分离
通常在开发阶段会有 import ./xxx.less 或 require('xxx.png') ES5 / ES6 语法来引入静态资源, 在打包时我们需要把所有静态文件和我们的组件解耦在合并成一个文件,这同样需要 webpack 来完成,同时要引入名为 extract-text-webpack-plugin 的插件,具体使用如下
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.export = {
module: {
loaders: [
... // other settings
{
test: /\.css/,
loader: ExtractTextPlugin.extract('style', ['css'])
},
{
test: /\.less/,
loader: ExtractTextPlugin.extract('style', ['css', 'less'])
},
]
},
plugins: [
new ExtractTextPlugin('[name].css'),
... // other settings
]
}
method3: 服务器端渲染
首先,明确一点的是 node 稳定的 4.x 版本并不能支持所有 ES6 的语法,因此采用 ES6 的语法写 node 服务器端,需要先转到 ES5 再执行,一般来说有两种方法。一是下载 babel-node 到操作系统直接执行,二是利用 webpack 引入 babel-loader,babel-core 打包(其实两种方法是一种思想)。所以按照正常 ES6 -> ES5 的构建流程打包即可。
module.export = {
node: {
fs: 'empty',
net: 'empty',
// 防止打包错乱
__filename: true,
__dirname: true
}
}
如果打包过程中出现了大量有关 fs , net 模块的报错或者打包后出现了文件引入的错误,添加上述 webpack 选项即可解决问题,这两种都是在 node 端打包经常出现的问题。
2. 开发
先来看看整个工程目录是怎样的。

build: 上述中各构建文件
server: 用于服务器端渲染的文件
views: 前端组件及redux状态管理文件系统
2.1 react
对于 react 语法这里就不提了,重点提下文件的组织方式,以便我们开发和日常维护。若只针对于工作量不大 react ,目录很简单,只需区分展示级组件( compnent ) 和 复合型组件( containers )。
--- views/
--- components/ 各展示级组件
--- containers/各复合型组件
具体呈现形式可在 github 上了解
2.2 redux, react-router
刚开始写 react 的时候总是觉得 redux 和 react-router 是一个哗众取宠的存在,直到数据量和逻辑变复杂,后台逻辑愈加复杂,而前端的 react 组件还是如同开始的上手练习一样,一直做着自顶向下的数据传递和渲染,每次更新数据我们都会请求服务器,这无疑增加了服务器的压力(对较大型应用),同时没有发挥react的长处,所谓的单页应用更是纸上谈兵。
那将三者结合会是怎样的开发体验和用户体验呢?
redux

上图是 facebook 提出 flux 架构思想,是专门用于软件的结构问题的,对于 react 开发它提供一种非常简单清晰的思想。
View : 视图层 ( react 组件)Action (动作): 视图层发出的消息(比如 mouseClick )Dispatcher (派发器) : 用来接收 Actions 、执行回调函数Store (数据层) : 用来存放应用的状态,一旦发生变动,就提醒 View 要更新页面
而 redux 提供了 action , dispatcher( redux 中是 reducer ), store 的实现 ,如何实现的呢?就拿个加载某一页数据做个例子。
action.js : loadThisPage 是一个action creater,每次调用就能创建一个带有 LOAD_THIS_PAGE 指令的对象给 reducer。
const LOAD_THIS_PAGE = 'LOAD_THIS_PAGE';
const loadThisPage = (pN) => {
return {
type: LOAD_THIS_PAGE,
pN
}
}
reducer.js : 在 reducer 中,通过判断指令来调用 store 中的数据改变状态
const LOAD_THIS_PAGE = 'LOAD_THIS_PAGE';
const articleReducer = (state = {}, action) => {
switch(action.type) {
case LOAD_THIS_PAGE:
return {
allArticles: state.allArticles,
articles: state.allArticles.slice(0, action.pN * 5)
};
default:
return state;
}
};
store.js : 创建一个 store 对象,可以通过调用这个对象的 dispatch 方法传入 action。
import { createStore, applyMiddleware} from 'redux';
const store = createStore(
reducers,
applyMiddleware(thunk) // 若需要redux中间件才添加
);
这些工作做完后,还需要将 store 和组件进行一个关联,也就是说组件要能获得 redux store。
import { Provider, connect } from 'react-redux';
// 通过connect连接组件和store
const HomeApp = connect(
(state) => {
return {
articles: state.articleReducer.articles,
articleLen: state.articleReducer.allArticles.length
};
}
)(Home);
const routes = (
<Route path="/" component={ LeftArea }>
<IndexRoute component={ HomeApp } />
</Route>
);
// store通过Provider传入到react组件
render(
<Provider store={store} key="index">
<Router history={browserHistory} routes={routes}>
</Router>
</Provider>, document.getElementById('app')
);
react-router
相比 redux , react-router 理解起来就好多了,每当 url 发生变化,改变的只是组件,而不会重新刷新页面。
对于这样一个SPA,用户访问只需加载一次数据,之后的逻辑都由浏览器来完成了~所以对交互性来说也是很大的提升。
2.3 server render
为什么需要去实现 server render ? 也就是说服务器端渲染比客户端渲染优在哪里?
server render vs client render
服务器端渲染更利于 SEO ,更容易被爬虫识别
服务器端渲染可以增加访问速度,用户访问时直接推送已经渲染好的 react 页面,不同于客户端渲染的将 react 放入浏览器中渲染。同时减少用户CPU开销,获得更好交互性,解决了首屏加载慢的问题。
分离前后端逻辑,利于开发
如何做到 react 服务器端渲染,其实 facebook 很早就给出了解决方案,并推出了 react-dom/server 库。
import { renderToString } from 'react-dom/server';
const html = renderToString(
<Provider store={store}>
<RoutingContext {...renderProps} />
</Provider>
);
最初的一个问题
为什么会采用两个node服务器呢?因为在进行 webpack 对 Node 的打包时,会将数据库的相关信息打包到一起,放在网络上是不安全的,所以需要创建另一个服务器专门用提供持久化数据服务。
3. 总结
这篇博文没有对技术做太多深入的探究,但提供了一个比较清晰地开发思路,刚从事开发工作或者还是小白的你可能在独立开发一个工程时会存在很多疑问,从构建到设计,从性能到安全都是需要考虑的。
今天微信小程序也正式上线了,赶紧去尝尝鲜~
基于React服务器端渲染的博客系统的更多相关文章
- vuejs+nodejs支持服务端渲染的博客系统
感悟 历时两个多月,终于利用工作之余完成了这个项目的1.0版本,为什么要写这个项目?其实基于vuejs+nodejs构建的开源博客系统有很多,但是大多数不支持服务端渲染,也不支持动态标题,只是做到了前 ...
- 基于express+mongodb+pug的博客系统——pug篇
很久之前就想自己搭一个博客了,最开始用hexo+github,但是换电脑后总是有些麻烦.后来使用WordPress,但是用WordPress总觉得没什么技术含量,前后端都是人家写好的,而且买的垃圾虚拟 ...
- 基于express+mongodb+pug的博客系统——后台篇
上一篇介绍了模板引擎pug.js的用法,这一篇就主要写后台逻辑了. 后台的大部分的功能都有了,只是在已经登录的状态下,前台和后台的逻辑处理还不是很完善. 先上几张图吧,仿旧版的简书,改了下UI,因为没 ...
- 基于开源博客系统(jpress)搭建网站
基于开源博客系统(jpress)搭建网站 JPress 使用 Java8 开发,基于流行的JFinal和Jboot框架. 目前JPress已经内置的文章和页面其实是两个模块,可以移除和新增其他模块,因 ...
- Asp.net博客系统收集和简单介绍
国内Asp.net博客系统收集和简单介绍 [转载文章,仅供个人参考,引自http://www.soyaoo.com/Blog/post/92.html] 1.ZJ-Blog程序简介:基于A ...
- 基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统
很久没更新博客,最近也有点忙,然后业余时间搞了一个比较完整基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统的流程系统,希望对 ...
- 分享个基于 Node.js + React 的博客系统
是使用 ES2015+ 特性写的,使用了 ThinkJS 框架,后台使用了 React. 完全使用 Markdown 来写文章,还可以把文章推送到团队博客系统中(团队博客也需要使用该系统). 项目地址 ...
- 欢迎阅读daxnet的新博客:一个基于Microsoft Azure、ASP.NET Core和Docker的博客系统
2008年11月,我在博客园开通了个人帐号,并在博客园发表了自己的第一篇博客.当然,我写博客也不是从2008年才开始的,在更早时候,也在CSDN和系统分析员协会(之后名为"希赛网" ...
- 一个基于Microsoft Azure、ASP.NET Core和Docker的博客系统
2008年11月,我在博客园开通了个人帐号,并在博客园发表了自己的第一篇博客.当然,我写博客也不是从2008年才开始的,在更早时候,也在CSDN和系统分析员协会(之后名为“希赛网”)个人空间发布过一些 ...
随机推荐
- linux (centos 6.4)安装自定义分区方案(转载)
在计算机上安装 Linux 系统,对硬盘进行分区是一个非常重要的步骤,下面介绍几个分区方案. 方案 1 / :建议大小在 5GB 以上. swap :即交换分区,建议大小是物理内存的 1~2 倍. 方 ...
- 【转】C# Excel 导入到 Access数据库表(winForm版)
/// <summary> /// 获取Excel文件 /// </summary> /// <param name="sender">< ...
- PHP — 用PHP实现一个双向队列
1.简介 deque,全名double-ended queue,是一种具有队列和栈的性质的数据结构.双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行.双向队列(双端队列)就像是一个队 ...
- mysql 查看数据库大小
select table_schema, concat(truncate(sum(data_length)/1024/1024,2),' mb') as data_size,concat(trunca ...
- gwt 创建 超链接cell (HyperTextCell)
package com.cnblogs.hooligen.client; import com.google.gwt.cell.client.AbstractCell; import com.goog ...
- java创建多线程(转载)
转载自:Java创建线程的两个方法 Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对 ...
- BeeFramework
A semi-hybrid framework that allows you to create mobile apps using Objective-C and XML/CSS
- js函数语法
<script type="text/javascript"> //1 普通方法 /* * function 方法名(参数){ * 方法体 * ...
- delphi xe5 android sample 中的 SimpleList 是怎样绑定的
C:\Users\Public\Documents\RAD Studio\12.0\Samples\FireMonkeyMobile 例子中的绑定方式如下图: 1.拖拽一个listview到界面上,然 ...
- shell 练习
shell 练习 iii= ] do iii=$[$iii+] echo -n "$iii " done iii= ] do iii=$[$iii+] echo -n " ...