什么是ssr:server side render,服务端渲染php
不一样于jsp,php等传统服务端渲染(这种状况下,先后端代码是分开的,写了两份)html
目前的ssr是基于react vue等前端框架的同构渲染(即一份代码,同时运行在server和client端),开发人员只关注业务实现便可前端
ssr的优缺点就不细说了,无非seo,首屏更快,学习成本变高,加大服务端资源开销等vue
目前咱们项目都逐步采用ssr方案,基于nextjs重构,做为开发人员,对原理比较好奇,研究一下node
大体的流程以下图react
打包阶段会将业务代码打包两次,一份部署在服务端,一份用于客户端(可传到cdn)git
而后启动服务,基于用户请求的路由决定render哪一个页面,主要用到renderToStringapi将page组件转化为html标记github
最简单的状况,将html标记直接返回客户端,渲染一个静态页面后端
但实际业务中,通常在服务端须要获取数据,根据数据来生成html,这种状况下,当在客户端从新render时,如何保证数据一致呢,解决办法是将服务端获取到的数据以字符串的形式返回给客户端,客户端渲染的时候直接以该数据进行渲染,保证数据的一致性,进而保证了ui的一致性api
当在客户端运行时,主要用hydrateapi将html标记与js代码从新结合,以后就与服务端彻底不要紧了,能够当spa的状况处理
基于这个流程,简单实现一个demo
服务端
客户端
主要代码实现:
// render页面 async function render(Element) { // 获取组件初始props,能够在该方法内获取数据 const props = await Element.getInitProps() const html = renderToString(<Element {...props} />) const __SSR_DATA__ = { props } return { html, __SSR_DATA__ } } router.get('/demo', async ctx => { // 将生成的标记和属性都转为文本传给客户端 const { html, __SSR_DATA__ } = await render(Demo) ctx.body = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>ssr</title> </head> <body> <script> window.__SSR_DATA__ = ${JSON.stringify(__SSR_DATA__)} </script> <div id="root">${html}</div> <script src="http://localhost:9090/index.js"></script> </body> </html>` })
import { hydrate } from 'react-dom'; import Demo from './demo'; // 服务端将props数据挂载到window上,客户端从新渲染时直接传入该属性 const { props } = window.__SSR_DATA__ // hydrate会根据html中已有的标记进行对比,决定是否要从新渲染dom hydrate( <Demo {...props} />, document.getElementById('root'), );
目前react ssr主要是用nextjs
nextjs实现原理与上面一致,增长了路由,缓存,打包,错误处理,页面加载等一系列功能
生产中,除非很简单,或者只为了首屏,不考虑同构,能够本身实现,正常状况,直接使用nextjs便可
后续会记录一下next源码分析
待续...