How can I inject a build number with webpack?

Webpack

Webpack Problem Overview


I'd like to inject a build number and version information to my project as it's built with webpack. For example, so that my code can do something like:

var buildInfo = require("build-info");

What would be the best way to generate that build-info module at build time?

Webpack Solutions


Solution 1 - Webpack

You can use the DefinePlugin that will make your build info available inlined with your code:

Config

new webpack.DefinePlugin({
   __VERSION__: JSON.stringify('12345')
})

App code

console.log(__VERSION__);

Solution 2 - Webpack

I would do more simpler, just use npm version patch (npm-version) (no plugin required)

package.json (Example path version before building)

{
  "version": "1.0.0",
  "scripts": {
    "build": "npm version patch && node build/build.js"
  }
}

So when you run npm run build this will patch the version (1.0.0 to 1.0.1 in your package.json)


Bonus: You can also add this to your config (example config/prod.env.js)

'use strict'
const pkg = require('./package.json')
module.exports = {
  NODE_ENV: '"production"',
  VERSION: pkg.version
}

Then you can use process.env.VERSION anywhere in your our JS

Updated: Or just use process.env.npm_package_version without required to include package.json

Solution 3 - Webpack

There is a plugin to auto inject version from package.json. It can inject it into HTML, CSS, JS as a comment, but also as a value by special tag webpack-auto-inject-version.

How to:

First of all, you have to add it to your project:

npm i webpack-auto-inject-version

Then you need to set up your webpack config:

var WebpackAutoInject = require('webpack-auto-inject-version');
 
module.exports = {
    plugins: [
        new WebpackAutoInject()
    ]
}

As you want to inject it into javascript, you should add a tag inside your javascript file ( which will be changed to version during the webpack compilation )

var version = '[AIV]{version}[/AIV]';
console.log(version);

Auto increasing:

You can set it up to auto increase the version directly from webpack by:

webpack --other-webpack-settings --major

webpack --other-webpack-settings -- minor

webpack --other-webpack-settings --patch

Where --other-webpack-settings is equal to your custom line args. Simplifying - you need to att --major, --minor or --patch whenever you want to auto increase a version.

Solution 4 - Webpack

Here is my recipe, derived from the other answers to this question. This makes use of the WebpackVersionFilePlugin and execa, and works great for me right now.

Install the plugins via npm:

npm install webpack-version-file-plugin --save-dev
npm install execa --save-dev

webpack.config.js:

const WebpackVersionFilePlugin = require('webpack-version-file-plugin');
const execa = require('execa');

const gitHash = execa.sync('git', ['rev-parse', '--short', 'HEAD']).stdout;
const gitNumCommits = Number(execa.sync('git', ['rev-list', 'HEAD', '--count']).stdout);
const gitDirty = execa.sync('git', ['status', '-s', '-uall']).stdout.length > 0;

