当前位置:首页 > 技术 > 正文内容

React 服务端渲染核心原理与实践

访客 技术 2026年8月15日 1

客户端渲染与服务端渲染对比

客户端渲染(CSR)流程:

  • 服务器返回空白HTML文档
  • 浏览器下载JavaScript资源
  • 浏览器执行React应用逻辑
  • 最终完成页面渲染

服务端渲染(SSR)流程:

  • 服务器直接生成完整的HTML文档
  • 浏览器接收并显示预渲染内容

关键优势分析:

  • SSR提供更快的首屏加载体验,用户无需等待JavaScript下载执行
  • 搜索引擎能够直接解析HTML内容,提升SEO效果

服务端Webpack环境搭建

首先在项目根目录创建服务端入口文件 server/entry.js

const express = require('express');
const app = express();

app.get('/', (request, response) => {
  response.send(`
    <html>
      <head>
        <title>React Server-Side Rendering</title>
      </head>
      <body>
        <div id="app"><h1>React SSR Implementation</h1></div>
      </body>
    </html>
  `);
});

const serverInstance = app.listen(8080);

更新 package.json 启动脚本:

"scripts": {
  "start": "node ./server/entry.js"
}

执行 npm run start 即可在8080端口访问应用。

为服务端代码集成Webpack构建,首先安装必要依赖:

npm install webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-stage-0 webpack-node-externals

创建 webpack.server.config.js 配置:

const path = require('path');
const nodeModulesExternal = require('webpack-node-externals');

module.exports = {
  target: 'node',
  mode: 'development',
  entry: './server/entry.js',
  output: {
    filename: 'server-bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  externals: [nodeModulesExternal()],
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/,
        options: {
          presets: [
            '@babel/react',
            '@babel/stage-0',
            ['@babel/env', {
              targets: {
                browsers: ['last 2 versions']
              }
            }]
          ]
        }
      }
    ]
  }
};

修改启动脚本指向构建后的文件:

"start": "node ./dist/server-bundle.js",
"build-server": "webpack --config webpack.server.config.js"

组件服务端渲染实现

创建示例组件 components/main.jsx

import React from 'react';

const MainComponent = () => (
  <div className="main-content">
    <h2>Welcome to SSR</h2>
    <p>This content was rendered on server side.</p>
  </div>
);

export default MainComponent;

更新服务端入口文件,集成React组件渲染:

const express = require('express');
import React from 'react';
import { renderToString } from 'react-dom/server';
import MainContent from './components/main';

const app = express();

app.get('/', (req, res) => {
  const componentHtml = renderToString(<MainContent />);
  
  res.send(`
    <html>
      <head>
        <title>SSR Application</title>
      </head>
      <body>
        <div id="root">${componentHtml}</div>
      </body>
    </html>
  `);
});

const serverInstance = app.listen(8080);

执行构建命令后,访问页面将看到服务端渲染的组件内容,查看页面源码可验证组件已预渲染。

同构应用开发

由于服务端渲染不包含事件绑定,需要在客户端重新激活交互功能。创建客户端入口 client/app.js

import React from 'react';
import { hydrate } from 'react-dom';
import MainContent from '../components/main';

hydrate(<MainContent />, document.getElementById('root'));

配置静态资源中间件:

app.use(express.static('public'));

创建客户端Webpack配置 webpack.client.config.js

const path = require('path');

module.exports = {
  mode: 'development',
  entry: './client/app.js',
  output: {
    filename: 'client-app.js',
    path: path.resolve(__dirname, 'public')
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: 'babel-loader',
        exclude: /node_modules/,
        options: {
          presets: [
            '@babel/react',
            '@babel/stage-0',
            ['@babel/env', {
              targets: {
                browsers: ['last 2 versions']
              }
            }]
          ]
        }
      }
    ]
  }
};

在HTML模板中引入客户端脚本:

<script src="/client-app.js"></script>

使用 hydrate 方法而非 render 可避免重复渲染警告,实现服务端内容的客户端激活。

构建配置优化

采用配置合并策略优化构建流程,安装 webpack-merge

创建基础配置 webpack.common.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: 'babel-loader',
        exclude: /node_modules/,
        options: {
          presets: [
            '@babel/react',
            '@babel/stage-0',
            ['@babel/env', {
              targets: {
                browsers: ['last 2 versions']
              }
            }]
          ]
        }
      }
    ]
  }
};

客户端配置继承基础配置:

const path = require('path');
const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.common.config');

const clientSpecific = {
  mode: 'development',
  entry: './client/app.js',
  output: {
    filename: 'client-bundle.js',
    path: path.resolve(__dirname, 'public')
  }
};

module.exports = merge(baseConfig, clientSpecific);

服务端配置同样继承:

const path = require('path');
const nodeModulesExternal = require('webpack-node-externals');
const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.common.config');

const serverSpecific = {
  target: 'node',
  mode: 'development',
  entry: './server/entry.js',
  output: {
    filename: 'server-bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  externals: [nodeModulesExternal()]
};

module.exports = merge(baseConfig, serverSpecific);

完整SSR流程总结:服务端执行React渲染生成HTML → 发送至浏览器 → 浏览器展示预渲染内容 → 加载客户端JavaScript → 客户端React接管并激活交互功能。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。