如何使用Express将服务器渲染的HTML注入create-react-app

作者 : IT 大叔 本文共5367个字,预计阅读时间需要14分钟 发布时间: 2020-09-22

我最近在开发工作中的项目时遇到了使用Express和Create React App创建应用程序的既定模式的限制。我需要能够将服务器渲染的HTML注入到由create-react-app生成的应用程序中。在工作中,我们有一个在服务器上生成的全局页眉和页脚,用于包装客户端JavaScript应用程序。我们一直在使用Vue + Vue CLI + Express将服务器渲染的HTML注入客户端应用程序,但是我想看看是否可以使用Create React App + Express实现相同的功能。

尽管可以通过Next.js之类的东西或使用Express + Webpack样板来渲染服务器端生成的HTML,但我真的很想看看我是否可以坚持使用Express + Create React App而不会像队友一样出现,我没有想要维护所有的webpack,babel,eslint等配置,而我们已经拥有围绕Express构建的大型模块生态系统。在创建反应的应用程序内的文档描述来呈现数据到index.html的能力文件,但它是如何,所以我想我会分享我做了什么让这对我的用例的工作真正实现此功能模糊。

使用create-react-app进行初始化

我们需要做的第一件事是运行create-react-app。运行以下命令以生成应用程序。

npx create-react-app my-app

安装所有依赖项后,在您喜欢的代码编辑器中打开项目。

安装其他依赖项

我们需要做的下一步是添加一些我们将用于该应用程序的依赖项。
运行以下命令以添加这些依赖项:

yarn add cra-build-watch express express-es6-template-engine npm-run-all reload serialize-javascript

如果已经nodemon全局安装,则可以跳过此步骤,否则,您还需要安装nodemon:

yarn add nodemon -D

让我们研究一下这些功能的用途。

cra-build-watch

而不是运行react-scripts start,我们将使用此软件包代替start脚本。这将构建文件,将它们写入磁盘,并设置文件观察器以在我们对./src./public目录进行更改时进行重建。

表达

我们将使用express在生产和开发中为我们的应用程序提供服务。与运行启动脚本时使用create-react-app相比,这是不同的,因为我们不会使用webpack-dev-server来提供任何文件。

express-es6-template-engine

我们将使用它来将占位符注入public/index.htmlcreate-react-app使用的文件中。将此文件转换为build/index.html我们的文件后,我们将通过express提供该文件,并使用express-es6-template-engine将占位符替换为我们要使用的任何服务器呈现的HTML。

npm-run-all

我们将使用它来并行运行cra-build-watch和express服务器。我们将在npm start脚本中使用此脚本,因此当我们运行该脚本时,我们可以在其中编辑我们的应用程序./src并使其重建文件,而express将从中提供文件./build

Nodemon

nodemon是一种工具,可在检测到目录中的文件更改时通过自动重新启动节点应用程序来帮助开发基于node.js的应用程序。每当对./server目录或./build目录进行更改时,我们将使用它来重新启动服务器。我们实际上将忽略对./src目录的更改,因为我们要监视由目录更改产生的构建目录中的更改./src。这是为了确保在./build目录更新之前,我们不会重新加载应用程序./src

重装

每当对Express服务器或react应用进行更改时,我们将在Express应用和react应用中使用它来重新加载浏览器。

序列化JavaScript

通过将JSON数据直接呈现在index.html文件中来自服务器的脚本标记中,该代码可用于序列化可能用于引导应用程序的所有JSON数据。有关更多信息,请参见:https :
//medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0

更新npm脚本

接下来,我们将替换npm脚本。删除当前的npm脚本:

"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"

将它们替换为以下npm脚本:

"start": "npm-run-all -p build:watch server:watch",
"server": "node server/app.js",
"server:watch": "nodemon --ignore './src/' server/app.js",
"build": "react-scripts build",
"build:watch": "cra-build-watch",
"test": "react-scripts test",
"eject": "react-scripts eject"

向package.json文件添加主页密钥

默认情况下,假设您的应用托管在服务器根目录下,Create React App会生成一个构建。

要覆盖它,您可以在package.json中指定主页。这将使Create React App正确推断要在生成的HTML文件中使用的根路径。投放静态资产时,我们还将在Express应用中使用此密钥。

我们将继续在package.json文件中设置以下内容:

"homepage": "/",

可以在以下位置找到有关使用此主页密钥的更多信息:https :
//create-react-app.dev/docs/deployment/#building-for-relative-paths

更新public / index.html

