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

yizhihongxing

使用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日

相关文章

  • NodeJs操作MYSQL方法详细介绍

    NodeJs操作MYSQL方法详细介绍 在 Node.js 中,可以通过第三方模块 mysql 来连接 MySQL 数据库。通过该模块,我们可以在 Node.js 中对 MySQL 数据库进行管理、操作。 安装 安装 mysql 模块: npm install mysql 连接 连接 MySQL 数据库: const mysql = require(‘mys…

    node js 2023年6月8日
    00
  • JS事件循环-微任务-宏任务(原理讲解+面试题分析)

    JS事件循环-微任务-宏任务 在JS中,事件循环是一种非常重要的机制。通过事件循环,我们可以更好地实现代码的异步执行。了解JS事件循环的机制,也是在前端开发中非常必要的一项知识。 事件循环机制 事件循环机制是指JS引擎处理JS代码的一种机制。简单来说,JS引擎在执行JS代码时,会按照特定的顺序去处理事件,而这个顺序就是事件循环。与此同时,JS引擎还会把这些事…

    node js 2023年6月8日
    00
  • typescript环境安装并开启VSCode自动监视编译ts文件为js文件

    下面是详细的 TypeScript 环境安装并开启 VSCode 自动监视编译ts文件为js文件的攻略。 步骤 1. 安装 TypeScript 首先需要安装 TypeScript,可以通过命令行执行以下命令进行全局安装: npm install -g typescript 2. 创建 TypeScript 文件 创建一个名为 main.ts 的文件,内容如…

    node js 2023年6月9日
    00
  • nodejs 中模拟实现 emmiter 自定义事件

    下面是详细讲解 “nodejs 中模拟实现 emitter 自定义事件” 的完整攻略。 1. 什么是 emitter 自定义事件 在 nodejs 中,EventEmitter 是一个非常重要的模块。其作用是提供了处理事件的基本机制,可以用于实现自定义事件。 实际上,EventEmitter 可以理解为用于注册和监听事件的中介。我们可以通过它来注册自定义事件…

    node js 2023年6月8日
    00
  • 开发Node CLI构建微信小程序脚手架的示例

    下面是完整的攻略: 开发Node CLI构建微信小程序脚手架的示例 1. 确定开发工具和技术栈 作为一名网站开发者,我们需要使用一些工具来开发Node CLI。这里我们推荐使用Node.js作为开发环境,并借助yargs和fs-extra这两个依赖库进行开发。 2. 创建项目和安装依赖 首先,我们需要在本地创建一个新的Node.js项目,并安装yargs和f…

    node js 2023年6月8日
    00
  • React Diff算法不采用Vue的双端对比原因详解

    React和Vue是两个目前最流行的前端框架。在实现虚拟DOM时,React和Vue采用了不同的算法。Vue采取的是双端对比算法,而React采取的则是基于Fiber架构的Diff算法。那么为什么React不采用Vue的双端对比算法呢?下面详细讲解React Diff算法不采用Vue的双端对比原因。 双端对比算法的原理 首先,我们简单介绍一下Vue的双端对比…

    node js 2023年6月8日
    00
  • JS常用函数使用指南

    JS常用函数使用指南 简介 本文将会带你了解一些 JS 常用函数,在特定的场合下使用它们可以大大提高开发效率。 Array 相关函数 map() 该方法可以遍历数组的每一项并执行一次回调函数,将回调函数的结果存储在新的数组中,并返回该新数组。 语法: let newArr = array.map(callback(currentValue [, index …

    node js 2023年6月8日
    00
  • Nodejs搭建多进程Web服务器实现过程

    Node.js是一个基于Chrome V8引擎运行JavaScript的开发平台,通过Node.js构建Web应用可以实现高并发、高可靠性,且易于开发和部署。本攻略旨在介绍如何使用Node.js搭建多进程Web服务器,以实现更高的并发量和更佳的性能表现。 一、多进程Web服务器的优劣 多进程Web服务器的优势在于多进程之间可以相互独立,互不干扰,可以有效地充…

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