如何在使用create-react-app创建的React Web应用中展示构建日期时间?

26

简短版 - 我想在应用程序的页脚上显示生产应用程序的部署日期,以便用户知道应用程序上次更新的确切时间。

我希望这是自动的,但我无法想到一种方法来捕获当前日期时间并将其解析为html(jsx)以展示它们。

更新 - 顺便说一句,我使用CRA,并且没有计划退出它! 至少对于这个问题不会。

背景 - 我为什么需要这个? 我有一个React生产应用程序,我无法无限制地访问它。有些问题在那里引起了问题,我能够在我的开发环境中复制它,并修复了问题并进行了部署(或者我认为我已经这样做)。但是问题仍然存在于生产中,在更长时间的调试之后,我向他们索取了很多诊断信息,以检查生产API或数据库是否存在问题等。但最终结果是我的部署到生产环境并不成功。我认为,如果我在应用程序的某个位置显示上次部署的日期时间,我就可以直接向用户询问而不必进入详细的诊断信息。


1
你可以创建一个环境变量来计算日期和时间,并在页脚组件中访问该变量。process.env.BUILD_DATE_TIME。这样,您就可以显示构建的大致日期和时间。 - simbathesailor
好的,但是我应该如何确切地在构建时更新环境变量? - Ragav Y
请注意,您的BUILD_DATE_TIME变量将在编译时计算,准确地说是在打包程序创建块时。这就是我之前说“大约”的原因。通过这种方式,您的问题将得到解决。每次您将构建发布到生产环境时,都会获得不同的日期和时间。 - simbathesailor
尝试过这个方法,但是CRA出于安全/隐私原因会自动清理除了NODE_ENV以外的所有环境变量(链接-https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables)。因此,如果BUILD_DATE_TIME变量在node.js上通常可用,则在CRA上将不可用。 - Ragav Y
1
啊,我错过了一个要点,你需要将环境变量命名为REACT_APP_BUILD_DATE_TIME。这样应该就可以了。然后在你的页脚组件中访问它。process.env.REACT_APP_BUILD_DATE_TIME。这样应该就可以了。 - simbathesailor
5个回答

48

我是 Create React App 的维护者!

从 Create React App 2 (react-scripts@^2.0) 开始,你可以通过宏来实现这个功能。

首先,安装 preval.macro

$ npm install --save preval.macro # if using npm
$ yarn add preval.macro # if using yarn

接下来,在您要呈现构建时间戳的文件中,包含preval.macro

import preval from 'preval.macro'

最后,您可以创建一个常量并像这样在您的应用程序中使用它:

const dateTimeStamp = preval`module.exports = new Date().toLocaleString();`

这里是一个完整的例子:

import React, { Component } from 'react'
import logo from './logo.svg'
import './App.css'
import preval from 'preval.macro'

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Build Date: {preval`module.exports = new Date().toLocaleString();`}.
          </p>
        </header>
      </div>
    )
  }
}

export default App

这个已经可以工作了。我试图将我的应用程序升级到react-scripts 2。在解决依赖问题后,它开始编译了。但是之后,在我的应用程序中出现了很多问题,这些问题以前从未被抱怨过,但现在正在被抱怨。很多这些错误甚至没有行号等信息。叹气 让我的应用程序在react-scripts 2上工作需要比我预期的时间更长。但是这个解决方案有效,我在一个新的应用程序上尝试过了。谢谢! - Ragav Y
很多这样的错误甚至没有行号等信息。这种行为听起来像是一个 bug!你能否提供更多信息并提交一个问题,以便我们可以仔细查看? - Joe Haddad
抱歉,我正在处理生产应用程序中的其他问题,暂时无法进行react-scripts2.0迁移。但是,一旦我开始处理,我会在这里更新任何异常错误。谢谢! - Ragav Y
在此解决方案上有一些讨论,请参见此处 - https://github.com/facebook/create-react-app/issues/4960 - Brian Burns
我在我的应用程序中尝试了这个,它可以正常工作。我能否将preval行移动到(组件内的)包中,同时确保它在应用程序构建时进行评估(而不是组件构建时)? - watery

