Renaming file by using Node Package Version [duplicate] - javascript

Is there a way to get the version set in package.json in a nodejs app? I would want something like this
var port = process.env.PORT || 3000
app.listen port
console.log "Express server listening on port %d in %s mode %s", app.address().port, app.settings.env, app.VERSION

I found that the following code fragment worked best for me. Since it uses require to load the package.json, it works regardless of the current working directory.
var pjson = require('./package.json');
console.log(pjson.version);
A warning, courtesy of #Pathogen:
Doing this with Browserify has security implications.
Be careful not to expose your package.json to the client, as it means that all your dependency version numbers, build and test commands and more are sent to the client.
If you're building server and client in the same project, you expose your server-side version numbers too.
Such specific data can be used by an attacker to better fit the attack on your server.

If your application is launched with npm start, you can simply use:
process.env.npm_package_version
See package.json vars for more details.

Using ES6 modules you can do the following:
import {version} from './package.json';

Or in plain old shell:
$ node -e "console.log(require('./package.json').version);"
This can be shortened to
$ node -p "require('./package.json').version"

There are two ways of retrieving the version:
Requiring package.json and getting the version:
const { version } = require('./package.json');
Using the environment variables:
const version = process.env.npm_package_version;
Please don't use JSON.parse, fs.readFile, fs.readFileSync and don't use another npm modules it's not necessary for this question.

For those who look for a safe client-side solution that also works on server-side, there is genversion. It is a command-line tool that reads the version from the nearest package.json and generates an importable CommonJS module file that exports the version. Disclaimer: I'm a maintainer.
$ genversion lib/version.js
I acknowledge the client-side safety was not OP's primary intention, but as discussed in answers by Mark Wallace and aug, it is highly relevant and also the reason I found this Q&A.

Here is how to read the version out of package.json:
fs = require('fs')
json = JSON.parse(fs.readFileSync('package.json', 'utf8'))
version = json.version
EDIT: Wow, this answer was originally from 2012! There are several better answers now. Probably the cleanest is:
const { version } = require('./package.json');

There is another way of fetching certain information from your package.json file namely using pkginfo module.
Usage of this module is very simple. You can get all package variables using:
require('pkginfo')(module);
Or only certain details (version in this case)
require('pkginfo')(module, 'version');
And your package variables will be set to module.exports (so version number will be accessible via module.exports.version).
You could use the following code snippet:
require('pkginfo')(module, 'version');
console.log "Express server listening on port %d in %s mode %s", app.address().port, app.settings.env, module.exports.version
This module has very nice feature - it can be used in any file in your project (e.g. in subfolders) and it will automatically fetch information from your package.json. So you do not have to worry where you package.json is.
I hope that will help.

NPM one liner:
From npm v7.20.0:
npm pkg get version
Prior to npm v7.20.0:
npm -s run env echo '$npm_package_version'
Note the output is slightly different between these two methods: the former outputs the version number surrounded by quotes (i.e. "1.0.0"), the latter without (i.e. 1.0.0).
One solution to remove the quotes in Unix is using xargs
npm pkg get version | xargs echo

Option 1
Best practice is to version from package.json using npm environment variables.
process.env.npm_package_version
more information on: https://docs.npmjs.com/using-npm/config.html
This will work only when you start your service using NPM command.
Quick Info: you can read any values in pacakge.json using process.env.npm_package_[keyname]
Option 2
Setting version in environment variable using https://www.npmjs.com/package/dotenv as .env file and reading it as process.env.version

