不是服务器端渲染,但仍想提升 React 网站的性能?尝试预渲染!
react-snap
是一个第三方库,可将您网站上的网页预呈现为静态 HTML 文件。这可以缩短应用中的首次绘制时间。
以下是在模拟的 3G 连接和移动设备上加载预渲染和未加载预渲染的同一应用的对比情况:
为什么搜索渠道报告非常实用?
大型单页应用的主要性能问题是,用户需要等待构成网站的 JavaScript 软件包完成下载,然后才能看到任何实际内容。软件包越大,用户需要等待的时间就越长。
为了解决此问题,许多开发者会采用在服务器上渲染应用的方法,而不是只在浏览器中启动应用。在每次页面/路由转换时,都会在服务器上生成完整的 HTML 并将其发送到浏览器,这可以缩短首次绘制时间,但会导致首字节时间变慢。
预渲染是一项单独的技术,其复杂程度不如服务器渲染,但也提供了一种缩短应用中的首次绘制时间的方法。无头浏览器或没有界面的浏览器用于在构建时为每个路由生成静态 HTML 文件。然后,这些文件可与应用所需的 JavaScript 软件包一起提供。
回应-Snap
react-snap
会使用 Puppeteer 在应用中创建不同路线的预渲染 HTML 文件。首先,将其作为开发依赖项安装:
npm install --save-dev react-snap
然后,在 package.json
中添加 postbuild
脚本:
"scripts": {
//...
"postbuild": "react-snap"
}
这样,每次有新版本的应用构建 (npm build
) 时,系统都会自动运行 react-snap
命令。
您需要做的最后一项操作是更改应用的启动方式。将 src/index.js
文件更改为以下内容:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
const rootElement = document.getElementById("root");
if (rootElement.hasChildNodes()) {
ReactDOM.hydrate(<App />, rootElement);
} else {
ReactDOM.render(<App />, rootElement);
}
该操作会检查是否已存在任何子节点,从而确定 HTML 内容是否已预呈现(或在服务器上呈现),而不是仅使用 ReactDOM.render
将根 React 元素直接呈现到 DOM 中。在这种情况下,系统会使用 ReactDOM.hydrate
将事件监听器附加到已创建的 HTML 中,而不是创建新的 HTML。
现在,构建应用时,系统会为抓取的每个路由生成静态 HTML 文件作为载荷。您可以查看 HTML 载荷,只需点击 HTML 请求的网址,然后点击 Chrome 开发者工具中的预览标签页即可。
闪烁未设置样式的内容
虽然静态 HTML 现在几乎可以立即呈现,但默认情况下它仍然没有样式,这可能会导致显示“内容未样式设置”(FOUC) 的问题。如果您使用 CSS-in-JS 库生成选择器,这种情况会特别明显,因为只有在 JavaScript 软件包执行完毕后,才能应用任何样式。
为了防止出现这种情况,您可以将关键 CSS(即呈现初始网页所需的最少 CSS 数量)直接内嵌到 HTML 文档的 <head>
中。react-snap
会在后台使用另一个第三方库 minimalcss
来提取不同路由的任何关键 CSS。您可以通过在 package.json
文件中指定以下内容来启用此功能:
"reactSnap": {
"inlineCss": true
}
在 Chrome 开发者工具中查看响应预览,现在将显示已内嵌关键 CSS 的已设置样式的页面。
总结
如果您的应用不是服务器端呈现路由,请使用 react-snap
向用户预呈现静态 HTML。
- 将其作为开发依赖项安装,并在开始时仅使用默认设置。
- 如果适用于您的网站,请使用实验性
inlineCss
选项内嵌关键 CSS。 - 如果您在任何路由的组件级别上使用代码拆分,请注意不要向用户预渲染加载状态。
react-snap
自述文件对此进行了更详细的介绍。