使用Node搭建reactSSR服务端渲染架构

使用Node搭建reactSSR服务端渲染架构是一个相对复杂的过程,需要以下步骤:

1. 创建基础项目

我们可以使用脚手架工具create-react-app创建一个基础的React项目。

npx create-react-app my-app --template typescript

之后需要安装一些依赖包,包括react、react-dom、react-router-dom以及其他一些常用的包。并且需要安装一些开发依赖包,如babel-plugin-import、@types/react等。

2. 配置服务端渲染环境

我们需要在项目根目录下创建一个server.js文件,并且在其中进行服务器的配置。在配置中需要引用react、react-dom、express等核心模块,同时还需要使用babel进行代码编译等。

import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './App'; // 项目根组件

const app = express();

// 配置路由,注意路由的“*”表示匹配所有路由
app.get('*', (req, res) => {
  const appString = ReactDOMServer.renderToString(<App />);
  res.send(`<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>React SSR example</title>
</head>
<body>
  <div id="root">${appString}</div>
  <script src="/static/js/bundle.js"></script>
</body>
</html>
`);
});

app.listen(3000, () => {
  console.log('Server is listening on port 3000');
});

需要注意的是,在用ReactDOMServer将React组件渲染成HTML字符串时,需要在服务器端进行组件的渲染。因此需要使用ReactDOMServer的renderToString函数,渲染完成后将渲染出的内容以字符串形式返回给客户端进行处理。

3. 配置Webpack打包

在服务端渲染架构中,我们需要将所有客户端代码打包成一个单独的文件,以供服务端渲染时使用。这个打包过程可以通过Webpack进行。

我们需要修改package.json文件中的启动脚本,以便在打包文件时可以一并打包服务端渲染代码:

"scripts": {
  "start": "npm run build && node server.js",
  "build": "react-scripts build && node build-server.js"
},

在根目录下创建一个build-server.js文件,并在其中进行Webpack打包的相关配置。

const path = require('path');
const webpack = require('webpack');

const webpackClientConfig = require('./node_modules/react-scripts/config/webpack.config.js')('development');
const webpackServerConfig = {
  ...webpackClientConfig,
  entry: {
    server: path.resolve(__dirname, './server.js')
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, './build')
  },
  target: 'node'
};

webpack([webpackClientConfig, webpackServerConfig]).run((err, stats) => {
  if (err) {
    console.error(err);
  } else {
    const info = stats.toJson();
    if (stats.hasErrors()) {
      console.error(info.errors);
      process.exit(1);
    } else {
      console.log(info);
    }
  }
});

在此文件中,我们首先获取了默认的Webpack配置(webpackClientConfig),并在此基础上针对服务端渲染进行了修改,包括:

  • 修改entry为server.js文件路径;
  • 修改output为输出到build文件夹下,文件名为[name].js,即使用entry的名字作为输出文件名;
  • 修改target为node,以保证打包后的JS文件可以在Node.js环境下执行。

4. 开始使用服务端渲染

完成以上的配置后,我们就可以使用服务端渲染来处理React组件的渲染了。

首先,在页面中引用我们打包生成的client.js文件:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>React SSR example</title>
</head>
<body>
  <div id="root"></div>
  <script src="/static/js/bundle.js"></script>
  <script src="/static/js/client.js"></script>
</body>
</html>

在client.js中,我们需要判断当前环境是否支持服务端渲染,如果支持,就使用ReactDOM.hydrate进行渲染,否则就使用ReactDOM.render进行客户端渲染。

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App'; // 项目根组件

const rootElement = document.getElementById('root');

if (rootElement.hasChildNodes()) {
  ReactDOM.hydrate(<App />, rootElement);
} else {
  ReactDOM.render(<App />, rootElement);
}

示例

示例一:使用服务器数据渲染组件

我们可以使用fetch等方式从服务器获取数据,并将数据传入React组件中进行渲染。

import React from 'react';

interface UserInfo {
  id: number;
  name: string;
  age: number;
}

interface Props {
  userId: number;
}

interface State {
  user: UserInfo | null;
  loading: boolean;
}

export default class User extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);

    this.state = {
      user: null,
      loading: true
    };
  }

  componentDidMount() {
    const id = this.props.userId;
    fetch(`/api/user?id=${id}`)
      .then(response => response.json())
      .then(data => {
        this.setState({ user: data, loading: false });
      });
  }

  render() {
    if (this.state.loading) {
      return (
        <div>Loading...</div>
      );
    } else {
      return (
        <div>
          User Info:
          <ul>
            <li>ID: {this.state.user?.id}</li>
            <li>Name: {this.state.user?.name}</li>
            <li>Age: {this.state.user?.age}</li>
          </ul>
        </div>
      );
    }
  }
}

在服务端,我们需要使用axios等方式获取数据,并把数据渲染到HTML字符串中。

import axios from 'axios';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import User from './User'; // 我们刚才创建的User组件

const app = express();

app.get('/user/:id', async (req, res) => {
  const response = await axios.get(`/api/user?id=${req.params.id}`);
  const user = response.data;
  const appString = ReactDOMServer.renderToString(<User userId={user.id} />);

  res.send(`<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>React SSR example</title>
</head>
<body>
  ${appString}
</body>
</html>
`);
});

在以上代码中,我们首先使用axios进行数据请求,获取到用户信息后,将其传入User组件中,并用ReactDOMServer.renderToString将组件渲染成HTML字符串。最后将HTML字符串返回给客户端。

示例二:使用react-router进行页面路由

使用react-router进行页面路由非常方便,但在服务端渲染中需要进行特殊处理,以保证客户端在进行路由切换时可以正确地进行服务端渲染。