Just adding an answer because I came to this question to see the best way to include the version from package.json in my web application.
I know this question is targetted for Node.js however, if you are using Webpack to bundle your app just a reminder the recommended way is to use the DefinePlugin to declare a global version in the config and reference that. So you could do in your webpack.config.json
const pkg = require('../../package.json');
...
plugins : [
new webpack.DefinePlugin({
AppVersion: JSON.stringify(pkg.version),
...
And then AppVersion is now a global that is available for you to use. Also make sure in your .eslintrc you ignore this via the globals prop

If you are looking for module (package.json: "type": "module") (ES6 import) support, e.g. coming from refactoring commonJS, you should (at the time of writing) do either:
import { readFile } from 'fs/promises';
const pkg = JSON.parse(await readFile(new URL('./package.json', import.meta.url)));
console.log(pkg.version)
or, run the node process with node --experimental-json-modules index.js to do:
import pkg from './package.json'
console.log(pkg.version)
You will however get a warning, until json modules will become generally available.
If you get Syntax or (top level) async errors, you are likely in a an older node version. Update to at least node#14.

You can use ES6 to import package.json to retrieve version number and output the version on console.
import {name as app_name, version as app_version} from './path/to/package.json';
console.log(`App ---- ${app_name}\nVersion ---- ${app_version}`);

A safe option is to add an npm script that generates a separate version file:
"scripts": {
"build": "yarn version:output && blitz build",
"version:output": "echo 'export const Version = { version: \"'$npm_package_version.$(date +%s)'\" }' > version.js"
}
This outputs version.js with the contents:
export const Version = { version: "1.0.1.1622225484" }

To determine the package version in node code, you can use the following:
const version = require('./package.json').version; for < ES6 versions
import {version} from './package.json'; for ES6 version
const version = process.env.npm_package_version;
if application has been started using npm start, all npm_* environment variables become available.
You can use following npm packages as well - root-require, pkginfo, project-version.

we can read the version or other keys from package.json in two ways
1- using require and import the key required e.g:
const version = require('./package.json')
2 - using package_vars as mentioned in doc
process.env.npm_package_version

You can use the project-version package.
$ npm install --save project-version
Then
const version = require('project-version');
console.log(version);
//=> '1.0.0'
It uses process.env.npm_package_version but fallback on the version written in the package.json in case the env var is missing for some reason.

Why don't use the require resolve...
const packageJson = path.dirname(require.resolve('package-name')) + '/package.json';
const { version } = require(packageJson);
console.log('version', version)
With this approach work for all sub paths :)

In case you want to get version of the target package.
import { version } from 'TARGET_PACKAGE/package.json';
Example:
import { version } from 'react/package.json';

I know this isn't the intent of the OP, but I just had to do this, so hope it helps the next person.
If you're using docker-compose for your CI/CD process, you can get it this way!
version:
image: node:7-alpine
volumes:
- .:/usr/src/service/
working_dir: /usr/src/service/
command: ash -c "node -p \"require('./package.json').version.replace('\n', '')\""
for the image, you can use any node image. I use alpine because it is the smallest.

The leanest way I found:
const { version } = JSON.parse(fs.readFileSync('./package.json'))

I've actually been through most of the solutions here and they either did not work on both Windows and Linux/OSX, or didn't work at all, or relied on Unix shell tools like grep/awk/sed.
The accepted answer works technically, but it sucks your whole package.json into your build and that's a Bad Thing that only the desperate should use temporarily to get unblocked, and in general should be avoided, at least for production code. The alternative is to use that method only to write the version to a single constant that can be used instead of the whole file.
So for anyone else looking for a cross-platform solution (not reliant on Unix shell commands) and local (without external dependencies):
Since it can be assumed that Node.js is installed, and it's already cross-platform for this, I just created a make_version.js file with:
const PACKAGE_VERSION = require("./package.json").version;
console.log(`export const PACKAGE_VERSION = "${PACKAGE_VERSION}";`);
console.error("package.json version:", PACKAGE_VERSION);
and added a version command to package.json:
scripts: {
"version": "node make_version.js > src/version.js",
and then added:
"prebuild": "npm run version",
"prestart": "npm run version",
and it creates a new src/versions.js on every start or build. Of course this can be easily tuned in the version script to be a different location, or in the make_version.js file to output different syntax and constant name, etc.

I do this with findup-sync:
var findup = require('findup-sync');
var packagejson = require(findup('package.json'));
console.log(packagejson.version); // => '0.0.1'

I am using gitlab ci and want to automatically use the different versions to tag my docker images and push them. Now their default docker image does not include node so my version to do this in shell only is this
scripts/getCurrentVersion.sh
BASEDIR=$(dirname $0)
cat $BASEDIR/../package.json | grep '"version"' | head -n 1 | awk '{print $2}' | sed 's/"//g; s/,//g'
Now what this does is
Print your package json
Search for the lines with "version"
Take only the first result
Replace " and ,
Please not that i have my scripts in a subfolder with the according name in my repository. So if you don't change $BASEDIR/../package.json to $BASEDIR/package.json
Or if you want to be able to get major, minor and patch version I use this
scripts/getCurrentVersion.sh
VERSION_TYPE=$1
BASEDIR=$(dirname $0)
VERSION=$(cat $BASEDIR/../package.json | grep '"version"' | head -n 1 | awk '{print $2}' | sed 's/"//g; s/,//g')
if [ $VERSION_TYPE = "major" ]; then
echo $(echo $VERSION | awk -F "." '{print $1}' )
elif [ $VERSION_TYPE = "minor" ]; then
echo $(echo $VERSION | awk -F "." '{print $1"."$2}' )
else
echo $VERSION
fi
this way if your version was 1.2.3. Your output would look like this
$ > sh ./getCurrentVersion.sh major
1
$> sh ./getCurrentVersion.sh minor
1.2
$> sh ./getCurrentVersion.sh
1.2.3
Now the only thing you will have to make sure is that your package version will be the first time in package.json that key is used otherwise you'll end up with the wrong version

I'm using create-react-app and I don't have process.env.npm_package_version available when executing my React-app.
I did not want to reference package.json in my client-code (because of exposing dangerous info to client, like package-versions), neither I wanted to install an another dependency (genversion).
I found out that I can reference version within package.json, by using $npm_package_version in my package.json:
"scripts": {
"my_build_script": "REACT_APP_VERSION=$npm_package_version react-scripts start"
}
Now the version is always following the one in package.json.

I made a useful code to get the parent module's package.json
function loadParentPackageJson() {
if (!module.parent || !module.parent.filename) return null
let dir = path.dirname(module.parent.filename)
let maxDepth = 5
let packageJson = null
while (maxDepth > 0) {
const packageJsonPath = `${dir}/package.json`
const exists = existsSync(packageJsonPath)
if (exists) {
packageJson = require(packageJsonPath)
break
}
dir = path.resolve(dir, '../')
maxDepth--
}
return packageJson
}

If using rollup, the rollup-plugin-replace plugin can be used to add the version without exposing package.json to the client.
// rollup.config.js
import pkg from './package.json';
import { terser } from "rollup-plugin-terser";
import resolve from 'rollup-plugin-node-resolve';
import commonJS from 'rollup-plugin-commonjs'
import replace from 'rollup-plugin-replace';
export default {
plugins: [
replace({
exclude: 'node_modules/**',
'MY_PACKAGE_JSON_VERSION': pkg.version, // will replace 'MY_PACKAGE_JSON_VERSION' with package.json version throughout source code
}),
]
};
Then, in the source code, anywhere where you want to have the package.json version, you would use the string 'MY_PACKAGE_JSON_VERSION'.
// src/index.js
export const packageVersion = 'MY_PACKAGE_JSON_VERSION' // replaced with actual version number in rollup.config.js

const { version } = require("./package.json");
console.log(version);
const v = require("./package.json").version;
console.log(v);

Import your package.json file into your server.js or app.js and then access package.json properties into server file.
var package = require('./package.json');
package variable contains all the data in package.json.

Used to version web-components like this:
const { version } = require('../package.json')
class Widget extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: 'open' })
}
public connectedCallback(): void {
this.renderWidget()
}
public renderWidget = (): void => {
this.shadowRoot?.appendChild(this.setPageTemplate())
this.setAttribute('version', version)
}
}

