服务端渲染 SSR
icejs 支持服务端渲染(即 SSR)能力,开发者可以按需一键开启 SSR 的模式,相比于传统的客户端渲染,SSR 常用于两个场景:1. 有 SEO 诉求;2. 对首屏渲染速度要求比较高。相比于传统的 SSR 方案,icejs 提供的 SSR 能力具有以下特性:
- 支持一键开启/关闭 SSR 能力
- 与服务端低耦合,无论是传统的 Nodejs 应用还是 Serverless 模式,都可以非常简单的集成
- 支持页面级服务端加载数据
#
开启 SSR在工程配置文件 build.json
中开启 SSR:
配置完之后即可启用 SSR,同理置为 false 即可关闭 SSR 功能。此时重新执行 npm run start
即可看到页面中直出的 HTML:
#
应用级数据#
获取应用初始化数据在 src/app.ts
中可通过 app.getInitialData()
获取全局数据:
开启了 SSR 的行为说明:
- 服务端渲染时直接调用
app.getInitialData()
获取数据并渲染应用,同时将数据注入到全局变量中 - 浏览器端渲染时不再调用
app.getInitialData()
,会直接通过全局变量获取初始数据 - 可以获取到当前请求的上下文
ctx
参数,包含以下字段ctx.req
:HTTP request 对象 (仅在 server 端输出)ctx.res
:HTTP response 对象 (仅在 server 端输出)ctx.pathname
:当前路由路径ctx.query
:请求参数对象ctx.path
:URL 路径(包括请求参数)ctx.ssrError
:服务端渲染时错误信息(仅在 client 端输出)
未开启 SSR 的行为说明:
- 浏览器端会同步调用
getInitialData
- 调用完成后执行页面 render 逻辑
#
消费应用初始化数据框架提供了两种方式获取 app.getInitialData()
返回的数据:
getInitialData()
消费#
通过 #
作为 store 的初始化状态app.getInitialData()
返回的 initialStates
字段会作为 store 的初始状态,比如 models/user.js
的默认 states 即上述的 { name: 'Jack', id: '01' }
,可以直接在 View 中使用:
#
页面级数据SEO 场景下,需要访问每个页面时都能够返回实际的 DOM 节点,此时如果把数据放到全局的 initialData
里管理成本会非常高,因此 icejs 支持页面级通过 getInitialProps
来获取自身需要的数据。
注意:如果只是追求首屏加载速度,不推荐使用页面级的 getInitialProps,因为这在一定程度上会延长服务端渲染直出 HTML 的时间。
在页面级组件中通过 Component.getInitialProps
来获取页面初始数据,同时可以获取到当前请求的上下文 ctx
参数,包含以下字段:
ctx.req
:HTTP request 对象 (仅在 server 端输出)ctx.res
:HTTP response 对象 (仅在 server 端输出)ctx.pathname
:当前路由路径ctx.query
:请求参数对象ctx.path
:URL 路径(包括请求参数)ctx.ssrError
:服务端渲染时错误信息(仅在 client 端输出)
开启了 SSR 的行为说明:
- 服务端渲染时调用对应页面的
getInitialProps
,然后在渲染页面组件时将数据作为 props 传递给页面组件,同时将数据注入到全局变量上 - 浏览器端渲染时不再调用
getInitialProps
,会直接通过全局变量获取初始数据并作为组件的 props
未开启 SSR 的行为说明:
- 浏览器端渲染时会在组件渲染(render)后调用该方法
- 调用完成后触发组件的 rerender
注意:页面组件渲染使用 props 时需要兼容 getInitialProps
未调用的情况
#
构建产物当应用开发完成时,通过运行 npm run build
默认构建后的文件如下:
icejs 1.15.0 开始支持在开启 SSR 的应用中使用代码分割,部署时需要把
server/
目录下所有的 bundle 资源下载到 server 端。
#
页面 Meta 标签在 SEO 场景下,往往需要动态设置每个页面的标题和 Meta 标签,以更好地让搜索引擎抓取页面内容。使用步骤如下:
#
服务端集成本地开发时 icejs 通过 webpack-dev-server 做服务端渲染,应用发布后则需要对应的服务端自行渲染,核心逻辑如下:
icejs 构建出来的 server/index.js
会暴露出 render
方法供服务端调用,该方法提供以下参数:
- ctx: 必填,当前请求上下文
- options:
- loadableStatsPath: 必填,loadable-stats.json 本地路径
- htmlTemplate: 选填,html 模板内容
- initialData: 选填,如果不填写,服务端则会调用前端声明的
app.getInitialData()
方法,但如果对性能追求比较极致,服务端则可以自行获取对应数据并通过initialData
传入。(调用前端的 getInitialData 一般会发起 HTTP 请求,但是服务端有可能通过缓存/数据库来查询,速度会快一点)
#
其他问题#
服务端请求必须使用绝对的 URL 路径开启了 SSR 之后,app.getInitialData
以及 Home.getInitialProps
都会在服务端下执行,服务端发请求必须用绝对路径不能用相对路径,因此这两个方法里如果出现异步请求,请务必使用绝对路径,或者正确设置 request.baseURL
。推荐做法:
src/config.js
中动态区分环境并配置 baseURL:
然后在 src/app.js
中设置 request.baseURL
: