【问题标题】:Dynamically updating index.html file in production build of a create react app在创建反应应用程序的生产版本中动态更新 index.html 文件
【发布时间】:2021-05-22 02:23:46
【问题描述】:

我的客户端应用程序是使用 Create React App 构建的,它内置了很多便利。但是,开箱即用的服务器端渲染是不可能的。因此,一旦运行 build 命令,所有输出实际上都是静态的。

我有一个用例,我不想切换到完成 SSR 设置,但想将一些数据动态添加到 index.html 文件,以便在客户端首次加载文件时立即在 javascript 中可用。

我想出了以下解决方案:

  • React 应用作为 docker 容器运行,使用 serve 库提供静态构建内容
  • 单独的节点服务在不同的 docker 容器中运行,并且可以通过共享卷从 react 应用程序访问构建内容
  • 节点服务每隔几分钟运行一个函数,该函数使用fs 读取index.html 文件的内容,将一些附加数据插入到脚本标签(例如window.myData={someKey: 'someValue'})中,并将更新后的字符串写入index.html .

本地使用docker-compose,效果很好。但是,我想知道这种方法可能产生的后果,尤其是当节点服务正在读取/写入 index.html 上的某种文件锁定时,对 react 应用程序的传入请求将失败的情况。

我不认为这会是一个问题,但我有足够的疑问来发布这个问题。由于一些不可预见的问题,我能承受的最后一件事是我的生产应用程序中的请求失败。

感谢任何意见、建议、轶事等!

【问题讨论】:

  • 我知道已经过去了很长一段时间,但仍然:您是否设法解决了这个问题,而不求助于 docker 等?也许以类似于@Phuoc Do 的答案的方式?

标签: reactjs create-react-app server-side-rendering


【解决方案1】:

我已成功为 CRA 添加了 SSR,但没有弹出。如果这是您唯一的用例,那么 SSR 设置将非常简单,因为您不必处理 webpack 或 babel 配置。如果您有兴趣,请按照以下 3 步操作:

  • 第 1 步:在根/项目文件夹(与 src/ 相同级别)的新文件夹中添加基本 Express 服务器
  • 第 2 步:对于主要应用程序路由,请阅读文件 build/index.html 并在发送前根据需要对其进行编辑。
  • 第 3 步:除这些路由外,按照 CRA SSR 文档的建议提供 CRA 构建/静态文件

TL;DR

// root/server/index.js (your build is at root/build)
const express = require("express");
const fs = require("fs");
const path = require("path");

const app = express();

// step 2
const renderContent = (req, res) => {
  fs.readFile(
    path.resolve(__dirname, "../build/index.html"), "utf8", (err, htmlData) => {
      if (err) {
        return res.sendStatus(500);
      }

      /* Do something with htmlData here */

      return res.send(htmlData);
    });
}

app.use("^/$", renderContent); // step 2
app.use(express.static(path.resolve(__dirname, "../build"))); // step 3
app.use("*", renderContent); // step 2

// step 1
app.listen(process.env.PORT, () => {
    console.log(`Listening on port ${process.env.PORT}`);
});

然后,你只需要运行:node server/index.js,这个服务器就会正常为你的 Create React App 提供服务,除了上面你编辑 HTML 的部分。

【讨论】:

  • 感谢您的回复。几个月前我也这样做了,我相信它大部分都有效,但我记得使用 typescript 带来了一些挑战,我需要为服务器和客户端提供单独的 tsconfig.json 文件。此外,我相信使用内置 CRA 实时重载进行本地开发会带来一些挑战。您是否在本地运行此设置,如果是,您是否遇到任何问题?
  • 要在服务器端使用相同的文件 tsconfig.json,请将 rootDir 选项更改为项目文件夹 root/ 而不是文件夹 root/src。通过此调整,根/服务器文件夹也将包含在 tsconfig.json 中。要使用内置的 CRA 开发服务器,请将步骤 3 更改为:if (NODE_ENV === "development") { const proxy = createProxyMiddleware({ target: "http://localhost:3000", changeOrigin: true }); app.use(Express.static("public")); app.use(/^\/(static|asset-manifest.json).*/, proxy); } else { app.use(Express.static("build")); }
【解决方案2】:

我不知道这是否会有所帮助,但作为一个建议。我遇到了类似的用例。我使用HtmlWebpackPlugin 非常简单地解决了它。

在 webpack 配置中。我写的是这样的:

 new htmlWebpackPlugin({
      template: path.join(rootpath, '', 'index.html'),
      inject: false //<-- Notice here
    })

我将“inject”设置为 false 并使用此标志它不会在 index.html 上附加脚本/捆绑包,同时它允许我们使用 ejs 模板来循环我们想要附加到索引上的文件.html。

就像我在 index.html 上写的:

 <% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
                <link rel="stylesheet" type="text/css" href="<%= htmlWebpackPlugin.files.chunks[chunk].css %>">
                <script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>
                <% } %>

我的建议是创建一个单独的块/文件(js),您希望在 index.html 上动态附加并使用 EJS 模板,您可以获得所需的结果。

如何创建块:READ HERE

谢谢,希望对您有所帮助。

【讨论】:

  • 您使用 creat-react-app 应用程序执行此操作?你的 webpack 配置在哪里?
猜你喜欢
  • 2019-08-01
  • 1970-01-01
  • 2017-12-08
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多