什么是同构
一份代码,先通过服务端渲染(server-side rendering,ssr),生成html字符串以及初始化数据,客户端拿到后,通过对html的dom进行patch和事件绑定对dom进行客户端激活(client-side hydration,csh),这个整体的过程叫同构渲染。
同构产生的背景 / 同构能够解决单纯客户端渲染的哪些痛点?
1.客户端渲染带来的的首屏白屏时间过长:
在 SPA 模式下,所有的数据请求和 Dom 渲染都在浏览器端完成,所以当我们第一次访问页面的时候很可能会存在“白屏”等待,而服务端渲染所有数据请求和 html内容已在服务端处理完成,浏览器收到的是完整的 html 内容,可以更快的看到渲染内容。
2. 客户端渲染不利于SEO:
由于现阶段大多搜索引擎采用的爬虫算法是直接抓取页面代码分析,而SPA应用只有一个入口文件而没实质内容,SEO性能差。
适用的场景?
1.特别依赖搜索引擎流量的项目;
2.对首屏时间有特殊要求;
现有的的开源框架?
next.js、react server、Beidou(北斗) 、
核心原理及架构流程图?
借助虚拟DOM的特性,将一份代码在服务端和客户端各执行一次:
1、服务端使用 react-dom包提供的 server端渲染api: renderToString (常用)或 renderToStaticMarkup直接渲染出包含页面信息的静态 html字符串。
2、客户端根据渲染出的静态 html 进行二次渲染,做一些绑定事件等交互操作。
同构的缺点?
1.同构会增加服务器的负载,对此一般推荐对于首屏和个别页面进行SSR服务端的渲染,此外仍保持应用为客户端SPA,充分利用浏览器特点,达到最优性能。
2.使原本简单的 React 项目变得非常复杂,项目的可维护性会降低,代码问题的追溯也会变得困难。所以,使用 SSR 在解决问题的同时,也会带来非常多的副作用,有的时候,这些副作用的伤害比起 SSR 技术带来的优势要大的多。
关键点?
1.双端框架选择:
客户端:react(v16+)
服务器端:koa/express
2.环境区分
同一套代码在客户端和服务端执行两次,但因为环境不同,有些对象是不自带的,要加以区分避免出现问题。像前端特有的 Window 对象,Ajax 请求 在后端是无法使用上的,后端需要去掉这些前端特有的对象 逻辑或使用对应的后端方案,如后端可以使用 http.request 替代 Ajax 请求,所以需要进行平台区分,主要有以下几种方式:
1. 代码使用前后端通用的模块,如 isomorphic-fetch
2. 前后端通过 webpack 配置 resolve.alias 对应不同的文件
3. 使用 webpack.DefinePlugin 在构建时添加一个平台区分的值
3.react服务端提供的渲染API
React 之所以可以做到服务端渲染 就是因为react-dom/server提供了服务端渲染的API。
renderToString 同步地把一个react 元素转换成带html字符串,遇到复杂页面时用户等待时间也不短。
renderToNodeStream把渲染结果以‘流’的形式返回给浏览器端,用户体验更友好。
后续为了客户端在渲染组件时,最大限度地保留在服务端使用 renderToString 生成的内容结构,ReactDom 相应的在客户端提供了一个新的 API:hydrate。
4.路由同构
首先需要抽离出一份路由组件文件routes.js:
客户端使用 react-router-dom 下的 BrowserRouter 进行前端路由控制。
服务端使用 react-router-dom 下的 StaticRouter 进行静态路由控制。
使用 react-router-config 下的 matchRoutes 匹配后端路由,使用 renderRoutes 渲染匹配到的路由。
使用 react-router-dom/server 下的 renderToString 方法,渲染出 html 字符串,并返回给前端。
使用 StaticRouter 中通过 context 可以和前端页面通信,传参。
数据交互与状态同步?
可以选用redux实现数据状态的同步:在服务端通过组件的静态API方法获取接口数据后创建store,再通过 window.store= store 传递给前端;此时应用中的所有页面都可以共享使用store中的数据,可以使用dispatch方法进行交互。
双端打包差异?
客户端打包:
服务端打包: