Creating a Git Information Injection Plugin for Webpack and Vite Using Trae‑Builder
This article explains how to develop a custom plugin that automatically captures Git metadata during build time, injects it into the bundled code, and exposes the information via a console command, with step‑by‑step guidance for both Webpack and Vite projects using Trae‑Builder.
Plugin Purpose
Hello, I’m Shi Xiaoshi. Often we need to embed custom data such as deployment documents, related resources, or build timestamps directly into the code so that they travel with the deployed artifact and are only visible to us. To address this, I created a small plugin that automatically records the current Git information and allows arbitrary custom content injection, compatible with both Webpack and Vite projects.
After installing the plugin, simply type info in the browser console to view the injected build information or your personal easter egg.
Implementing the Plugin with Trae
Plugin Principle
The overall idea consists of three steps:
During packaging or compilation, use Node to obtain the current Git information.
After packaging, inject the retrieved Git data into the bundled code.
Expose the data in the browser console via a special accessor.
├── Core Logic Layer
│ ├── Git information collection (via Node)
│ ├── Information processing & injection (via Webpack or Vite hooks)
├── Build‑tool Adapter Layer (detect tool type)
│ ├── Webpack plugin implementation
│ └── Vite plugin implementation
└── Output Presentation Layer
├── Console style optimization
└── Information display mechanism (window hijacking)Rapid Project Setup with Trae‑Builder
First create a dist-info folder and open the project with Trae. A minimal plugin project should contain:
├── index.js // plugin core logic
├── README.md // usage instructions
├── rollup.config.js // build configuration
├── package.json // dependenciesTrae‑Builder offers a “Trae‑Builder mode” that automatically creates this structure and saves any file changes instantly.
Core Code Implementation with Trae
The main entry point determines whether the project uses Vite or Webpack and returns the appropriate plugin:
const isVite =
process.argv.some((arg) => arg.includes("vite")) ||
process.env.VITE_ !== undefined;
function DistInfoPlugin() {
try {
const jsContent = getJsContent();
return isVite ? vitePlugin(jsContent) : webpackPlugin(jsContent);
} catch (err) {
console.log("DistInfoPlugin", err);
}
}
module.exports.default = DistInfoPlugin;
module.exports = DistInfoPlugin;getJsContent gathers Git metadata using Node’s child_process module and formats it into a list of description/value pairs.
const { execSync } = require('child_process');
const getGitInfo = (gitMeta) => {
try { return execSync(gitMeta)?.toString().trim(); }
catch { return "--"; }
};
const getJsContent = () => {
const consoleList = [
{ description: "Commit Author", value: getGitInfo("git show -s --format=%cn") },
{ description: "Version", value: getGitInfo("git show -s --format=%h") },
{ description: "Branch", value: getGitInfo("git symbolic-ref --short -q HEAD") },
{ description: "Message", value: getGitInfo("git show -s --format=%s") },
{ description: "Commit Time", value: getGitInfo("git show -s --format=%cd") },
];
// ... (returns a script that defines window.info getter)
};The script defines a getter on window.info that, when accessed (e.g., by typing info in the console), clears the console and logs each description/value pair.
function webpackPlugin(jsContent) {
return {
apply(compiler) {
compiler.hooks.emit.tap('distInfoPlugin', (compilation) => {
const jsAsset = Object.keys(compilation.assets).find(p => p.endsWith('.js'));
const htmlAsset = Object.keys(compilation.assets).find(p => p.endsWith('.html'));
if (!jsAsset || !htmlAsset) return;
const timestamp = Date.now().toString();
const jsPath = jsAsset.replace(/[^/]+\.js$/, `dist-info-${timestamp}.js`);
const originalHtml = compilation.assets[htmlAsset].source();
const updatedHtml = originalHtml.replace(/(
]*>)/, `$1
`);
compilation.assets[htmlAsset] = { source: () => updatedHtml, size: () => updatedHtml.length };
compilation.assets[jsPath] = { source: () => jsContent, size: () => jsContent.length };
});
}
};
}For Vite, the transformIndexHtml hook inserts the generated script before the closing </body> tag.
function vitePlugin(jsContent) {
return {
name: "vite-plugin-dist-info",
transformIndexHtml(html) {
const scriptTag = `
`;
return html.replace(/<\/body>/, `${scriptTag}
`);
}
};
}Code Optimization
Potential improvements include encrypting the injected script to protect sensitive Git data, beautifying console output with styled logs, and adding configurable options to the plugin so users can customize which information is displayed.
function log(description, value) {
console.log(
"%c Info Name %c Info Value ",
"background:#ff4d4f;border:1px solid #ff4d4f; padding:1px; border-radius:2px 0 0 2px; color:#fff",
"border:1px solid #ff4d4f; padding:1px; border-radius:0 2px 2px 0; color:#ff4d4f"
);
}The plugin can also accept an options object to allow users to enable/disable features or change the console command.
function BuildInfoPlugin(options = {}) {
try {
const jsContent = getJsContent(options);
return isVite ? vitePlugin(jsContent) : webpackPlugin(jsContent);
} catch (err) {
console.log('BuildInfo', err);
}
}Project Participation and Code Contribution
The plugin is published on npm as dist-info . Developers are encouraged to star the repository, submit pull requests, and explore further enhancements. The source code is available at GitHub .
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.