Goku是《七龙珠》的主人公孙悟空,神通广大,解决世间存在的问题。同样,尝试前后端分离,也希望可以解决目前前端开发中存在的痛点。
整体上使用MVC的架构,但跟Angular不同(双向绑定),数据是单向流动的,数据单向流动有如下的好处:
MVC各层使用的基本技术:
Goku整体架构主要存在四个实体: 浏览器(browser)、nginx、node中间层、后端sever。跟传统的网站架构相比,多了一层node中间层,该层也是Goku的核心。
因为使用了react-router,所以整个系统就是一个单页面应用(SPA):
这里面存在一个问题:如果保证前后端渲染的一致性? 即要求react的 data-react-checksum
前后结果保持一致。
JSON.stringify(datat)
传递给页面 new Date()
,则这个时间在node和browser渲染后就会造成不同 nginx已经非常流行,起到请求分发和负载均衡的作用。这里,通过nginx将不同的请求,分发到不同的服务器上:
node server就是一个中间层,起到两个作用:
具体来说,可以分为如下几个功能点:
思路: 根据请求的URL + react router的router配置信息,得到匹配的component
import { match, RoutingContext } from 'react-router'; import routes from './routes'; serve((req, res) => { match({ routes, location: req.url }, (err, rediction, renderProps) => { if (...) { res.status(200).send(htmlStr); } }) })
思路: 每个URL均有指定的首屏数据,通过Promise.all并发地发布异步请求,当所有数据都拿到后,执行回调函数
Promise.all([promise1, promise2, ..., promisen], (vals)=> { ... const initialState = val; const store = createStore(reducer, initialState); })
思路: 使用react的 renderToString
得到静态化数据
Promise.all([promise1, promise2, ..., promisen], (vals)=> { ... const initialState = val; const store = createStore(reducer, initialState); ... const props = { store, ... }; str = React.renderToString(App, props); });
思路: 每个api跟一个相应的js文件对应起来,js文件通过 mockjs
的数据模板完成数据的mock
思路: 将3.3得到的字符串 str
与html的其他内容(例如 mta
、 <script>
)、首屏数据( initialState
)拼接得到一个完整的html字符串
通过使用browserify的transform function、plugin进行了功能的拓展,可以完成更多的事情。同时使用watchify来watch文件的变化。
思路: 使用css-modules,将css文件映射成一个js对象和css线上文件,在jsx中直接require css
思路:为了避免将所有的文件打包成一个js文件,使用browserify的plugin机制(使用factor-bundle插件)来进行js文件的拆分,然后使用react router的getComponent、getChildroutes完成动态加载。
通过3.4.2, 将文件打包成一个公共js文件、若干个业务文件,同时采用树形结构来进行文件的组织。类似于: https://github.com/rackt/react-router/tree/master/examples/huge-apps
为了保证node服务的稳定性,需要进行一些监控,保证服务的稳定性,包括:node进行管理、falcon机器监控、sentry收集浏览器异常、性能监控、权限管理、日志管理
目前是通过一个内网域名进行访问,当然这种方式存在一些问题:多一次域名解析、访问协议等。
在这种架构下,后端服务只提供API,不再涉及后端模板、URL controller,后端同学可以专注于数据处理,不需要留意页面展示,前后端分工更加明确。
先说感受最深的收益吧:
代价:
针对上述问题,个人认为,目前前后端分离适合于一些访问量不大的内部系统,而对于大pv量的页面,还是采用传统的两层架构(B/S)。