在create-react-app中添加git信息

mdfafbf1  于 12个月前  发布在  Git
关注(0)|答案(8)|浏览(94)

在开发过程中,我希望能够从Web上看到构建信息(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。有人有什么主意吗?

vuktfyat

vuktfyat1#

稍微偏离一下(不需要弹出,并且可以在开发中工作),这可能有助于其他人将他们当前的git commit SHA作为元标签添加到他们的index.html中:

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

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

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

到公用文件夹中的index.html。
在react组件中,这样做:

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

p8h8hvxi2#

受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包中,因此请确保提交消息中没有输入任何安全信息。我还将created_git_commit. js添加到.gitignore中,这样它就不会被检入(并创建了一个疯狂的git提交循环)。

11dmarpk

11dmarpk3#

在没有eject ing的情况下是不可能做到这一点的,直到Create React App 2.0(Release Notes)带来了在编译时运行的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项目有更多的信息。您还可以看到here软件包的现场演示。

gfttwv5a

gfttwv5a4#

所以,事实证明没有办法在不弹出的情况下实现这一点,所以我使用的解决方法是:
1)在package.json中,定义脚本"git-info": "git log -1 --oneline > src/static/gitInfo.txt"
2)为启动和构建添加npm run git-info
3)在configjs文件中(或者当你需要git信息时),我有

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

2g32fytz5#

我的方法与@uidevthing的答案略有不同。我不想用环境变量设置污染package.json文件。
您只需运行另一个脚本,将这些环境变量保存到项目根目录下的.env文件中。就这样
在下面的例子中,我将使用typescript,但无论如何转换为JavaScript应该是微不足道的。

package.json

如果使用JavaScript,则为node scripts/start.js

...
  "start": "ts-node scripts/start.ts && react-scripts start",

scripts/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://stackoverflow.com/a/56577324/9449426
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

更多参考:

  • https://create-react-app.dev/docs/adding-custom-environment-variables/#adding-development-environment-variables-in-env
xriantvc

xriantvc6#

如果你的package.json脚本总是在unix环境中执行,你可以实现与@NearHuscarl答案中相同的效果,但是通过从shell脚本初始化你的.env dotenv文件来减少代码行。生成的.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。

bfnvny8b

bfnvny8b7#

你可以使用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"
}
7jmck4yq

7jmck4yq8#

上面提供的答案涵盖了广泛的场景,但我找不到任何提供vanilla 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环境)。它将使用添加或更新的REACT_APP_VERSION=XX属性更新.env文件。原始内容保持原样。如果文件不存在,则将创建该文件。

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://stackoverflow.com/a/77133455/7961775
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 + os.EOL;
            }

            output += lineToAppend;
        });

        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);
    }
})();

相关问题