我们需要做的一件事是从中删除HTML注释public/index.html,express-es6-template-engine似乎已陷入其中。然后,我们将添加占位符,这些占位符将在从Express服务到应用程序时注入,以注入服务器渲染的HTML。

<body>index.html文件的内部,我们将添加以下内容:

<%= '${header}' %>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<%= '${footer}' %>
<script>var bootstrap = <%= '${bootstrap}' %>;</script>

这对于创建占位符${header}${footer}${bootstrap};

仅当我们在开发模式或非生产模式下运行应用程序时,才需要添加下一部分。

我们将以下</body>代码添加到index.html结束标记之前。

<% if(process.env.NODE_ENV !== 'production'){ %>
<script src="/reload/reload.js"></script>
<% } %>

这将连接我们将在客户端上使用的代码,以在以开发人员模式构建时重新加载应用程序正在运行的网页。

快捷应用设置

我们要做的下一步是设置Express应用。

服务器/ app.js

首先,我们将server在根目录内部创建一个目录。接下来,我们将app.jsserver目录内部创建一个文件,并在其中添加以下代码。

const express = require('express');
const http = require('http');
const path = require('path');
const reload = require('reload');
const es6Renderer = require('express-es6-template-engine');
const serialize = require('serialize-javascript');

const packageJson = require('../package.json');
const router = require('./api');

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

// Api Routes
app.use(`${packageJson.homepage}api`, router);

// view engine setup
app.engine('html', es6Renderer);
app.set('views', path.resolve(__dirname, '../build/'));
app.set('view engine', 'html');

// Serve static files
app.use(packageJson.homepage, express.static(path.join(__dirname, '..', 'build'), {
  index: false
}));

const server = http.createServer(app);
server.listen(3000, () => console.log('App is running on localhost:3000'));
// Wire up reload behavior if app is not running in production mode
if (process.env.NODE_ENV !== 'production') {
  // Wires up handler for /reload/reload.js route
  reload(app);
}

// For all requests besides /api, serve the index template based on create-react-app's public/index.html file
app.get('*', (req, res) => {
  res.render('index', {
    locals: {
      header: '<header class="express-header">Custom Header from Express</header>',
      footer: '<footer class="express-footer">Custom Footer from Express</footer>',
      bootstrap: serialize({ bootstrap: 'data' }, { isJSON: true }),
    },
  });
});

概括而言,此文件的作用是设置Express应用,以服务从create-react-app(输出到./build)生成的应用。我们将./build/index.html与express-es6-template-engine一起使用,以替换页眉,页脚和引导占位符。我们还为Express将提供的API设置了一条路由。

服务器/api/index.js

接下来,我们将设置一个将用于API的路由处理程序。在目录api内部创建一个server目录。然后index.jsapi目录内部创建一个名为的文件。在中index.js,添加以下代码:

const express = require('express');

const router = express.Router();

// Api routes
router.get('/ping', (req, res) => {
  return res.json({ text: 'pong' });
});

module.exports = router;

在这里,您可以构建应用程序可能需要的任何API。

启动应用

首次运行start npm脚本之前,您需要运行yarn build以生成./build目录。

完成上述操作后,我们就可以启动该应用程序了。运行以下命令以在开发人员模式下启动应用程序。

yarn start

该应用程序应在http:// localhost:3000上打开

当我们启动应用程序并在浏览器中导航到http:// localhost:3000时,我们可以看到从express注入到index.html文件中的自定义页眉和页脚。

我们还可以在index.html文件中看到内联脚本,该内联脚本可呈现从Express服务器提供的数据。这可用于引导来自服务器的数据的客户端应用程序,并保存API请求以在页面加载时获取初始数据。

如果我们在./src./public或中的文件进行了更改./server,则该应用程序将重新加载到浏览器中。

在生产中运行

准备好在生产模式下运行该应用程序后,请记住运行yarn build以构建用于生产的资产,然后可以运行yarn server以启动该应用程序。

免责声明:
1. 本站资源转自互联网,源码资源分享仅供交流学习,下载后切勿用于商业用途,否则开发者追究责任与本站无关!
2. 本站使用「署名 4.0 国际」创作协议,可自由转载、引用,但需署名原版权作者且注明文章出处
3. 未登录无法下载,登录使用金币下载所有资源。
IT小站 » 如何使用Express将服务器渲染的HTML注入create-react-app

常见问题FAQ

没有金币/金币不足 怎么办?
本站已开通每日签到送金币,每日签到赠送五枚金币,金币可累积。
所有资源普通会员都能下载吗?
本站所有资源普通会员都可以下载,需要消耗金币下载的白金会员资源,通过每日签到,即可获取免费金币,金币可累积使用。

发表评论