vite-react-ts
2023年12月21日
一、前置知识
1.1 构建产物
首先 Vite
作为一个构建工具,是如何支持 SSR
构建的呢?换句话说,它是如何让前端的代码也能顺利在 Node.js
中成功跑起来的呢?
可以分为两种情况:
-
开发环境下:
Vite
依然秉承ESM
模块按需加载即no-bundle
的理念,对外提供了ssrLoadModule API
,你可以无需打包项目,将入口文件的路径传入ssrLoadModule
即可// 加载服务端入口模块
const xxx = await vite.ssrLoadModule('/src/entry-server.tsx') -
生产环境:
Vite
会默认进行打包,对于SSR
构建输出CommonJS
格式的产物。我们可以在package.json
中加入这样类似的构建指令:{
"build:ssr": "vite build --ssr 服务端入口路径"
}这样
Vite
会专门为SSR
打包出一份构建产物。因此你可以看到,大部分SSR
构建时的事情,Vite
已经帮我们提供了开箱即用的方案,我们后续直接使用即可。
1.2 加载入口
Sever
层 的第一步是 加载服务端入口模块, 主要逻辑如下:
export async function loadSsrEntryModule(
vite: ViteDevServer | null,
isProd,
root
) {
if (isProd) {
// 生产模式下直接 import 打包后的产物
const entryPath = path.join(root, 'dist/server/entry-server.js');
return await import(entryPath);
} else {
// 开发环境下通过 no-bundle 方式加载
const entryPath = path.join(root, 'src/entry-server.tsx');
return vite!.ssrLoadModule(entryPath);
}
}
1.3 组件渲染为字符串(脱水)
调用前端框架的 renderToStringAPI
将组件渲染为字符串
const appHtml = renderToString(
React.createElement(ServerEntry, { data })
);
1.4 服务端向客户端注入数据
在拼接 HTML
的逻辑中,除了添加页面的具体内容,同时我们也注入了一个挂载全局数据的 script
标签。为了激活页面的交互功能,我们需要执行 CSR
的 JavaScript
代码来进行 hydrate
操作,而客户端 hydrate
的时候需要和服务端同步预取后的数据,保证页面渲染的结果和服务端渲染一致,因此,我们刚刚注入的数据 script
标签便派上用场了。由于全局的 window
上挂载服务端预取的数据