How to show build datetime on my react web app using create-react-app?

Viewed 10801

tl;dr version - I want to show the date of deployment of the production application on the footer of my application so that the users know exactly when the application was last updated.

I want it to be automatic, but I can't think of a way to capture the current date time during build and then parse it into html (jsx) to show them.

Update - Btw, I use CRA and have no plans of ejecting from it! At least not for this.

Context - Why do I want this? I have a production application in React that I don't have unrestricted access to. There were some issues raised on there and I was able to replicate it on my dev and I fixed the issues and deployed it (or I thought I did). But the issue remained on production and after more time debugging, I just asked for a lot of diagnostic information from them to check if there was something wrong with the production API or database etc. But it finally turned out that my deployment to production wasn't successful. I think that if I showed the last deployement date-time somewhere on the app, I could just ask that from the users rather than get into elaborate diagnostic information.

5 Answers

I'm a Create React App maintainer!

Starting in Create React App 2 (react-scripts@^2.0) you can accomplish this via macros.

First, install preval.macro:

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

Next, in the file you want to render a build timestamp in, include preval.macro:

import preval from 'preval.macro'

Finally, you can create a constant and use it in your app like so:

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

Here's a full example:

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

The solution from joe-haddad is working well. Here is a drop-in component you can use like <VersionNumber />. This will display something like:

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;

Set a process environment using webpack. You can save the value to a local json file and read from it with an increment during the compilation.

    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;

The old solution will also work. Please check the code again. As i can see the proper value in my app.

A contribution to Joe Haddat's answer; if you want to illustrate the build date by using preval.macro in the viewer timezone instead of the environment timezone which builds the app, here is how to do it;


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

This will save the build date, but turning it into a locale string will still happen on runtime, on the browser where the viewer timezone is used.

Related