import React from 'react';
import { Route, Switch } from 'react-router-dom';

import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';

export default class App extends React.Component {
  render() {
    return (
      <Switch>
        <Route exact path="/" component={Home} />
        <Route exact path="/about" component={About} />
        <Route exact path="/contact" component={Contact} />
      </Switch>
    );
  }
}

对于上述代码,我们需要在服务端根据浏览器请求的URL来选择渲染哪个组件。同时还需要根据客户端路由的路径,来正确地选择渲染哪个页面,以保证服务端渲染和客户端渲染时输出的DOM树相同。

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';

import App from './App'; // 我们刚才创建的根组件

app.get('*', (req, res) => {
  const context = {};

  const appString = ReactDOMServer.renderToString(
    <StaticRouter location={req.url} context={context}>
      <App />
    </StaticRouter>
  );

  if (context.url) {
    res.redirect(301, context.url);
  } else {
    res.send(`<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>React SSR example</title>
</head>
<body>
  <div id="root">${appString}</div>
  <script src="/static/js/bundle.js"></script>
  <script src="/static/js/client.js"></script>
</body>
</html>
`);
  }
});

在上述代码中,我们使用了StaticRouter组件来渲染路由,其中的location和context参数分别表示当前浏览器请求的URL、和服务端渲染上下文对象。其中上下文对象主要用于重定向或修改HTTP响应码等操作。

最后,如果context.url存在,则表示需要重定向到另一个URL,可通过res.redirect函数实现。否则,如果context.url不存在,则表示当前路径可以正常渲染,使用ReactDOMServer.renderToString将根组件渲染成HTML字符串后返回给客户端。

以上就是Node搭建reactSSR服务端渲染架构的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:使用Node搭建reactSSR服务端渲染架构 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • Js中使用正则表达式验证输入是否有特殊字符

    Sure!以下是使用正则表达式验证输入是否有特殊字符的攻略: 步骤一:定义正则表达式 首先,定义一个RegExp对象来表示我们所需要的正则表达式。例如,我们希望限制输入只包含数字和字母,那么可以定义如下正则表达式: var reg = /^[a-zA-Z0-9]+$/; 在上述正则表达式中: /…/ 表示正则表达式的开始和结尾; ^ 表示匹配输入的开始位…

    node js 2023年6月8日
    00
  • node.js中的path.normalize方法使用说明

    下面是详细讲解“node.js中的path.normalize方法使用说明”的完整攻略。 什么是path.normalize方法 在node.js中,path模块提供了一系列与路径相关的方法,其中之一就是normalize方法。normalize方法的作用是规范化一个路径,消除路径中的冗余部分并将其转换为标准格式。这在处理路径时非常有用,尤其是在跨平台开发时…

    node js 2023年6月8日
    00
  • Node.js 8 中的 util.promisify的详解

    让我来详细讲解“Node.js 8 中的 util.promisify的详解”。 1. 什么是util.promisify? 在 Node.js 8 版本中,引入了一个新的模块 util.promisify,它是一个实用工具,用于将一个返回值为 callback 的函数转换为 Promise 风格。使用 util.promisify,可以更轻松地将现有的回调…

    node js 2023年6月8日
    00
  • JavaScript数据结构之二叉树的删除算法示例

    下面我来详细讲解一下“JavaScript数据结构之二叉树的删除算法示例”的完整攻略。 什么是二叉树? 二叉树是一种特殊的树形结构,每个节点最多只能有两个子节点,分别称为左子节点和右子节点。二叉树是一种常用的数据结构,在计算机科学中有着广泛的应用。 二叉树的删除算法 二叉树的删除算法是指在二叉树中删除一个节点的过程。删除节点通常需要考虑以下几种情况: 要删除…

    node js 2023年6月8日
    00
  • 浅谈NodeJs之数据库异常处理

    浅谈NodeJs之数据库异常处理 在NodeJs开发过程中,经常需要对数据库进行增、删、改、查操作。在操作过程中,难免会遇到各种异常情况,如重复插入、删除不存在的数据、修改不存在的数据等,这时我们需要对这些异常做出相应的处理,以保证数据的完整性和程序的稳定性。 异常处理的基本思路 数据库操作是异步的,不能简单地使用try-catch来捕获异常。在NodeJs…

    node js 2023年6月8日
    00
  • 解决Node.js mysql客户端不支持认证协议引发的问题

    问题描述 在使用 Node.js MySQL 客户端时,可能会遇到以下错误: Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client 这个错误发…

    node js 2023年6月8日
    00
  • node.js 基于 STMP 协议和 EWS 协议发送邮件

    Node.js 是一种基于事件驱动和非阻塞 I/O 模型的 JavaScript 运行时环境,广泛应用于服务器端应用程序的开发。基于 STMP 协议和 EWS 协议的邮件发送是 Node.js 程序中一项常见的任务。下面是一份完整的攻略,包含邮件发送的各个步骤和两个示例说明。 准备工作 在进行邮件发送前,需要安装以下 npm 模块: nodemailer:用…

    node js 2023年6月8日
    00
  • Node的事件处理和readline模块详解

    Node.js 是一个基于事件驱动、非阻塞 I/O 的 JavaScript 运行时环境。事件处理是 Node.js 的核心机制之一。本文将详细讲解 Node.js 事件处理机制以及 readline 模块,希望能够为大家提供一定的参考。 Node.js 事件处理机制 Node.js 的事件处理机制建立在 EventEmitter 类之上,提供了一种处理事件…

    node js 2023年6月8日
    00
合作推广
合作推广
分享本页
返回顶部