module.exports = {
// ... snip ...
plugins: [
    new WebpackVersionFilePlugin({
        packageFile: path.join(__dirname, 'package.json'),
        template: path.join(__dirname, 'version.ejs'),
        outputFile: path.join('build/ts/', 'version.json'),
        extras: {
            'githash': gitHash,
            'gitNumCommits': gitNumCommits,
            'timestamp': Date.now(),
            'dirty': gitDirty
        }
    }),
// ... snip ...

version.ejs (in project root):

{
	"name":       "<%= package.name %>",
	"buildDate":  <%= extras.timestamp %>,
	"version":    "<%= package.version %>",
	"numCommits": <%= extras.gitNumCommits %>,
	"hash":       "<%= extras.githash %>",
	"dirty":      <%= extras.dirty %>
}

So far, running this gets us a version.json file in build/ts with this content:

{
	"name":       "app name from package.json",
	"buildDate":  1518774257225,
	"version":    "2.0.1",
	"numCommits": 148,
	"hash":       "5a74b7a",
	"dirty":      false
}

The dirty flag indicates if the build included uncommitted or untracked changes.

I use TypeScript, so the following describes how to get the JSON file into my TypeScript code. If you don't have TypeScript, we have still reduced the problem to reading a JSON file. :-)

app.ts:

import * as appVersionJson from './version.json';

export const appVersion: AppVersion = <any>appVersionJson;

export interface AppVersion {
    /** application name as specified in package.json */
    readonly name: string;

    /** build timestamp in milliseconds since the epoch */
    readonly buildDate: number;

    /** application version as specified in package.json */
    readonly version: string;

    /** number of commits in the Git repo */
    readonly numCommits: number;

    /** latest Git commit hash */
    readonly hash: string;

    /** flag is set when uncommitted or untracked changes are present in the workspace */
    readonly dirty: boolean;
}

// ...snip...
// now just use it in methods, for example:
appVersion.version + '.' + appVersion.numCommits + ' (' + appVersion.hash + ')'

Alright - hope this provides some more clues on how to have good build number information available in the code. Btw, npm version is a good way to bump the version numbers, when working like this.

Solution 5 - Webpack

I have two files that I distribute that have the build number from the viewpoint of both git and npm (package.json). I'd still like to pull this into my index.template.html in a meta tag, but haven't figured that out yet (how can I make a DEFINE from file contents or a cmd output?).

For git, I use webpack-shell-plugin to make a file with the git info:

const WebpackVersionFilePlugin = require('webpack-version-file-plugin');
plugins: [
new WebpackShellPlugin({
      onBuildStart: [
        'git name-rev --name-only HEAD > dist/gitversion.txt',
        'git rev-list HEAD --count >> dist/gitversion.txt',
        'git rev-parse HEAD >> dist/gitversion.txt']
    }),

For npm, I add the npm version command ("npm version patch/minor/major") to (1) ensure there is no outstanding uncommitted changes in git - it fails if there are any and (2) update the package.json version and check it into git.

  "scripts": {
    "build": "npm run lint && npm run init && npm version patch && webpack --config webpack.config.js",

I then distribute that using poorly documented, probably buggy, WebpackVersionFilePlugin.

const WebpackVersionFilePlugin = require('webpack-version-file-plugin');
new WebpackVersionFilePlugin({
      packageFile:path.join(__dirname, 'package.json'),
      outputFile: path.join('./dist/', 'version.json')
    }),

Using this template in the top directory:

{
  "version" : {
    "name":      "<% package.name %>",
    "buildDate": "<%= currentTime %>",
    "version":   "<%= package.version %>"
  }
}

Neither "package.name" nor "name" work.

The result is two files in my ./dist/directory. gitversion.txt (branch, commit, count from head):

fmwk/feathers
9cfe791a09d3d748e8120e0628
51

and version.json:

{
  "version" : {
    "name":      "",
    "buildDate": "Fri Oct 21 2016 11:10:12 GMT+0800 (PHT)",
    "version":   "0.6.2"
  }
}

Solution 6 - Webpack

If you can get away with build version rather than code version you can grab the build date during build time and use that for your version:

webpack.config.js

const now = new Date()
const buildDate = `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()}`


module.exports = {
  ...
  plugins: [
    new webpack.EnvironmentPlugin({'BUILD_DATE': buildDate}),
  ]
  ...
}

Then anywhere in your code you'll be able to do

console.log(process.env.BUILD_DATE)

This might suffice and doesn't require types definition, modifying your CI etc...

Solution 7 - Webpack

I couldn't get this to work with TypeScript, so I helped myself by creating a file upon every compilation.

webpack.config.js

const fs = require('fs'); 
const path = require('path'); 
fs.writeFileSync(path.resolve(path.join(__dirname, 'src/version.ts')), 
`// This file is auto-generated by the build system. 
const BundleVersion = "${ new Date().toISOString().substr(0, 10) }"; 
export default BundleVersion; 
`); 

Then I just import BundleVersion from './version'; and make sure it actually gets used somewhere (console.log or exposing it somewhere), so it is not being tree-shaken out, and that's it, timestamp (or version) in the bundle, created at compilation time (straight forward from here to read the package.json and use the package version if needed).

Solution 8 - Webpack

I made a webpack loader that injects build information into an automatically generated file. You can find it on npm.

Once you install it, you can use it like this:

import buildinfo from "!webpack-plugin-buildinfo?gitHashShort&time!";
console.log(
    `MyCoolProject v${buildinfo.gitHashShort} compiled at ${new Date(
        buildinfo.time
    ).toISOString()}`
);

For more information, visit the github repo.

Solution 9 - Webpack

If you're okay with inserting the build information as a global variable directly in your index.html page, then the simplest approach may be to leverage the HtmlWebpackPlugin you're probably already using in your webpack config.

This article explains how to inject data into the index.html file at build time. You can add arbitrary data to the plugin in your webpack.config.js file like this:

plugins: [
	...
	new HtmlWebpackPlugin({
		template: "./src/index.html",
		filename: "index.html",
		info: {
			foo: "bar",
			time: new Date().toLocaleString()
		},
	})
]

In the index.html template file, you can add an escape sequence to access that data and insert it (the JSON.stringify() outputs the data as an object literal that will be evaluated as part of the script):

<script type="text/javascript">
	window.BUILD_INFO = <%= JSON.stringify(htmlWebpackPlugin.options.info, null, 2) %>;
</script>

You can then access that global variable from wherever you want in your code, like console.log("Built at ", BUILD_INFO.time);

For my use case, I just wanted to include a build timestamp as a comment in the HTML file. So I added the timestamp to the plugin object and set minify: false to prevent comments from being stripped (and which also prevents the HTML from being output on a single line).

plugins: [
	...
	new HtmlWebpackPlugin({
		...
		minify: false,
		buildTime: new Date().toLocaleString()
	})
]

This timestamp was then injected into an HTML comment like this:

<!-- Built at <%= htmlWebpackPlugin.options.buildTime %> -->

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid WoleverView Question on Stackoverflow
Solution 1 - WebpacknewtriksView Answer on Stackoverflow
Solution 2 - Webpackl2aelbaView Answer on Stackoverflow
Solution 3 - WebpackYabreeView Answer on Stackoverflow
Solution 4 - WebpackbarfuinView Answer on Stackoverflow
Solution 5 - WebpackMichael BusheView Answer on Stackoverflow
Solution 6 - WebpackMikhailView Answer on Stackoverflow
Solution 7 - WebpackfrevdView Answer on Stackoverflow
Solution 8 - WebpacksportzpikachuView Answer on Stackoverflow
Solution 9 - WebpackjdunningView Answer on Stackoverflow