Related

How should I load package.json for a CLI app installed globally?

I created a cli application which reads its version number from package.json with this bit of code
const packageJson = JSON.parse(fs.readFileSync(path.resolve('./package.json'), 'utf8'))
This works fine if I run the app with yarn start or a similar command while development
But after the package is installed with npm install --global app-name the user should use the declare executable from any path on the system. So if I want to run it say in /Users/myUser/Desktop I get an error like this
Error: ENOENT: no such file or directory, open '/Users/myUser/Desktop/package.json'
So what's a good protocol of loading this package.json within my CLI or is there a better way for approaching this?
Later edit:
For clarity, my package json contains this
{
...
"bin": {
"clip": "./bin/clip.js"
},
...
}
so what I mean by my problem, is when I am running the executable "clip" from a different path, after I used npm publish
After some research I tried this code (use the path.dirname function):
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
export const packageJsonLocation = path.join(__dirname, './../package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonLocation, 'utf8'))
and this (just importing the file as json using node's standard import keyword)
import * as packageJson from './../package.json' assert { type: 'json' }
in both cases I get the same result, the executable generated and it tries to read package.json from the current directory. Specifically if I try to console.log() the path I get my current path where I am executing the global executable (clip in my case)
Use __dirname because it always refers to the path of the file that contains this variable, whereas ./ gives you the working directory, such as process.cwd().
const packageJson = JSON.parse(fs.readFileSync(
path.join(__dirname, 'package.json'), 'utf8')
)
If you're using ES Modules, do also to get __dirname
import { dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const packageJson = JSON.parse(fs.readFileSync(
path.join(__dirname, 'package.json'), 'utf8')
)
Edit:
You installed the package globally with a bin, but the bin you're calling with a CLI is a symlink which is inside the path <npm_glob_path>/node_modules/bin not <npm_glob_path>/node_modules/app-name/bin. The package.json of your app is inside <npm_glob_path>/node_modules/app-name. And don't use ./, always use path calls
Hence try this instead (replace app-name by your app's name):
import { dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url))
console.log('__dirname:' + __dirname) // TELL ME WHAT YOU SEE HERE WHEN YOU RUN THE CLI CMD
const packageJsonLocation = path.join(__dirname, '..', 'app-name' 'package.json')
const packageJson = JSON.parse(fs.readFileSync(
path.join(__dirname, 'package.json'), 'utf8')
)
And please, add console.log('__dirname:' + __dirname) after defining __dirname. Which path do you see when you run the CLI app?
is there a better way for approaching this?
Yes - you should store the version number in the actual package itself somewhere. This way it will always be available/accessible and there's no risk of the package.json version and the installed version becoming out of sync. For example, if someone adds your package to a project and then runs yarn install, but later uses git pull to get an up-to-date version of their local files which happens to include a version bump for your package, there is a window where the package.json has a different version number to the installed version.

react-testing-library why is toBeInTheDocument() not a function

Here is my code for a tooltip that toggles the CSS property display: block on MouseOver and on Mouse Out display: none.
it('should show and hide the message using onMouseOver and onMouseOut events respectively', () => {
const { queryByTestId, queryByText } = render(
<Tooltip id="test" message="test" />,
)
fireEvent.mouseOver(queryByTestId('tooltip'))
expect(queryByText('test')).toBeInTheDocument()
fireEvent.mouseOut(queryByTestId('tooltip'))
expect(queryByText('test')).not.toBeInTheDocument()
cleanup()
})
I keep getting the error TypeError: expect(...).toBeInTheDocument is not a function
Has anyone got any ideas why this is happening? My other tests to render and snapshot the component all work as expected. As do the queryByText and queryByTestId.
toBeInTheDocument is not part of RTL. You need to install jest-dom to enable it.
And then import it in your test files by:
import '#testing-library/jest-dom'
As mentioned by Giorgio, you need to install jest-dom. Here is what worked for me:
(I was using typescript)
npm i --save-dev #testing-library/jest-dom
Then add an import to your setupTests.ts
import '#testing-library/jest-dom/extend-expect';
Then in your jest.config.js you can load it via:
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.ts"
]
When you do npm i #testing-library/react make sure there is a setupTests.js file with the following statement in it
import '#testing-library/jest-dom/extend-expect';
Having tried all of the advice in this post and it still not working for me, I'd like to offer an alternative solution:
Install jest-dom:
npm i --save-dev #testing-library/jest-dom
Then create a setupTests.js file in the src directory (this bit is important! I had it in the root dir and this did not work...). In here, put:
import '#testing-library/jest-dom'
(or require(...) if that's your preference).
This worked for me :)
Some of the accepted answers were basically right but some may be slightly outdated:
Some references that are good for now:
https://github.com/testing-library/jest-dom
https://jestjs.io/docs/configuration
Here are the full things you need:
in the project's <rootDir> (aka where package.json and jest.config.js are), make sure you have a file called jest.config.js so that Jest can automatically pick it up for configuration. The file is in JS but is structured similarly to a package.json.
Make sure you input the following:
module.exports = {
testPathIgnorePatterns: ['<rootDir>/node_modules', '<rootDir>/dist'], // might want?
moduleNameMapper: {
'#components(.*)': '<rootDir>/src/components$1' // might want?
},
moduleDirectories: ['<rootDir>/node_modules', '<rootDir>/src'],
setupFilesAfterEnv: ['<rootDir>/src/jest-setup.ts'] // this is the KEY
// note it should be in the top level of the exported object.
};
Also, note that if you're using typescript you will need to make sure your jest-setup.ts file is compiled (so add it to src or to the list of items to compile in your tsconfig.json.
At the top of jest-setup.ts/js (or whatever you want to name this entrypoint) file: add import '#testing-library/jest-dom';.
You may also want to make sure it actually runs so put a console.log('hello, world!');. You also have the opportunity to add any global functions you'd like to have available in jest such as (global.fetch = jest.fn()).
Now you actually have to install #testing-library/jest-dom: npm i -D #testing-library/jest-dom in the console.
With those steps you should be ready to use jest-dom:
Without TS: you still need:
npm i -D #testing-library/jest-dom
Creating a jest.config.js and adding to it a minimum of: module.exports = { setupFilesAfterEnv: ['<rootDir>/[path-to-file]/jest-setup.js'] }.
Creating a [path-to-file]/jest-setup.js and adding to it: import '#testing-library/jest-dom';.
The jest-setup file is also a great place to configure tests like creating a special renderWithProvider( function or setting up global window functions.
None of the answers worked for me because I made the silly mistake of typing toBeInDocument() instead of toBeInTheDocument(). Maybe someone else did the same mistake :)
I had a hard time solving that problem so I believe it's important to note the followings if you're using CREATE REACT APP for your project:
You DO NOT need a jest.config.js file to solve this, so if you have that you can delete it.
You DO NOT need to change anything in package.json.
You HAVE TO name your jest setup file setupTests.js and have it under the src folder. It WILL NOT work if your setup file is called jest.setup.js or jest-setup.js.
install required packages
npm install --save-dev #testing-library/jest-dom eslint-plugin-jest-dom
create jest-setup.js in the root folder of your project and add
import '#testing-library/jest-dom'
in jest.config.js
setupFilesAfterEnv: ['<rootDir>/jest-setup.js']
TypeScript only, add the following to the tsconfig.json file. Also, change .js extension to .ts.
"include": ["./jest-setup.ts"]
toBeInTheDocument() and many similar functions are not part of the React-testing-library. It requires installing an additional package.
For anyone out there that like is trying to run tests in Typescript with jest and is still getting the same error even after installing #testing-library/jest-dom and following all the other answers: you probably need to install the type definitions for jest-dom (here) with:
npm i #types/testing-library__jest-dom
or
yarn add #types/testing-library__jest-dom
You need to install them as real dependencies and not as devDependency.
I was having this issue but for #testing-library/jasmine-dom rather than #testing-library/jest-dom.
The process of setup is just a tiny bit different with jasmine. You need to set up the environment in a before function in order for the matchers to be added. I think jest-dom will go ahead and add the matchers when you first import but Jasmine does not.
import { render, screen } from '#testing-library/react';
import MyComponent from './myComponent';
import JasmineDOM from '#testing-library/jasmine-dom';
describe("My Suite", function () {
beforeAll(() => {
jasmine.getEnv().addMatchers(JasmineDOM);
})
it('render my stuff', () => {
const { getByText } = render(<MyComponent />);
const ele = screen.getByText(/something/i);
expect(ele).toBeInTheDocument();
});
});
If you are using react-script then follow the below steps
Install #testing-library/jest-dom library if not done already using
npm i #testing-library/jest-dom.
Put import "#testing-library/jest-dom/extend-expect" in setUpTest.js
If you are using jest then import the library in jest.setup.js file.
the problem already was solved, but i will comment a little tip here, you don't need to create a single file called setup just for this, you just need to specify the module of the jest-dom on the setupFilesAfterEnv option in your jest configuration file.
Like this:
setupFilesAfterEnv: ['#testing-library/jest-dom/extend-expect'],
If you're using TS
You could also add a test.d.ts file to your test directory and use a triple slash directive:
///<reference types='#testing-library/jest-dom'>
Instead of doing:
expect(queryByText('test')).toBeInTheDocument()
you can find and test that it is in the document with just one line by using
let element = getByText('test');
The test will fail if the element isn't found with the getBy call.

esm does not resolve module-alias

So I'm using the package esm and module-alias, but it seems like esm does not register module-alias's paths.
Here's how I'm loading my server file:
nodemon -r esm ./src/index.js 8081
Here's the top of my index.js file:
import "module-alias/register"
import "#/setup"
import "#/setup" does not work whereas require("#/setup") does.
The problem is that esm tries to handle all import statements when parsing the file, before any other module gets loaded.
When processing import statements, it uses node's builtin require rather than the modified require created by module-alias
To fix this, you need to first load module-alias and then esm. This way, module-alias will get the chance to modify the require function before esm gets to do anything.
You can achive this by passing multiple -r parameters to node, but make sure module-alias comes first:
node -r module-alias/register -r esm index.js 8081
or with nodemon:
nodemon -r module-alias/register -r esm ./src/index.js 8081
You also need to remove the import "module-alias/register" from your code, since now it's loaded from the command line.
For me worked the following code:
package.json
"scripts": {
"dev": "pkill -f lib/serverIndex.js; NODE_ENV=development node lib/serverIndex.js",
lib/serverIndex.js
require = require('esm')(module/*, options*/);
require('module-alias/register');
module.exports = require("./server.js");
This problem has been plaguing me for years because I want to write good quality code that is shared between node & browser.
I finally found a system that works:
Place 'nesm.js' in the root of your project
[optional] Place the 'nesm' shell script in your path, make it executable
Run scripts with: 'nesm file_to_run.js' or 'node path/to/nesm.js -- file_to_run.js'
'nesm.js'
/*
* esm and module-alias do not play nicely together.
* this precise arrangement is the only way I found to make it work.
* you can run this from anywhere in your project hierarchy.
* you can use args, and use in npm scripts.
* encourage the node.js devs to make this work natively. ux matters.
* ---- CAVEATS
* will not work with "type":"module"
* ---- SETUP
* place 'nesm.js' in the root of your project
* [optional] place the 'nesm' shell script in your path, make it executable
* ---- USAGE
* > nesm file_to_run.js
* to run without the nesm shell script:
* > node path/to/nesm.js -- file_to_run.js
* to run with nodemon:
* > nodemon -- path/to/nesm.js -- file_to_run.js
*/
require = require('esm')(module); // eslint-disable-line no-global-assign
require('module-alias/register'); // must come after esm for some reason
let runNext;
for(const arg of process.argv) {
if(runNext) {
let filename = arg;
if(filename[0]!='.' && filename[0]!='/') filename = './'+filename;
require(filename);
break;
}
runNext = (arg=='--');
}
'nesm' shell script
#!/bin/bash
if [ -z $1 ]; then
echo "Node esm runner. Usage: nesm file_to_run.js"
exit 1
fi
baseDir=$( pwd )
while [ ! -f "$baseDir/nesm.js" ]; do
if [ ${#baseDir} -le 1 ]; then
echo "nesm.js not found in folder ancestry"
exit 1
fi
baseDir="$(dirname "$baseDir")"
done
file1=$(realpath $1);
node $baseDir/nesm.js -- $file1
There is another solution, initially found in this comment to solve the problem without even using module-alias.
I also made a repo to simplify this, check it here esm-module-alias

How to use in node properties for deployment and local usage

I've created node application which I can run locally and in the cloud
Now I want that it be done somehow smoother and cleaner ,so I try to put some property in config.json file to check if I want to deploy the app or use it locally but I need to update manually this property before I change the propose , there is a better way to do it with node ?
let runnerServer = `http://localhost:8060/service/runner/${server.address().port}`;
if (cfg.isHosted) {
blogServer = `http://${serverName}/service/runner/${server.address().port}`;
}
and in the conig.json I've the field isHosted which I change manually(true/false) if I want to deploy or not...
update
maybe I can use process.env.PORT but this is just one example that I need to use in my code , currently I've several of fork that need to konw if Im in deployment or running locally ..
One option is to use use node's in built object called process.env (https://nodejs.org/api/process.html) and use two config files per se. This approach is somewhat similar to what you are doing but may be cleaner
config.localhost.json
config.production.json
then by setting properties on this object based on environment such as process.env.NODE_ENV = 'localhost' or process.env.NODE_ENV = 'production', you could read the corresponding file to import the configurations.
var config = require('./config.production.json');
if(process.env.NODE_ENV === 'localhost')
{
config = require('./config.localhost.json');
}
So to set this environment variable when running locally on your dev box , if
OSX - then on terminal export NODE_ENV=localhost
WINDOWS - then on cmd line set NODE_ENV=localhost
An easy way to solve this, if every environment configuration can be in the repo:
config.json:
production: {
// prod config
},
staging: {
// staging config
},
devel: {
// devel config
}
config.js:
const environment = process.env['ENV'] || 'devel';
module.exports = require('./config.json')[environment];
then in your package.json you could add the following scripts:
package.json
// npm stuff
scripts {
prod: "ENV=production node index.js",
stage: "ENV=staging node index.js",
dev: "ENV=devel node index.js"
}
and with this setup, you can run each configuration with the following commands:
production: npm run prod
staging: npm run stage
devel: npm run dev

How to auto-reload files in Node.js?

Any ideas on how I could implement an auto-reload of files in Node.js? I'm tired of restarting the server every time I change a file.
Apparently Node.js' require() function does not reload files if they already have been required, so I need to do something like this:
var sys = require('sys'),
http = require('http'),
posix = require('posix'),
json = require('./json');
var script_name = '/some/path/to/app.js';
this.app = require('./app').app;
process.watchFile(script_name, function(curr, prev){
posix.cat(script_name).addCallback(function(content){
process.compile( content, script_name );
});
});
http.createServer(this.app).listen( 8080 );
And in the app.js file I have:
var file = require('./file');
this.app = function(req, res) {
file.serveFile( req, res, 'file.js');
}
But this also isn't working - I get an error in the process.compile() statement saying that 'require' is not defined. process.compile is evaling the app.js, but has no clue about the node.js globals.
A good, up to date alternative to supervisor is nodemon:
Monitor for any changes in your node.js application and automatically restart the server - perfect for development
To use nodemon with version of Node without npx (v8.1 and below, not advised):
$ npm install nodemon -g
$ nodemon app.js
Or to use nodemon with versions of Node with npx bundled in (v8.2+):
$ npm install nodemon
$ npx nodemon app.js
Or as devDependency in with an npm script in package.json:
"scripts": {
"start": "nodemon app.js"
},
"devDependencies": {
"nodemon": "..."
}
node-supervisor is awesome
usage to restart on save for old Node versions (not advised):
npm install supervisor -g
supervisor app.js
usage to restart on save for Node versions that come with npx:
npm install supervisor
npx supervisor app.js
or directly call supervisor in an npm script:
"scripts": {
"start": "supervisor app.js"
}
i found a simple way:
delete require.cache['/home/shimin/test2.js']
If somebody still comes to this question and wants to solve it using only the standard modules I made a simple example:
var process = require('process');
var cp = require('child_process');
var fs = require('fs');
var server = cp.fork('server.js');
console.log('Server started');
fs.watchFile('server.js', function (event, filename) {
server.kill();
console.log('Server stopped');
server = cp.fork('server.js');
console.log('Server started');
});
process.on('SIGINT', function () {
server.kill();
fs.unwatchFile('server.js');
process.exit();
});
This example is only for one file (server.js), but can be adapted to multiple files using an array of files, a for loop to get all file names, or by watching a directory:
fs.watch('./', function (event, filename) { // sub directory changes are not seen
console.log(`restart server`);
server.kill();
server = cp.fork('server.js');
})
This code was made for Node.js 0.8 API, it is not adapted for some specific needs but will work in some simple apps.
UPDATE:
This functional is implemented in my module simpleR, GitHub repo
nodemon came up first in a google search, and it seems to do the trick:
npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js
nodemon is a great one. I just add more parameters for debugging and watching options.
package.json
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon --watch server --inspect ./server/server.js"
}
The command: nodemon --watch server --inspect ./server/server.js
Whereas:
--watch server Restart the app when changing .js, .mjs, .coffee, .litcoffee, and .json files in the server folder (included subfolders).
--inspect Enable remote debug.
./server/server.js The entry point.
Then add the following config to launch.json (VS Code) and start debugging anytime.
{
"type": "node",
"request": "attach",
"name": "Attach",
"protocol": "inspector",
"port": 9229
}
Note that it's better to install nodemon as dev dependency of project. So your team members don't need to install it or remember the command arguments, they just npm run dev and start hacking.
See more on nodemon docs: https://github.com/remy/nodemon#monitoring-multiple-directories
Nodemon has been the go to for restarting server for file changes for long time. Now with Node.js 19 they have introduced a --watch flag, which does the same [experimental]. Docs
node --watch index.js
node-dev works great. npm install node-dev
It even gives a desktop notification when the server is reloaded and will give success or errors on the message.
start your app on command line with:
node-dev app.js
There is Node-Supervisor that you can install by
npm install supervisor
see http://github.com/isaacs/node-supervisor
You can use nodemon from NPM.
And if you are using Express generator then you can using this command inside your project folder:
nodemon npm start
or using Debug mode
DEBUG=yourapp:* nodemon npm start
you can also run directly
nodemon your-app-file.js
Hope this help.
There was a recent (2009) thread about this subject on the node.js mailing list. The short answer is no, it's currently not possible auto-reload required files, but several people have developed patches that add this feature.
With Node.js 19 you can monitor file changes with the --watch option. After a file is changed, the process is restarted automatically, reflecting new changes.
node --watch server.js
yet another solution for this problem is using forever
Another useful capability of Forever is that it can optionally restart
your application when any source files have changed. This frees you
from having to manually restart each time you add a feature or fix a
bug. To start Forever in this mode, use the -w flag:
forever -w start server.js
Here is a blog post about Hot Reloading for Node. It provides a github Node branch that you can use to replace your installation of Node to enable Hot Reloading.
From the blog:
var requestHandler = require('./myRequestHandler');
process.watchFile('./myRequestHandler', function () {
module.unCacheModule('./myRequestHandler');
requestHandler = require('./myRequestHandler');
}
var reqHandlerClosure = function (req, res) {
requestHandler.handle(req, res);
}
http.createServer(reqHandlerClosure).listen(8000);
Now, any time you modify myRequestHandler.js, the above code will no­tice and re­place the local re­questHandler with the new code. Any ex­ist­ing re­quests will con­tin­ue to use the old code, while any new in­com­ing re­quests will use the new code. All with­out shut­ting down the serv­er, bounc­ing any re­quests, pre­ma­ture­ly killing any re­quests, or even re­ly­ing on an in­tel­li­gent load bal­ancer.
I am working on making a rather tiny node "thing" that is able to load/unload modules at-will (so, i.e. you could be able to restart part of your application without bringing the whole app down).
I am incorporating a (very stupid) dependency management, so that if you want to stop a module, all the modules that depends on that will be stopped too.
So far so good, but then I stumbled into the issue of how to reload a module. Apparently, one could just remove the module from the "require" cache and have the job done. Since I'm not keen to change directly the node source code, I came up with a very hacky-hack that is: search in the stack trace the last call to the "require" function, grab a reference to it's "cache" field and..well, delete the reference to the node:
var args = arguments
while(!args['1'] || !args['1'].cache) {
args = args.callee.caller.arguments
}
var cache = args['1'].cache
util.log('remove cache ' + moduleFullpathAndExt)
delete( cache[ moduleFullpathAndExt ] )
Even easier, actually:
var deleteCache = function(moduleFullpathAndExt) {
delete( require.cache[ moduleFullpathAndExt ] )
}
Apparently, this works just fine. I have absolutely no idea of what that arguments["1"] means, but it's doing its job. I believe that the node guys will implement a reload facility someday, so I guess that for now this solution is acceptable too.
(btw. my "thing" will be here: https://github.com/cheng81/wirez , go there in a couple of weeks and you should see what I'm talking about)
solution at:
http://github.com/shimondoodkin/node-hot-reload
notice that you have to take care by yourself of the references used.
that means if you did : var x=require('foo'); y=x;z=x.bar; and hot reloaded
it.
it means you have to replace the references stored in x, y and z. in the hot reaload callback function.
some people confuse hot reload with auto restart
my nodejs-autorestart module also has upstart integration to enable auto start on boot.
if you have a small app auto restart is fine, but when you have a large app hot reload is more suitable. simply because hot reload is faster.
Also I like my node-inflow module.
Here's a low tech method for use in Windows. Put this in a batch file called serve.bat:
#echo off
:serve
start /wait node.exe %*
goto :serve
Now instead of running node app.js from your cmd shell, run serve app.js.
This will open a new shell window running the server. The batch file will block (because of the /wait) until you close the shell window, at which point the original cmd shell will ask "Terminate batch job (Y/N)?" If you answer "N" then the server will be relaunched.
Each time you want to restart the server, close the server window and answer "N" in the cmd shell.
my app structure:
NodeAPP (folder)
|-- app (folder)
|-- all other file is here
|-- node_modules (folder)
|-- package.json
|-- server.js (my server file)
first install reload with this command:
npm install [-g] [--save-dev] reload
then change package.json:
"scripts": {
"start": "nodemon -e css,ejs,js,json --watch app"
}
now you must use reload in your server file:
var express = require('express');
var reload = require('reload');
var app = express();
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function() {
console.log( 'server is running on port ' + app.get('port'));
});
reload(server, app);
and for last change, end of your response send this script:
<script src="/reload/reload.js"></script>
now start your app with this code:
npm start
You can do it with browser-refresh. Your node app restarts automatically, your result page in browser also refreshes automatically. Downside is that you have to put js snippet on generated page. Here's the repo for the working example.
const http = require('http');
const hostname = 'localhost';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
res.write('Simple refresh!');
res.write(`<script src=${process.env.BROWSER_REFRESH_URL}></script>`);
res.end();
})
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
if (process.send) {
process.send({ event: 'online', url: `http://${hostname}:${port}/` })
}
});
Not necessary to use nodemon or other tools like that. Just use capabilities of your IDE.
Probably best one is IntelliJ WebStorm with hot reload feature (automatic server and browser reload) for node.js.
I have tried pm2 : installation is easy and easy to use too; the result is satisfying. However, we have to take care of which edition of pm2 that we want. pm 2 runtime is the free edition, whereas pm2 plus and pm2 enterprise are not free.
As for Strongloop, my installation failed or was not complete, so I couldn't use it.
If your talking about server side NodeJS hot-reloading, lets say you wish to have an Javascript file on the server which has an express route described and you want this Javascript file to hot reload rather than the server re-starting on file change then razzle can do that.
An example of this is basic-server
https://github.com/jaredpalmer/razzle/tree/master/examples/basic-server
The file https://github.com/jaredpalmer/razzle/blob/master/examples/basic-server/src/server.js will hot-reload if it is changed and saved, the server does not re-start.
This means you can program a REST server which can hot-reload using this razzle.
it's quite simple to just do this yourself without any dependency... the built in file watcher have matured enough that it dose not sucks as much as before
you don't need any complicated child process to spawn/kill & pipe std to in/out... you just need a simple web worker, that's all! A web Worker is also what i would have used in browsers too... so stick to web techniques! worker will also log to the console
import { watch } from 'node:fs/promises'
import { Worker } from 'node:worker_threads'
let worker = new Worker('./app.js')
async function reloadOnChange (dir) {
const watcher = watch(dir, { recursive: true })
for await (const change of watcher) {
if (change.filename.endsWith('.js')) {
worker.terminate()
worker = new Worker('./app.js')
}
}
}
// All the folder to watch for
['./src', './lib', './test'].map(reloadOnChange)
this might not be the best solution where you use anything else other than javascript and do not depend on some build process.
Use this:
function reload_config(file) {
if (!(this instanceof reload_config))
return new reload_config(file);
var self = this;
self.path = path.resolve(file);
fs.watchFile(file, function(curr, prev) {
delete require.cache[self.path];
_.extend(self, require(file));
});
_.extend(self, require(file));
}
All you have to do now is:
var config = reload_config("./config");
And config will automatically get reloaded :)
loaddir is my solution for quick loading of a directory, recursively.
can return
{ 'path/to/file': 'fileContents...' }
or
{ path: { to: { file: 'fileContents'} } }
It has callback which will be called when the file is changed.
It handles situations where files are large enough that watch gets called before they're done writing.
I've been using it in projects for a year or so, and just recently added promises to it.
Help me battle test it!
https://github.com/danschumann/loaddir
You can use auto-reload to reload the module without shutdown the server.
install
npm install auto-reload
example
data.json
{ "name" : "Alan" }
test.js
var fs = require('fs');
var reload = require('auto-reload');
var data = reload('./data', 3000); // reload every 3 secs
// print data every sec
setInterval(function() {
console.log(data);
}, 1000);
// update data.json every 3 secs
setInterval(function() {
var data = '{ "name":"' + Math.random() + '" }';
fs.writeFile('./data.json', data);
}, 3000);
Result:
{ name: 'Alan' }
{ name: 'Alan' }
{ name: 'Alan' }
{ name: 'Alan' }
{ name: 'Alan' }
{ name: '0.8272748321760446' }
{ name: '0.8272748321760446' }
{ name: '0.8272748321760446' }
{ name: '0.07935990858823061' }
{ name: '0.07935990858823061' }
{ name: '0.07935990858823061' }
{ name: '0.20851597073487937' }
{ name: '0.20851597073487937' }
{ name: '0.20851597073487937' }
another simple solution is to use fs.readFile instead of using require
you can save a text file contaning a json object, and create a interval on the server to reload this object.
pros:
no need to use external libs
relevant for production (reloading config file on change)
easy to implement
cons:
you can't reload a module - just a json containing key-value data
For people using Vagrant and PHPStorm, file watcher is a faster approach
disable immediate sync of the files so you run the command only on save then create a scope for the *.js files and working directories and add this command
vagrant ssh -c "/var/www/gadelkareem.com/forever.sh restart"
where forever.sh is like
#!/bin/bash
cd /var/www/gadelkareem.com/ && forever $1 -l /var/www/gadelkareem.com/.tmp/log/forever.log -a app.js
I recently came to this question because the usual suspects were not working with linked packages. If you're like me and are taking advantage of npm link during development to effectively work on a project that is made up of many packages, it's important that changes that occur in dependencies trigger a reload as well.
After having tried node-mon and pm2, even following their instructions for additionally watching the node_modules folder, they still did not pick up changes. Although there are some custom solutions in the answers here, for something like this, a separate package is cleaner. I came across node-dev today and it works perfectly without any options or configuration.
From the Readme:
In contrast to tools like supervisor or nodemon it doesn't scan the filesystem for files to be watched. Instead it hooks into Node's require() function to watch only the files that have been actually required.
const cleanCache = (moduleId) => {
const module = require.cache[moduleId];
if (!module) {
return;
}
// 1. clean parent
if (module.parent) {
module.parent.children.splice(module.parent.children.indexOf(module), 1);
}
// 2. clean self
require.cache[moduleId] = null;
};

Categories