React SSR,如何使用脱水函数renderToPipeableStream()?
发布于 作者:苏南大叔 来源:程序如此灵动~

接触到renderToString()
这个函数后,就可以理解到react
脱水的过程了。这里就引申到了一个用户体验的问题,用户浏览器总是期待服务器端有着最快的响应速度,除去硬件等因素外,react
官方推出了renderToPipeableStream()
这个函数,可以说是对renderToString()
的改进和优化。

苏南大叔的“程序如此灵动”,记录苏南大叔的编程心得体会。本文测试环境:nodejs@20.18.0,create-react-app@5.0.1,react-router-dom@6.27.0,react@18.3.1。本文主要讨论react
的脱水函数renderToPipeableStream()
的使用问题。
前文回顾
本文的代码改编自上一篇文章中的第三个有关express
的例子,参考:
renderToPipeableStream()
的使用基本原理就是:配合http
或者express
的pipe
使用,管道渐进式输出html
代码。
函数原型
下面的链接是react
的官方描述:
函数原型:
这里的options
是用于配置流的对象的。下面的其属性表格,整理自react
官方文档。
可选参数 | 参数文字解释 |
---|---|
bootstrapScriptContent | 指定一个字符串,这个字符串将被放入<script> 标签中作为其内容。 |
bootstrapScripts | 一个 URL 字符串数组,它们将被转化为 <script> 标签嵌入页面。 |
bootstrapModules | 和 bootstrapScripts 相似,但是嵌入页面的是 <script type="module"> 。 |
identifierPrefix | 一个字符串前缀,用于由 useId 生成的 id 。在同一页面下的多人协作场景中会很有用。 |
namespaceURI | 一个字符串,指定与流相关联的 命名空间 URI 。默认是常规的 HTML 。 |
nonce | 一个字符串,能为脚本设置跨域限制,即 script-src 浏览器内容安全策略。 |
onShellReady | 一个回调函数,在 shell 初始化渲染后立即调用,渐进式流数据发送。 |
onAllReady | 一个回调函数,将会在所有渲染完成时触发,包括 shell 和所有额外的 content 。 |
onError | 一个回调函数,只要是出现了异常错误,无论这是 可恢复的 还是 不可恢复的,它都会触发。 |
onShellError | 一个回调函数,在初始化 shell 发生错误渲染时调用。 |
progressiveChunkSize | 一个块中的字节数。 |
苏南大叔看完官方说明后,就关注三个参数:
onShellReady
,每次渲染结束时机。【似乎非常切合这个函数的人社啊】onAllReady
,所有的渲染全部结束时机。【和这个函数的人设,是不是有冲突?】bootstrapScripts
,这个用于输出底部的那个特殊js
,可用也可以不用。
官方文档的内容很多,谈到了大量的特殊情况,很不符合本文的新手入门文档调性。所以,本文中,苏南大叔并不打算做更多深入描述。
发送的时机
react
脱水函数renderToPipeableStream()
,有两个回调函数时机(onShellReady
和onAllReady
)可以使用。经过代码实验,都可以用于发送(pipe(res)
)渲染结果。
官方说:pipe
将一段HTML
输出到Node.js
可写流中。如果你想启用流式传输,那么可以在onShellReady
中调用pipe
;如果要做爬虫和静态内容生成的话,那么可以在onAllReady
中调用它。
苏南大叔认为:大多数情况下,都应该在onShellReady()
中执行pipe(res)
。在onAllReady()
中执行pipe(res)
的话,就失去了这个函数的灵魂所在。所以,推荐的使用方式是:
js文件的位置
由于官方提供了一个选项(bootstrapScripts
/bootstrapModules
),来输出一个js
文件地址。实际上就相当于react
项目尾部的那个js
文件的输出。
实际使用的话,就会发现:
传统思路下,先输出html
的<div id='app'>
及之前,然后靠renderToPipeableStream()+bootstrapScripts
来输出渲染结果代码的话,这个js
的输出位置就会出现在<div id='app'>
的闭合代码之前,也就是说出现在div#app
内部,这显然是不合理的。
期待值是:
官方给出的思路是:
将模版代码,放在app
这个react
组件里面,然后整体作为<app/>
进行渲染,最后的js
代码就会出现在页面的</html>
标签之后。虽然说规避了上面所说的问题,但是,并不符合苏南大叔对js
加载位置的认知。【期待react
官方的后续改进】
测试代码主体
测试代码的主体框架,是下面这样的。
执行方式是:
测试代码一【个人推荐】
res
先发送html
的开头部分代码,然后渲染react
的代码。然后在onShellReady()
里面管道输出渲染结果,最后发送html
的底部部分。
其实这里就主体部分是管道输出的。

测试代码二【官方推荐】
要把模版写成jsx
的形式,其实还是比较艰巨的。个人不是很喜欢,但是官方推荐。只能尽量规避哪些令人头晕的写法。参考文章:

测试代码三【也许不错】
意料外的是:这个renderToPipeableStream()
的渲染输出,会自带tidy
效果。

这个方案里面,就是投个机取个巧,治标不治本。不过,对于很框架型的react
代码项目来说,可能是个不错的解决方案。
结束语
苏南大叔其实挺想不写这个结束语部分的,但是偶尔发现有个新的站点,又又又把我的全部内容给巴拉走了。不过,保留了基本人设,和文章里面的链接。所以,还是加个链接吧。万一被留下来了呢?
欢迎查看苏南大叔的react
相关经验文章:


