将 Git 信息添加到 create-react-app

55

在开发中,我想要能够从网页上查看构建信息(git提交哈希值、作者、最后一次提交消息等)。我尝试过:

  • 使用 child_process 执行 git 命令行,并读取结果(因为浏览器环境的原因不可行)
  • npm build 过程中生成 buildInfo.txt 文件,并从文件中读取(因为浏览器环境中也无法使用 fs 不可行)
  • 使用外部库,例如 "git-rev"

唯一剩下的做法似乎是运行 npm run eject 并应用 https://www.npmjs.com/package/git-revision-webpack-plugin ,但我真的不想退出 create-react-app。有人有什么想法吗?

8个回答

98
在一个轻微的偏离方向上(无需弹出并且在开发中可工作),这可能对其他人有所帮助,想要将他们当前的git提交SHA添加到他们的index.html中作为元标记,可以通过添加以下内容实现:

On a slight tangent (no need to eject and works in develop), this may be of help to other folk looking to add their current git commit SHA into their index.html as a meta-tag by adding:

REACT_APP_GIT_SHA=`git rev-parse --short HEAD`

在 package.json 的构建脚本中添加(注意它必须以 REACT_APP... 开头,否则将被忽略):

<meta name="ui-version" content="%REACT_APP_GIT_SHA%">

将其放入public文件夹中的index.html文件中。

在React组件内,可以这样做:

<Component>{process.env.REACT_APP_GIT_SHA}</Component>

8
@BugsBunny 这应该是相同的工作原理。只需将分配添加到“start”脚本中。 "start": "REACT_APP_GIT_SHA=\git rev-parse --short HEAD` react-scripts start"` - Bohdan Ganicky
@uidevthing 你是怎么知道在 package.json 脚本中使用反引号来实现替换的?我之前为了让它正常工作而苦苦挣扎了几个小时,直到偶然发现了你的解决方案。顺便说一句,它完美地解决了我的问题! - IAmKale
9
这不是跨平台的解决方案。在 Windows 上无法使用 Powershell 或 cmd。 - Abhyudaya Sharma
1
如果不改变你的 npm 配置,cross-env 将无法工作;请参见此处:https://github.com/kentcdodds/cross-env/issues/192#issuecomment-513341729 - TranquilMarmot
"REACT_APP_GIT_SHA=git rev-parse --short HEAD react-scripts start"。我该如何在Windows命令提示符中运行此命令? - Rohit Vyas
显示剩余5条评论

15

我创建了受 Yifei Xu 回答启发的另一个选项,它使用 es6 模块和 create-react-app。此选项创建一个 JavaScript 文件,并将其作为常量导入到构建文件中。虽然将其作为文本文件可以方便地更新,但此选项可确保它是打包到 JavaScript 包中的 js 文件。该文件的名称为 _git_commit.js。

package.json 脚本:

"git-info": "echo export default \"{\\\"logMessage\\\": \\\"$(git log -1 --oneline)\\\"}\"  > src/_git_commit.js",
"precommit": "lint-staged",
"start": "yarn git-info; react-scripts start",
"build": "yarn git-info; react-scripts build",
一个消费该提交消息的示例组件:
import React from 'react';

/**
 * This is the commit message of the last commit before building or running this project
 * @see ./package.json git-info for how to generate this commit
 */
import GitCommit from './_git_commit';

const VersionComponent = () => (
  <div>
    <h1>Git Log: {GitCommit.logMessage}</h1>
  </div>
);

export default VersionComponent;
请注意,这将自动将您的提交消息放入JavaScript包中,请确保不要在提交消息中输入任何安全信息。我还将创建的_gi t_commit.js 添加到 .gitignore 中,因此不会被检入(并且会创建一个疯狂的 git 提交循环)。

11
在Create React App 2.0版本(发布说明)之前,没有使用 eject 命令就无法完成此操作。此版本自动配置了Babel插件,可以在编译时运行。为了方便大家,我编写了其中一个宏,并发布了一个NPM包,您可以导入该包以获取git信息并将其添加到React页面中:https://www.npmjs.com/package/react-git-info

使用如下:

import GitInfo from 'react-git-info/macro';

const gitInfo = GitInfo();

...

render() {
  return (
    <p>{gitInfo.commit.hash}</p>
  );
}

这个项目的README有更多信息。您也可以在这里查看包的实时演示。


虽然这会增加另一个软件包,但这是一种超级干净和有用的实现目标的方式。 - Fred Zimmerman

9

所以,事实证明没有办法在不弹出的情况下实现这一点,因此我使用的解决方法是:

1)在package.json中定义一个脚本"git-info": "git log -1 --oneline > src/static/gitInfo.txt"

2)为启动和构建添加npm run git-info

3)在config js文件中(或者你需要Git信息的任何地方),我有:

const data = require('static/gitInfo.txt')
fetch(data).then(result => {
    return result.text()
})

9
我的方法与@uidevthing的答案略有不同。我不想用环境变量设置来污染package.json文件。
你只需运行另一个脚本,将这些环境变量保存到项目根目录下的.env文件中。就是这样。
在下面的示例中,我将使用typescript,但无论如何都应该很容易转换为javascript。 package.json
如果您使用javascript,则为node scripts/start.js
  ...
  "start": "ts-node scripts/start.ts && react-scripts start",

脚本/start.ts

创建一个新的脚本文件scripts/start.ts

const childProcess = require("child_process");
const fs = require("fs");

function writeToEnv(key: string = "", value: string = "") {
  const empty = key === "" && value === "";

  if (empty) {
    fs.writeFile(".env", "", () => {});
  } else {
    fs.appendFile(".env", `${key}='${value.trim()}'\n`, (err) => {
      if (err) console.log(err);
    });
  }
}

// reset .env file
writeToEnv();

childProcess.exec("git rev-parse --abbrev-ref HEAD", (err, stdout) => {
  writeToEnv("REACT_APP_GIT_BRANCH", stdout);
});
childProcess.exec("git rev-parse --short HEAD", (err, stdout) => {
  writeToEnv("REACT_APP_GIT_SHA", stdout);
});

// trick typescript to think it's a module
// https://dev59.com/x1MI5IYBdhLWcg3wS5cv#56577324
export {};

上述代码将设置环境变量并将它们保存到根文件夹下的.env文件中。它们必须以REACT_APP_开头。React脚本在构建时自动读取.env,并将它们定义在process.env中。

App.tsx

...
console.log('REACT_APP_GIT_BRANCH', process.env.REACT_APP_GIT_BRANCH)
console.log('REACT_APP_GIT_SHA', process.env.REACT_APP_GIT_SHA)

结果

REACT_APP_GIT_BRANCH master
REACT_APP_GIT_SHA 042bbc6

更多参考资料:

运行得非常顺利 - Ilimkan Omurzakova
适用于React Native,运行良好。 - Stanislau Buzunko

2
如果你的 package.json 脚本总是在Unix环境下执行,你可以通过从shell脚本初始化你的 .env dotenv 文件来以更少的代码行数实现与 @NearHuscarl 的答案相同的效果。生成的 .env 然后会被 react-scripts 在后续步骤中 使用
"scripts": {
  "start": "sh ./env.sh && react-scripts start"
  "build": "sh ./env.sh && react-scripts build",
}

在您的项目根目录中放置.env.sh文件,其中包含类似以下代码的内容,以便在每次构建或启动时覆盖您的.env文件内容。

{
  echo BROWSER=none
  echo REACT_APP_FOO=bar
  echo REACT_APP_VERSION=$(git rev-parse --short HEAD)
  echo REACT_APP_APP_BUILD_DATE=$(date)
  # ...
} > .env

由于每次构建都会覆盖.env文件,您可以考虑将其放在.gitignore列表中,以避免提交差异过多。

再次声明:此解决方案仅适用于存在Bourne shell解释器或类似解释器的Unix环境。


0

你可以使用 CRACOcraco-interpolate-html-plugin 轻松将你的 git 信息(如 commit hash)注入到 index.html 文件中。这种方式无需使用 yarn eject,并且适用于开发服务器环境以及生产构建。

安装了 CRACO 后,在 craco.config.js 中添加以下配置对我很有效:

const interpolateHtml = require('craco-interpolate-html-plugin');

module.exports = {
  plugins: [
    {
      plugin: interpolateHtml,
      // Enter the variable to be interpolated in the html file
      options: {
        BUILD_VERSION: require('child_process')
          .execSync('git rev-parse HEAD', { cwd: __dirname })
          .toString().trim(),
      },
    },
  ],
};

在你的 index.html 文件中添加以下代码:

<meta name="build-version" content="%BUILD_VERSION%" />

以下是需要添加到 package.json 文件中的代码行,以使其正常工作:

"scripts": {
    "start": "craco start",
    "build": "craco build"
}

0
上面提供的答案涵盖了各种情况,但我没有找到任何提供纯JS和跨平台解决方案的答案。@NearHuscarl的解决方案完全覆盖了.env文件的内容,当文件中包含其他值时,这并不方便。这里提供一个只更新文件的解决方案。
我定义了一个新的脚本,在我的常规react-scripts命令之前调用我的JS片段:

package.json

{
    "scripts": {
        "git-version": "node scripts/set_env.js",
        "start": "yarn run git-version && react-scripts start",
        "build": "yarn run git-version && react-scripts build",
        
    },
}

脚本本身是使用Node运行的,不需要外部依赖(除了需要有Node环境)。它将更新.env文件,添加或更新REACT_APP_VERSION=XX属性。原始内容保持不变。如果文件不存在,将会被创建。

scripts/set_env.js

const childProcess = require("child_process");
const fs = require("fs");
const os = require("os");
const readline = require("readline");

const PREFIX = "REACT_APP_VERSION=";

// Append current git version on .env file https://dev59.com/6FYM5IYBdhLWcg3wxSR_#77133455
function writeToEnv(content) {
    return new Promise((resolve, reject) => {
        const fileStream = fs.createReadStream(".env");
        let output = "";
        let hasVersion = false;

        const readInterface = readline.createInterface({
            input: fileStream,
            crlfDelay: Infinity,
        });

        fileStream.on("error", (err) => {
            readInterface.close();
            fileStream.close();
            reject(err);
        });

        readInterface.once("error", (err) => {
            readInterface.close();
            fileStream.close();
            if (err.includes("Error: ENOENT:")) {
                console.info(".env file not found, will create it", err);
            } else {
                reject(err);
            }
        });

        readInterface.on("line", (line) => {
            let lineToAppend = "";

            if (!hasVersion && line.startsWith(PREFIX)) {
                lineToAppend = content;
                hasVersion = true;
            } else {
                lineToAppend = line;
            }

            output += lineToAppend + (lineToAppend.endsWith(os.EOL) ? undefined : os.EOL);
        });

        readInterface.on("close", () => {
            if (!hasVersion) {
                // File was not found
                output += content + os.EOL;
            }
            fs.writeFile(".env", output, (error) => {
                if (error) {
                    reject(error);
                } else {
                    resolve();
                }
            });
        });
    });
}

(async () => {
    try {
        const tags = childProcess.execSync("git describe --tags").toString().trim();
        const reactVersion = `${PREFIX}${tags}`;
        console.info(`Setting ${reactVersion}`);
        await writeToEnv(reactVersion);
    } catch (err) {
        console.error(`Could not set ${PREFIX}`, err);
    }
})();


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