How to Pass Commit Hash to an Environment Variable Using Webpack Plugin in Vue 3

Dawid Witulski
JavaScript in Plain English
4 min readOct 20, 2021

--

Photo by Nubelson Fernandes on Unsplash

How do we determine which commit the app was built from?

Deploying the app to multiple instances — e.g., for many clients — may cause problems. When someone reports a bug, you might wonder how to determine the version of the app that a particular client is using. In Evionica, we have such a need since our apps are being used by many aviation companies.

Of course, there are many different approaches to do it. You could just check the latest deployment, but it takes some time. Why would the client not just provide the app version in the bug report? If you haven’t got an automated bug-reporting tool, it may be tricky to find out which version it is.

You could, of course, print the app version somewhere inside it. But you need to remember to update it between releases. Let’s be straight — you didn’t become a programmer to perform manual repeatable tasks when you could automate them.

Most of us use git

Probably, your app is stored somewhere in some version control system (if you don’t use such solutions — you’re a very brave person 😉). Let’s assume you’re using git in your project. Is there a better version identifier than commit hash? You can print it in the terminal using:

git rev-parse HEAD

That will print the SHA hash of the current commit — e.g. 1dfc6da771f3642c5c75g933bc05ca0d5fff6736. If you add the flag --short to this command, you will get the short version of this hash — e.g. 1dfc6da7:

git rev-parse --short HEAD

But how do you pass variables to the app during the build?

You can use environment variables to achieve it. Let’s create a simple component for this purpose. process.env isn’t accessible directly in the template, so we might wrap it in component data.

<template>
<div class="version-info">
{{ version }}
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
data: () => ({
version: process.env.VUE_APP_VERSION,
}),
});
</script>

Okay, so we’ve got a commit hash and template with printing environmental variable, but how to pass the commit hash to an environment variable? We can extend our vue.config.js. You need to create a Webpack plugin and add it to the plugin list inside the configureWebpack section:

module.exports = {
...
configureWebpack: {
plugins: [
/*** HERE :) ***/
],
},
};

To create a Webpack plugin, you need to create an instance of webpack.DefinePlugin class and define within the constructor the value you would like to access in the runtime

new webpack.DefinePlugin(runtimeValue)

You can define process.env variables using such runtimeValue

{
'process.env': {
/*** ENVIRONMENT VARIABLES ***/
},
}

So, to define our VUE_APP_VERSION we just use:

{
'process.env': {
VUE_APP_COMMIT_HASH: gitLastCommitHash,
},
}

Overall, we’ve got such construction:

module.exports = {
...
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
'process.env': {
VUE_APP_COMMIT_HASH: lastCommitHash,
},
}),
],
},
};

Git command in frontend app?

But now — how to pass terminal command results to vue.config.js? The file is loaded during the compilation, and we can execute here some node commands. There’s one that allows executing terminal commands in a js file:

const childProcess = require('child_process');childProcess.execSync('/*** COMMAND ***/')

As a command, we will use our git rev-parse --short HEAD. The execSync() may throw an error, so it’s a good practice to wrap it up in a try-catch block and print a possible error to the console.

const childProcess = require('child_process');try {
childProcess.execSync('git rev-parse --short HEAD')
} catch (e) {
console.error(e);
}

Let’s now store the result into a variable. Since we got try-catch, we might never get the result, so at first — let’s initialize the variable using let with an empty string value. Then we need to cast theexecSync() result to string with .toString(). To avoid redundant whitespaces, we may additionally use .trim().

const childProcess = require('child_process');let lastCommitHash = '';try {
lastCommitHash = childProcess
.execSync('git rev-parse --short HEAD')
.toString()
.trim();
} catch (e) {
console.error(e);
}

This way, we got the value ready to be passed to the Webpack plugin we’ve created previously. To avoid errors connected with string escaping, you can use JSON.stringify().

The ready file will look like this:

const childProcess = require('child_process');let lastCommitHash = '';try {
lastCommitHash = childProcess
.execSync('git rev-parse --short HEAD')
.toString()
.trim();
} catch (e) {
console.error(e);
}
module.exports = {
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
'process.env': {
VUE_APP_COMMIT_HASH: JSON.stringify(lastCommitHash),
},
}),
],
},
};

Wasn’t that hard, huh?

In that way, you can extend your app with any external data passed during compilation. In our app, we’ve printed the commit hash and the current app version from the package.json. We’ve placed the version info component inside the sidebar, making it easily accessible to the user.

Version info next to copyright in the sidebar.

Now, when the client reports a bug, we can easily verify the version of the app he is using and the commit used to perform its build.

~ Dawid Witulski @ Evionica — 2021

More content at plainenglish.io

--

--