5
joe-haddad提供的解决方案效果很好。下面是一个可直接使用的组件,您可以像这样使用:<VersionNumber />。这将显示类似于以下内容:enter image description here
import React       from 'react';
import moment      from 'moment';
import packageJson from '../../../package.json';
import preval      from 'preval.macro';

const buildTimestamp = preval`module.exports = new Date().getTime();`;

class Component extends React.Component {
    getDateString = () => {
        const lastUpdateMoment = moment.unix(buildTimestamp / 1000);
        const formattedDate    = lastUpdateMoment.format('DD.MM.YYYY HH:mm:ss');

        return formattedDate;
    };

    render () {
        return (
            <div>
                {packageJson.version}
                {'.'}
                {buildTimestamp}
                {' '}
                {'('}
                {this.getDateString()}
                {')'}
            </div>
        );
    }
}

Component.propTypes = {};

Component.defaultProps = {};

export default Component;

这个能否移动到作为依赖项的应用程序包中? - watery

0

使用webpack设置进程环境。您可以将值保存到本地json文件中,并在编译过程中进行增量读取。


0

Joe Haddat的回答的贡献;如果你想使用preval.macro在查看器时区而不是构建应用程序的环境时区来说明构建日期,以下是如何操作:


render() {
  const buildDate = preval`module.exports = new Date();`
  return (
     <div>Build Date: {new Date(buildDate).toLocaleString()}</div>
  )
}

这将保存构建日期,但将其转换为区域设置字符串仍将在运行时发生,在浏览器中使用查看器时区。


-1
    function getClientEnvironment(publicUrl) {
      const raw = Object.keys(process.env)
        .filter(key => REACT_APP.test(key))
        .reduce(
          (env, key) => {
            env[key] = process.env[key];
            return env;
          },
          {
            // Useful for determining whether we’re running in production mode.
            // Most importantly, it switches React into the correct mode.
            NODE_ENV: process.env.NODE_ENV || 'development',
            REACT_APP_DATE_TIME: new Date().toDateString(),
            // Useful for resolving the correct path to static assets in `public`.
            // For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
            // This should only be used as an escape hatch. Normally you would put
            // images into the `src` and `import` them in code to get their paths.
            PUBLIC_URL: publicUrl,
          }
        );
      // Stringify all values so we can feed into Webpack DefinePlugin
      const stringified = {
        'process.env': Object.keys(raw).reduce((env, key) => {
          env[key] = JSON.stringify(raw[key]);
          return env;
        }, {}),
      };

      return { raw, stringified };
    }

module.exports = getClientEnvironment;

旧的解决方案也可以使用。请再次检查代码。因为我在我的应用程序中看到了正确的值。


尝试过这个,但它只是将其渲染为字符串 "new Date().toDateString()"。不能在 .env 文件上运行 JS 代码,对吧? - Ragav Y
现在我需要运行它并检查一下。这里有很多陷阱 :)。让我试试。 - simbathesailor
你能否给我一些关于如何处理那个函数的上下文信息?我应该把它放在哪里,什么时候调用它?到目前为止,我只在 .env.development 和 .env.production 文件中使用了环境变量。在 CRA 中还有其他定义环境变量的方法吗? - Ragav Y
你正在使用如上所述的create react app。因此,请前往YourProject/config/env.js。在那里,你会发现这个函数已经被编写好了,我只添加了一行REACT_APP_DATE_TIME: new Date().toDateString()。 - simbathesailor
我之前没有config/env.js文件。但是我尝试创建了一个config文件夹,并添加了一个包含上述代码的env.js文件,但不起作用。我还尝试将env.js文件放在根目录中,但也不起作用。你是否使用像dotenv这样的env依赖项?因为当你使用npx create-react-app <app-name>创建create-react-app时,它不会自动创建config/env.js。另外,你能给我展示一下你的package.json中的scripts部分吗? - Ragav Y
2
我代表您记录了一个问题。即使我不确定如何在未弹出的情况下执行此操作。我的应用程序已被弹出,这就是我能够做到的原因。https://github.com/facebook/create-react-app/issues/5598。 - simbathesailor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接