So you want yourmodule.version
to follow the version in package.json but are tired of updating it manually every time the version changes? Could you just require('./package.json').version
or import { version } from './package.json'
? That works but for your client side apps, that would bundle the whole package.json and thus expose the versions of your dependencies and possibly other sensitive data too. It is usually a naughty thing to do! How to import only the version? Genversion to the rescue!
YES!!! This is the right answer. Nobody should be shipping their package.json file with their app. — Eric Jorgensen
Try it out – Integrate to your build – Command line API – Node API – Contribute – Artwork
Usage is simple:
$ cd yourmodule
$ npm install genversion
$ npx genversion version.js
Voilà! The new version.js
:
// Generated by genversion.
module.exports = '1.2.3'
Use flags to match your coding style. $ genversion --esm --semi version.js
creates:
// Generated by genversion.
export const version = '1.2.3';
Need more data? Try $ genversion --property name,version version.js
:
// Generated by genversion.
exports.name = 'yourmodule';
exports.version = '1.2.3';
Node API is also available:
> const gv = require('genversion')
> gv.generate('lib/version.js', { useSemicolon: true }, (err) => { ... })
See API documentation below for details.
The following describes the basic way to use genversion as a part of your workflow. See Advanced integration for alternative ways that might suit you better.
First install via npm.
$ npm install genversion --save-dev
Genversion works by reading the current version from your package.json and then generating a module file that exports the version tag. For clarity, the file begins with a signature that tells both genversion and human readers that the file may be overwritten in future:
// Generated by genversion.
module.exports = '1.2.3'
Therefore, your job is to 1) choose a target path for the module file, 2) import the new module into your project, and 3) add genversion to your build or release pipeline. For example, let us choose the path lib/version.js
and expose it via yourmodule/index.js
as follows:
...
exports.version = require('./lib/version')
If your project uses ECMAScript modules, you need to call genversion with --esm
. In this case expose the version in yourmodule/index.js
like this:
...
import { version } from './lib/version'
export const version
Then, let's add genversion into your build pipeline in package.json
for example like this:
"scripts": {
"build": "genversion lib/version.js && other build stuff"
}
Altenatively, you might prefer adding genversion as a script and run it only upon a release:
"scripts": {
...
"gv": "genversion lib/version.js",
"release": "npm run gv && npm run build && npm test && npm publish"
}
If you use npm version for your version increments and like to run genversion as a postversion
script, see advanced integration.
Finished! Now your module has a version property that matches with your package.json and is updated every time you build or release the project.
> var yourmodule = require('yourmodule')
> yourmodule.version
'1.2.3'
Great! Having a version property in your module is very convenient for debugging. More than once we have painstakingly debugged a module, just to find out that it was a cached old version that caused the error. An inspectable version property would have helped a big time.
Directly from $ genversion --help
:
Usage: genversion [options] <target>
Generates a version module at the target filepath.
Options:
-s, --semi use semicolons in generated code
-d, --double use double quotes in generated code
-b, --backtick use backticks in generated code
-e, --esm use ESM exports in generated code
--es6 alias for --esm flag
-u, --strict add "use strict" in generated code
-c, --check-only check if target is up to date
-f, --force force file rewrite upon generation
-p, --source <path> search for package.json along a custom path
-P, --property <key> select properties; default is "version"
-t, --template <path> generate with a custom template
--template-engine <name> select template engine; default is "ejs"
-v, --verbose increased output verbosity
-V, --version output genversion's own version
-h, --help display help for command
The target
path is given as the first argument after options. If the file already exists and has been previously created by genversion, it will be replaced. If the file exists but it looks like it was not created by genversion, you will see a warning, genversion exits with the exit code 1, and the file stays untouched unless you use --force
.
End each generated line of code with a semicolon as required by some style guides.
Use double quotes "
instead of single quotes '
as required by some style guides.
Use backticks `
instead of single '
or double "
quotes as required by some style guides.
Use ECMAScript module export statement syntax export const
instead of module.exports
in the generated code. Prefer --esm
because --es6
might be deprecated in future.
Prepend each generated file with 'use strict'
as required by some style guides.
When --check-only
flag is used, only the existence and validity of the version module is checked. No files are generated or modified. The flag is useful for pre-commit hooks and similar.
The command exits with the exit code:
0
if the version module is found and is exactly as freshly generated.1
if the version module cannot be found.2
if the version module is found but needs a refresh. This exit code can occur after version increment or when the version module formatting has changed. Also, if a version module is found but is not made by genversion, the command will exit with this exit code.
The command with --check-only
does not produce any output by default. Use -v
to increase its verbosity.
Force rewrite of possibly pre-existing file at the target path. Otherwise genversion will rewrite the file only if it looks like it was created by genversion.
By default, genversion finds and reads package.json
nearest to the target path. In case your package.json
is located somewhere else or you have multiple package.json
files along the path, you can select the one with --source <path>
parameter.
Select which property or properties will be picked from package.json and inserted into the generated module. Specify multiple properties with a comma separated list without spaces, for example -P name,version
. Note that with two or more properties and without --esm
flag the module is generated with exports
instead of module.exports
.
Use a custom template instead of the default template when generating the module. The template is called with two parameters pkg
and options
where the former is an object containing a set of properties picked from package.json and the latter is an object containing the formatting options. The template is free to respect or neglect the parameters provided.
For example, consider the following template.ejs
:
export default '<%= pkg.version %>';
Calling genversion --template template.ejs lib/version.js
would generate:
export default '1.2.3';
Use --properties
to control which package properties will be passed to the template in pkg
object. Only version
is passed by default.
The default template engine is EJS. You can select another templating engine with --template-engine
, given that genversion supports it.
Select which template engine to use in order to process the template file selected with --template
. Supported template engines are: ejs
.
By default, genversion prints output only upon a warning or error. Use -v
to increase verbosity.
Output the genversion's own version tag.
You can also use genversion within your code:
const gv = require('genversion');
The available properties and functions are listed below.
Check if it is possible to generate the version module into targetPath
. Check also does the file need an update.
Parameters:
- targetPath: string. An absolute or relative file path. Relative to
process.cwd()
. - opts: optional options. Available keys are:
- properties: optional array of strings. These properties will be picked from
package.json
and rendered. Defaults to['version']
. - source: optional string. An absolute or relative path to a file or directory. Genversion searches for the source package.json along this path. Defaults to the value of
targetPath
. - template: optional string. An absolute or relative path to a custom template file.
- templateEngine: optional string. Defaults to
ejs
. - useSemicolon: optional boolean. Defaults to
false
. - useDoubleQuotes: optional boolean. Defaults to
false
. - useBackticks: optional boolean. Defaults to
false
. - useEs6Syntax: deprecated alias of
useEsmSyntax
. - useEsmSyntax: optional boolean. Use ECMAScript modules. Defaults to
false
. - useStrict: optional boolean. Defaults to
false
.
- properties: optional array of strings. These properties will be picked from
- callback: function (err, doesExist, isByGenversion, isUpToDate), where:
- doesExist: boolean. True if a file at targetPath already exists.
- isByGenversion: boolean. True if the existing file seems like it has been generated by genversion.
- isUpToDate: boolean. True if the existing file contents are exactly as freshly generated.
Example:
gv.check('lib/version.js', function (err, doesExist, isByGv, isUpToDate) {
if (err) {
throw err;
}
if (isByGenversion) {
gv.generate(...)
}
...
});
Read the version property from the nearest package.json
along the targetPath
and then generate a version module file at targetPath
. A custom path to package.json
can be specified with opts.source
.
Parameters:
- targetPath: string. An absolute or relative file path. Relative to
process.cwd()
. - opts: optional options. Available keys are:
- properties: optional array of strings. These properties will be picked from
package.json
and rendered. Defaults to['version']
. - source: optional string. An absolute or relative path to a file or directory. Genversion searches for the source package.json along this path. Defaults to the value of
targetPath
. - template: optional string. An absolute or relative path to a custom template file.
- templateEngine: optional string. Defaults to
ejs
. - useSemicolon: optional boolean. Defaults to
false
. - useDoubleQuotes: optional boolean. Defaults to
false
. - useBackticks: optional boolean. Defaults to
false
. - useEs6Syntax: deprecated alias of
useEsmSyntax
. - useEsmSyntax: optional boolean. Use ECMAScript modules. Defaults to
false
. - useStrict: optional boolean. Defaults to
false
.
- properties: optional array of strings. These properties will be picked from
- callback: function (err, version). Parameter version is the version string read from
package.json
. Parameter err is non-null ifpackage.json
cannot be found, its version is not a string, or writing the version module fails.
Examples:
gv.generate('lib/version.js', function (err, version) {
if (err) {
throw err;
}
console.log('Sliding into', version, 'like a sledge.');
});
gv.generate('src/v.js', { useSemicolon: true }, (err) => {
if (err) { throw err }
console.log('Generated version file with a semicolon.')
})
This property is a string that contains genversion's own version tag in semantic versioning format. Generated with genversion itself, of course ;)
Following projects are using genversion and can work as examples of how to integrate genversion to your project.
Do you use genversion in your project? We are happy to mention it in the list. Just hit us with an issue or a pull request.
If genversion fails to fit your use case, you might want to check out the following projects by others.
- versiony for version increments
- package-json-versionify for browserify builds
- browserify-versionify for browserify builds
- semantic-release for automatic version increments
- semver for semantic version formatting
Pull requests and bug reports are highly appreciated.
Clone the repository:
$ git clone git@github.com:axelpale/genversion.git
Install development tooling:
$ cd genversion; npm install
Please test your contribution. Run the test suite:
$ npm run test
Run only linter:
$ npm run lint
Thank you.
If you are about to contribute using VS Code editor, you might want to configure VS Code debugger for genversion development. Create a file .vscode/launch.json
with the following contents and adjust args
to your liking:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/bin/genversion.js",
"args": [
"--semi",
"--double",
"--esm",
"--strict",
"--verbose",
"target.js"
]
}
]
}
Consider the following tips to further integrate genversion to your workflow.
You might already use the npm version <major/minor/patch>
command to increase your package version and automatically commit the change to the version control. If so, you can integrate genversion to this workflow by hooking to a postversion
script that will be executed whenever you run the npm version
. Here are the steps to do this:
- Install genversion as a dev dependency
- Create a
postversion.sh
file with the following contents:
#!/bin/sh
lastTag=$(git describe --exact-match --abbrev=0)
genversion lib/version.js
git add lib/version.js
git commit --amend --no-edit
git tag -fa $lastTag -m $lastTag
- Run
chmod +x postversion.sh
to make the script executable - Assign this script as the "postversion" script in
package.json
{
...
"scripts": {
"postversion": "./postversion.sh"
...
}
}
Then, when you run npm version major/minor/patch
, genversion is automatically called and correctly amends the version commit as well.
The genversion source code is released under MIT license.
Free Creative Commons Attribution CC-BY artwork (c) Akseli Palén, Tarina Palén. The star pattern is made with Sprinkler.js. The font is Bitstream Vera Sans Mono.
We are made of starstuff. — Carl Sagan