genversion
A CLI and Node API that generates a version module from package.json, so client bundles never need to ship the whole file.
Repository Health
Technical Analysis
genversion is a small build-time tool that solves a common problem: keeping a module’s exposed version string in sync with package.json without requiring require('./package.json') in client-side bundles, which would leak dependency versions and other metadata publicly. It reads selected properties (by default just version) from the nearest package.json and writes a plain JavaScript module that can be imported directly.
The generated file starts with a recognizable signature line so genversion can safely detect whether it created a file before overwriting it, preventing accidental clobbering of hand-written code. It supports CommonJS and ESM output, single/double/backtick quote styles, optional semicolons and a ‘use strict’ header, custom EJS templates, and a --check-only mode for CI or pre-commit hooks that verifies the version file is current without writing to disk.
What You Get
- CLI generator -
npx genversion <target>writes a version module in one command, ready to wire into build or release scripts. - Node API -
generate()andcheck()functions let you script version-file creation and validation programmatically. - Safe overwrite detection - generated files carry a signature comment so genversion refuses to clobber a file it didn’t create, unless
--forceis passed. - Format flexibility - flags for semicolons, quote style (single/double/backtick), ESM vs CommonJS exports, and a custom EJS template for the output shape.
- CI-friendly check mode -
--check-onlyexits non-zero when the version file is missing or stale, without writing anything, for pre-commit hooks or CI gates.
Common Use Cases
- Client-side bundles - front-end libraries expose
.versionwithout shipping the full package.json (and its dependency list) to the browser. - Build pipeline integration -
npm run buildcalls genversion first so every build embeds the current version string. - Pre-commit / CI verification -
--check-onlyruns in CI to catch a version file that wasn’t regenerated after a version bump. - Custom output shape - projects with non-standard export conventions supply their own EJS template via
--template.
Under The Hood
Architecture
The standalone CLI (bin/genversion.js, built on commander) delegates to a small library organized as a single-responsibility pipeline: dryRun.js validates options and resolves the target package.json via pickPackage.js (wrapping the find-package dependency), then renders content through the default template.js or a custom template loaded by getTemplate.js via EJS; generate.js and check.js layer file IO (write vs. read-and-compare) on top of the shared dryRun() result. There’s no class hierarchy or DI container - just plain function exports required directly - so the dryRun() return shape (absoluteTargetPath, generatedContent, version) is the one abstraction both the write path and the check path depend on.
Tech Stack
Plain JavaScript targeting Node >=10, using commander 7 for CLI argument parsing, ejs 3 for default and custom template rendering, and find-package 1.x to resolve the nearest package.json along a given path. Tests run on mocha 8 with should.js assertions and fs-extra for fixture setup/teardown; linting uses the zero-config standard style checker rather than a hand-rolled ESLint config. GitHub Actions runs the test suite across a Node 10-18 matrix on every push.
Code Quality
A dedicated test/ directory splits API tests (api.test.js) from CLI tests (cli.test.js) with supporting fixtures, and npm test runs standard (lint) followed by mocha. Error handling is consistently Node-style err-first callbacks propagated up from dryRun.js; there is no TypeScript or runtime type validation, with JSDoc-style comments documenting parameters instead. Naming is consistent camelCase throughout, and CI verifies the suite passes across five Node major versions, though no code-coverage tooling is visible.
API Design
The underlying idea, generating a plain importable file instead of requiring the whole package.json, is a well-known, narrow trick rather than something novel, but it’s executed with unusually thorough developer experience: the CLI exposes nearly every stylistic knob a downstream project might need (semicolons, quote style, ESM vs CommonJS, custom templates and template engines), and check()/--check-only distinguishes “file doesn’t exist” from “file exists but wasn’t generated by genversion” from “file is stale”, a careful safety detail that avoids silently overwriting hand-edited code. Getting started requires exactly one CLI invocation with zero configuration.