Create relative symlinks using absolute paths in Node.JS - node.js

I have a projects with the following structure:
project-root
├── some-dir
│   ├── alice.json
│   ├── bob.json
│   └── dave.json
└── ...
I want to create symlinks like the following ones:
foo -> alice.json
I chose to use the fs.symlink function:
fs.symlink(srcpath, dstpath[, type], callback)
Asynchronous symlink(2). No arguments other than a possible exception are given to the completion callback. The type argument can be set to 'dir', 'file', or 'junction' (default is 'file') and is only available on Windows (ignored on other platforms). Note that Windows junction points require the destination path to be absolute. When using 'junction', the destination argument will automatically be normalized to absolute path.
So, I did:
require("fs").symlink(
projectRoot + "/some-dir/alice.json"
, projectRoot + "/some-dir/foo"
, function (err) { console.log(err || "Done."); }
);
This creates the foo symlink. However, since the paths are absolute the symlink uses absolute path as well.
How can I make the symlink path relative to a directory (in this case to some-dir)?
This will prevent errors when the parent directories are renamed or the project is moved on another machine.
The dirty alternative I see is using exec("ln -s alice.json foo", { cwd: pathToSomeDir }, callback);, but I would like to avoid that and use the NodeJS API.
So, how can I make relative symlinks using absolute paths in NodeJS?

Option 1: Use process.chdir() to change the current working directory of the process to projectRoot. Then, provide relative paths to fs.symlink().
Option 2: Use path.relative() or otherwise generate the relative path between your symlink and its target. Pass that relative path as the first argument to fs.symlink() while providing an absolute path for the second argument. For example:
var relativePath = path.relative('/some-dir', '/some-dir/alice.json');
fs.symlink(relativePath, '/some-dir/foo', callback);

const path = require('path');
const fs = require('fs');
// The actual symlink entity in the file system
const source = /* absolute path of source */;
// Where the symlink should point to
const absolute_target = /* absolute path of target */;
const target = path.relative(
path.dirname(source),
absolute_target
);
fs.symlink(
target,
source,
(err) => {
}
);

Related

How to create file on the project that installed your package? [duplicate]

Is there a different way, other than process.cwd(), to get the pathname of the current project's root-directory. Does Node implement something like ruby's property, Rails.root,. I'm looking for something that is constant, and reliable.
There are many ways to approach this, each with their own pros and cons:
require.main.filename
From http://nodejs.org/api/modules.html:
When a file is run directly from Node, require.main is set to its module. That means that you can determine whether a file has been run directly by testing require.main === module
Because module provides a filename property (normally equivalent to __filename), the entry point of the current application can be obtained by checking require.main.filename.
So if you want the base directory for your app, you can do:
const { dirname } = require('path');
const appDir = dirname(require.main.filename);
Pros & Cons
This will work great most of the time, but if you're running your app with a launcher like pm2 or running mocha tests, this method will fail. This also won't work when using Node.js ES modules, where require.main is not available.
module.paths
Node publishes all the module search paths to module.paths. We can traverse these and pick the first one that resolves.
async function getAppPath() {
const { dirname } = require('path');
const { constants, promises: { access } } = require('fs');
for (let path of module.paths) {
try {
await access(path, constants.F_OK);
return dirname(path);
} catch (e) {
// Just move on to next path
}
}
}
Pros & Cons
This will sometimes work, but is not reliable when used in a package because it may return the directory that the package is installed in rather than the directory that the application is installed in.
Using a global variable
Node has a global namespace object called global — anything that you attach to this object will be available everywhere in your app. So, in your index.js (or app.js or whatever your main app
file is named), you can just define a global variable:
// index.js
var path = require('path');
global.appRoot = path.resolve(__dirname);
// lib/moduleA/component1.js
require(appRoot + '/lib/moduleB/component2.js');
Pros & Cons
Works consistently, but you have to rely on a global variable, which means that you can't easily reuse components/etc.
process.cwd()
This returns the current working directory. Not reliable at all, as it's entirely dependent on what directory the process was launched from:
$ cd /home/demo/
$ mkdir subdir
$ echo "console.log(process.cwd());" > subdir/demo.js
$ node subdir/demo.js
/home/demo
$ cd subdir
$ node demo.js
/home/demo/subdir
app-root-path
To address this issue, I've created a node module called app-root-path. Usage is simple:
const appRoot = require('app-root-path');
const myModule = require(`${ appRoot }/lib/my-module.js`);
The app-root-path module uses several techniques to determine the root path of the app, taking into account globally installed modules (for example, if your app is running in /var/www/ but the module is installed in ~/.nvm/v0.x.x/lib/node/). It won't work 100% of the time, but it's going to work in most common scenarios.
Pros & Cons
Works without configuration in most circumstances. Also provides some nice additional convenience methods (see project page). The biggest con is that it won't work if:
You're using a launcher, like pm2
AND, the module isn't installed inside your app's node_modules directory (for example, if you installed it globally)
You can get around this by either setting a APP_ROOT_PATH environmental variable, or by calling .setPath() on the module, but in that case, you're probably better off using the global method.
NODE_PATH environmental variable
If you're looking for a way to determine the root path of the current app, one of the above solutions is likely to work best for you. If, on the other hand, you're trying to solve the problem of loading app modules reliably, I highly recommend looking into the NODE_PATH environmental variable.
Node's Modules system looks for modules in a variety of locations. One of these locations is wherever process.env.NODE_PATH points. If you set this environmental variable, then you can require modules with the standard module loader without any other changes.
For example, if you set NODE_PATH to /var/www/lib, the the following would work just fine:
require('module2/component.js');
// ^ looks for /var/www/lib/module2/component.js
A great way to do this is using npm:
{
"scripts": {
"start": "NODE_PATH=. node app.js"
}
}
Now you can start your app with npm start and you're golden. I combine this with my enforce-node-path module, which prevents accidentally loading the app without NODE_PATH set. For even more control over enforcing environmental variables, see checkenv.
One gotcha: NODE_PATH must be set outside of the node app. You cannot do something like process.env.NODE_PATH = path.resolve(__dirname) because the module loader caches the list of directories it will search before your app runs.
[added 4/6/16] Another really promising module that attempts to solve this problem is wavy.
__dirname isn't a global; it's local to the current module so each file has its own local, different value.
If you want the root directory of the running process, you probably do want to use process.cwd().
If you want predictability and reliability, then you probably need to make it a requirement of your application that a certain environment variable is set. Your app looks for MY_APP_HOME (Or whatever) and if it's there, and the application exists in that directory then all is well. If it is undefined or the directory doesn't contain your application then it should exit with an error prompting the user to create the variable. It could be set as a part of an install process.
You can read environment variables in node with something like process.env.MY_ENV_VARIABLE.
1- create a file in the project root call it settings.js
2- inside this file add this code
module.exports = {
POST_MAX_SIZE : 40 , //MB
UPLOAD_MAX_FILE_SIZE: 40, //MB
PROJECT_DIR : __dirname
};
3- inside node_modules create a new module name it "settings" and inside the module index.js write this code:
module.exports = require("../../settings");
4- and any time you want your project directory just use
var settings = require("settings");
settings.PROJECT_DIR;
in this way you will have all project directories relative to this file ;)
the easiest way to get the global root (assuming you use NPM to run your node.js app 'npm start', etc)
var appRoot = process.env.PWD;
If you want to cross-verify the above
Say you want to cross-check process.env.PWD with the settings of you node.js application. if you want some runtime tests to check the validity of process.env.PWD, you can cross-check it with this code (that I wrote which seems to work well). You can cross-check the name of the last folder in appRoot with the npm_package_name in your package.json file, for example:
var path = require('path');
var globalRoot = __dirname; //(you may have to do some substring processing if the first script you run is not in the project root, since __dirname refers to the directory that the file is in for which __dirname is called in.)
//compare the last directory in the globalRoot path to the name of the project in your package.json file
var folders = globalRoot.split(path.sep);
var packageName = folders[folders.length-1];
var pwd = process.env.PWD;
var npmPackageName = process.env.npm_package_name;
if(packageName !== npmPackageName){
throw new Error('Failed check for runtime string equality between globalRoot-bottommost directory and npm_package_name.');
}
if(globalRoot !== pwd){
throw new Error('Failed check for runtime string equality between globalRoot and process.env.PWD.');
}
you can also use this NPM module: require('app-root-path') which works very well for this purpose
Simple:
require('path').resolve('./')
As simple as adding this line to your module in the root, usually it is app.js or app.ts.
global.__basedir = __dirname;
Then _basedir will be accessible to all your modules.
Note: For typescript implementation, follow the above step and then you will be able to use the root directory path using global.__basedir
I've found this works consistently for me, even when the application is invoked from a sub-folder, as it can be with some test frameworks, like Mocha:
process.mainModule.paths[0].split('node_modules')[0].slice(0, -1);
Why it works:
At runtime node creates a registry of the full paths of all loaded files. The modules are loaded first, and thus at the top of this registry. By selecting the first element of the registry and returning the path before the 'node_modules' directory we are able to determine the root of the application.
It's just one line of code, but for simplicity's sake (my sake), I black boxed it into an NPM module:
https://www.npmjs.com/package/node-root.pddivine
Enjoy!
EDIT:
process.mainModule is deprecated as of v14.0.0
Use require.main instead:
require.main.paths[0].split('node_modules')[0].slice(0, -1);
Try traversing upwards from __dirname until you find a package.json, and decide that's the app main root directory your current file belongs to.
According to Node docs
The package.json file is normally located at the root directory of a Node.js project.
const fs = require('fs')
const path = require('path')
function getAppRootDir () {
let currentDir = __dirname
while(!fs.existsSync(path.join(currentDir, 'package.json'))) {
currentDir = path.join(currentDir, '..')
}
return currentDir
}
All these "root dirs" mostly need to resolve some virtual path to a real pile path, so may be you should look at path.resolve?
var path= require('path');
var filePath = path.resolve('our/virtual/path.ext');
Preamble
This is a very old question, but it seems to hit the nerve in 2020 as much as back in 2012.
I've checked all the other answers and could not find the following technique mentioned (it has its own limitations, but the others are not applicable to every situation either):
Git + child process
If you are using Git as your version control system, the problem of determining the project root can be reduced to (which I would consider the proper root of the project - after all, you would want your VCS to have the fullest visibility scope possible):
retrieve repository root path
Since you have to run a CLI command to do that, we need to spawn a child process. Additionally, as project root is highly unlikely to change mid-runtime, we can use the synchronous version of the child_process module at startup.
I found spawnSync() to be the most suitable for the job. As for the actual command to run, git worktree (with a --porcelain option for ease of parsing) is all that is needed to retrieve the absolute path of the root.
In the sample at the end of the answer, I opted to return an array of paths because there might be multiple worktrees (although they are likely to have common paths) just to be sure. Note that as we utilize a CLI command, shell option should be set to true (security shouldn't be an issue as there is no untrusted input).
Approach comparison and fallbacks
Understanding that a situation where VCS can be inaccessible is possible, I've included a couple of fallbacks after analyzing docs and other answers. The proposed solutions boil down to (excluding third-party modules & packages):
Solution
Advantage
Main Problem
__filename
points to module file
relative to module
__dirname
points to module dir
same as __filename
node_modules tree walk
nearly guaranteed root
complex tree walking if nested
path.resolve(".")
root if CWD is root
same as process.cwd()
process.argv\[1\]
same as __filename
same as __filename
process.env.INIT_CWD
points to npm run dir
requires npm && CLI launch
process.env.PWD
points to current dir
relative to (is the) launch dir
process.cwd()
same as env.PWD
process.chdir(path) at runtime
require.main.filename
root if === module
fails on required modules
From the comparison table above, the following approaches are the most universal:
require.main.filename as an easy way to get the root if require.main === module is met
node_modules tree walk proposed recently uses another assumption:
if the directory of the module has node_modules dir inside, it is likely to be the root
For the main app, it will get the app root and for a module — its project root.
Fallback 1. Tree walk
My implementation uses a more lax approach by stopping once a target directory is found as for a given module its root is the project root. One can chain the calls or extend it to make the search depth configurable:
/**
* #summary gets root by walking up node_modules
* #param {import("fs")} fs
* #param {import("path")} pt
*/
const getRootFromNodeModules = (fs, pt) =>
/**
* #param {string} [startPath]
* #returns {string[]}
*/
(startPath = __dirname) => {
//avoid loop if reached root path
if (startPath === pt.parse(startPath).root) {
return [startPath];
}
const isRoot = fs.existsSync(pt.join(startPath, "node_modules"));
if (isRoot) {
return [startPath];
}
return getRootFromNodeModules(fs, pt)(pt.dirname(startPath));
};
Fallback 2. Main module
The second implementation is trivial:
/**
* #summary gets app entry point if run directly
* #param {import("path")} pt
*/
const getAppEntryPoint = (pt) =>
/**
* #returns {string[]}
*/
() => {
const { main } = require;
const { filename } = main;
return main === module ?
[pt.parse(filename).dir] :
[];
};
Implementation
I would suggest using the tree walker as the preferred fallback because it is more versatile:
const { spawnSync } = require("child_process");
const pt = require('path');
const fs = require("fs");
/**
* #summary returns worktree root path(s)
* #param {function : string[] } [fallback]
* #returns {string[]}
*/
const getProjectRoot = (fallback) => {
const { error, stdout } = spawnSync(
`git worktree list --porcelain`,
{
encoding: "utf8",
shell: true
}
);
if (!stdout) {
console.warn(`Could not use GIT to find root:\n\n${error}`);
return fallback ? fallback() : [];
}
return stdout
.split("\n")
.map(line => {
const [key, value] = line.split(/\s+/) || [];
return key === "worktree" ? value : "";
})
.filter(Boolean);
};
Disadvantages
The most obvious one is having Git installed and initialized which might be undesirable/implausible (side note: having Git installed on production servers is not uncommon, nor is it unsafe). Can be mediated by fallbacks as described above.
There is an INIT_CWD property on process.env. This is what I'm currently working with in my project.
const {INIT_CWD} = process.env; // process.env.INIT_CWD
const paths = require(`${INIT_CWD}/config/paths`);
Good Luck...
A technique that I've found useful when using express is to add the following to app.js before any of your other routes are set
// set rootPath
app.use(function(req, res, next) {
req.rootPath = __dirname;
next();
});
app.use('/myroute', myRoute);
No need to use globals and you have the path of the root directory as a property of the request object.
This works if your app.js is in the root of your project which, by default, it is.
Actually, i find the perhaps trivial solution also to most robust:
you simply place the following file at the root directory of your project: root-path.js which has the following code:
import * as path from 'path'
const projectRootPath = path.resolve(__dirname)
export const rootPath = projectRootPath
Add this somewhere towards the start of your main app file (e.g. app.js):
global.__basedir = __dirname;
This sets a global variable that will always be equivalent to your app's base dir. Use it just like any other variable:
const yourModule = require(__basedir + '/path/to/module.js');
Simple...
I know this one is already too late.
But we can fetch root URL by two methods
1st method
var path = require('path');
path.dirname(require.main.filename);
2nd method
var path = require('path');
path.dirname(process.mainModule.filename);
Reference Link:- https://gist.github.com/geekiam/e2e3e0325abd9023d3a3
process.mainModule is deprecated since v 14.0.0. When referring to the answer, please use require.main, the rest still holds.
process.mainModule.paths
.filter(p => !p.includes('node_modules'))
.shift()
Get all paths in main modules and filter out those with "node_modules",
then get the first of remaining path list. Unexpected behavior will not throw error, just an undefined.
Works well for me, even when calling ie $ mocha.
At top of main file add:
mainDir = __dirname;
Then use it in any file you need:
console.log('mainDir ' + mainDir);
mainDir is defined globally, if you need it only in current file - use __dirname instead.
main file is usually in root folder of the project and is named like main.js, index.js, gulpfile.js.
if you want to determine project root from a running node.js application you can simply just too.
process.mainModule.path
It work for me
process.env.PWD
This will step down the directory tree until it contains a node_modules directory, which usually indicates your project root:
const fs = require('fs')
const path = require('path')
function getProjectRoot(currentDir = __dirname.split(path.sep)) {
if (!currentDir.length) {
throw Error('Could not find project root.')
}
const nodeModulesPath = currentDir.concat(['node_modules']).join(path.sep)
if (fs.existsSync(nodeModulesPath) && !currentDir.includes('node_modules')) {
return currentDir.join(path.sep)
}
return this.getProjectRoot(currentDir.slice(0, -1))
}
It also makes sure that there is no node_modules in the returned path, as that means that it is contained in a nested package install.
Create a function in app.js
/*Function to get the app root folder*/
var appRootFolder = function(dir,level){
var arr = dir.split('\\');
arr.splice(arr.length - level,level);
var rootFolder = arr.join('\\');
return rootFolder;
}
// view engine setup
app.set('views', path.join(appRootFolder(__dirname,1),'views'));
I use this.
For my module named mymodule
var BASE_DIR = __dirname.replace(/^(.*\/mymodule)(.*)$/, '$1')
Make it sexy 💃🏻.
const users = require('../../../database/users'); // 👎 what you have
// OR
const users = require('$db/users'); // 👍 no matter how deep you are
const products = require('/database/products'); // 👍 alias or pathing from root directory
Three simple steps to solve the issue of ugly path.
Install the package: npm install sexy-require --save
Include require('sexy-require') once on the top of your main application file.
require('sexy-require');
const routers = require('/routers');
const api = require('$api');
...
Optional step. Path configuration can be defined in .paths file on root directory of your project.
$db = /server/database
$api-v1 = /server/api/legacy
$api-v2 = /server/api/v2
You can simply add the root directory path in the express app variable and get this path from the app. For this add app.set('rootDirectory', __dirname); in your index.js or app.js file. And use req.app.get('rootDirectory') for getting the root directory path in your code.
Old question, I know, however no question mention to use progress.argv. The argv array includes a full pathname and filename (with or without .js extension) that was used as parameter to be executed by node. Because this also can contain flags, you must filter this.
This is not an example you can directly use (because of using my own framework) but I think it gives you some idea how to do it. I also use a cache method to avoid that calling this function stress the system too much, especially when no extension is specified (and a file exist check is required), for example:
node myfile
or
node myfile.js
That's the reason I cache it, see also code below.
function getRootFilePath()
{
if( !isDefined( oData.SU_ROOT_FILE_PATH ) )
{
var sExt = false;
each( process.argv, function( i, v )
{
// Skip invalid and provided command line options
if( !!v && isValidString( v ) && v[0] !== '-' )
{
sExt = getFileExt( v );
if( ( sExt === 'js' ) || ( sExt === '' && fileExists( v+'.js' )) )
{
var a = uniformPath( v ).split("/");
// Chop off last string, filename
a[a.length-1]='';
// Cache it so we don't have to do it again.
oData.SU_ROOT_FILE_PATH=a.join("/");
// Found, skip loop
return true;
}
}
}, true ); // <-- true is: each in reverse order
}
return oData.SU_ROOT_FILE_PATH || '';
}
};
Finding the root path of an electron app could get tricky. Because the root path is different for the main process and renderer under different conditions such as production, development and packaged conditions.
I have written a npm package electron-root-path to capture the root path of an electron app.
$ npm install electron-root-path
or
$ yarn add electron-root-path
// Import ES6 way
import { rootPath } from 'electron-root-path';
// Import ES2015 way
const rootPath = require('electron-root-path').rootPath;
// e.g:
// read a file in the root
const location = path.join(rootPath, 'package.json');
const pkgInfo = fs.readFileSync(location, { encoding: 'utf8' });
This will do:
path.join(...process.argv[1].split(/\/|\\/).slice(0, -1))
path.dirname(process.mainModule.filename);
In modern versions of npm, you can add an entry to exports, to use as a shorthand. Note that if you want to be able to reference both the root itself and files within that root, you'll need both ./ and ./* respectively:
package.json:
{
"imports": {
"#root": "./",
"#root/*": "./*",
...
},
...
}
./index.js:
import {namedExport} from '#root/file.js'
./file.js:
export const namedExport = {
hi: "world",
};
Then:
$ node --experimental-specifier-resolution=node index.js
You could extend this further with a constants.js file, where you may use one of the methods in the above answers, or input an absolute path, should you require the path itself
You can also use
git rev-parse --show-toplevel
Assuming you are working on a git repository

Run zprint-cli recursively on multiple files in nested directories via NPM scripts

Goal: Use npm scripts to run zprint-clj on each file with the appropriate file extension in a bundle of nested folders.
zprint-clj expects a filename in and a filename out each time it's run. eg: zprint-clj -i <filein.ext> -o <fileout.ext>
I'm having difficulty understanding how to recursively run the command/script on each file with the matching file extension. The tutorials and guides I've found don't seem to deal with libraries that require specific files be typed out with the library command.
I am still new to this process, so I may be overlooking something obvious.
Short answer:
You're not overlooking something obvious. It's rather a case of the feature that you want simply doesn't exist.
Unfortunately zprint-clj does not provide an option to recursively process .clj files in a bundle of nested folders. It only accepts one input file per usage.
Perhaps you should post a request for this feature to be added in the projects GitHub repo here.
Meanwhile, to meet your requirement you could consider creating a custom node script which utilizes zprint-cli. This script can then be invoked via your npm script.
Long answer with solution:
The following demonstrates a solution to fulfill your requirement.
1. Additional packages
Firstly you'll need to cd to your project directory and install some additional packages locally via npm (Note: we'll also include references to these packages in the devDependencies section of package.json):
Install cli-glob by running:
npm i -D cli-glob
Next, install shelljs by running:
npm i -D shelljs
And, if you haven't got it installed locally already, install zprint-clj by running:
npm i -D zprint-clj
2. Custom node script
Next create a custom node script as follows. Let's name the file recursive-zprint.js and save it to a hidden directory named .scripts in the root of your project folder.
project
├─── .scripts
│ └─── recursive-zprint.js
├─── node_modules
└─── ...
recursive-zprint.js
const path = require('path');
const readline = require('readline');
const shelljs = require('shelljs');
const TICK = process.platform === 'win32' ? '√' : '✔';
var outputDir = '';
var verbose = false;
// Setup interface to read glob paths piped to stdin.
const rl = readline.createInterface({
input: process.stdin,
output: null,
terminal: false
});
// Read each line from process.stdin
// (i.e. the filepath for each .clj found via the glob pattern)
rl.on('line', function (filePath) {
formatData(filePath);
});
// Handle the optional `-o` argument for the output dir.
if (process.argv.indexOf('-o') !== -1) {
outputDir = process.argv[process.argv.indexOf('-o') + 1];
}
// Handle the optional `-v` argument for verbose logging.
if (process.argv.indexOf('-v') !== -1) {
verbose = true;
}
/**
* Gets the path to node_modules/.bin executable.
* #param {string} command - The executable name
* #returns {string} The path to the executable.
*/
function getBin(command) {
return path.join('node_modules', '.bin', command);
}
/**
* Obtains the destination path for where the formated file should be saved.
* Creates directories, and executes the zprint command . If the `-o` argument
* is not specified via the npm-script the original file is overwritten.
*
* #param {String} srcPath - The path to the source file.
*/
function formatData(srcPath) {
const destPath = getDestPath(srcPath);
makeDirectory(path.dirname(destPath));
shelljs.exec(getBin('zprint-clj') + ' -i ' + srcPath + ' -o ' + destPath);
// Log formatted filepath to console.
if (verbose) {
shelljs.echo('\x1b[32m%s\x1b[0m', TICK, destPath);
}
}
/**
* Obtains destination path for where to save the formatted file. Joins the
* source path, excluding the root directory, with the given output path.
*
* #param {String} srcPath - The path to the source file.
* #return {String} - The destination file path.
*/
function getDestPath(srcPath) {
if (outputDir) {
const parts = srcPath.split(path.sep);
parts.shift();
return path.join(outputDir, parts.join(path.sep));
}
return srcPath;
}
/**
* Create a new directory and intermediate directories if necessary.
* #param {String} dirPath - The path for the directory.
*/
function makeDirectory(dirPath) {
if (!shelljs.test('-d', dirPath)) {
shelljs.mkdir('-p', dirPath);
}
}
3. Configuring npm-scripts
Configure your npm-script as follows. Lets name the script zprint:
Overwriting the original files...`
{
...
"scripts": {
"zprint": "glob \"src/**/*.clj\" | node .scripts/recursive-zprint"
},
...
}
Note the following:
The script above utilizes cli-glob to obtain the path to each .clj file stored in the src directory many levels deep. You'll need to replace the \"src/**/*.clj\" part with a glob pattern suitable for your project.
The list of files found by the glob pattern are then piped to the custom node script (i.e. recursive-zprint.js).
All original source .clj using this configuration will be overwritten with the formatted data.
Avoid overwriting the original files...
To avoid overwriting the original .clj files recursive-zprint.js allows an optional -o argument to be passed via the script that specified the output directory.
{
...
"scripts": {
"zprint": "glob \"src/**/*.clj\" | node .scripts/recursive-zprint -o \"path/to/output\""
},
...
}
Note the following:
This example configuration includes the additonal -o argument followed by the path to where the formatted files will be saved.
If you're going to use the -o argument you'll again need to replace the \"path/to/output\" part with a suitable output path for your project.
4. Source directory vs resultant directory
Given the last npm script configuration shown (the one which utilizes the -o argument). Lets assume we have a src directory with files as follows:
project
├─── src
│ ├─── a.clj
│ ├─── x
│ │ ├─── b.clj
│ │ └─── y
│ │ └─── c.clj
│ └─── d.clj
└─── ...
Afer running npm run zprint, via your CLI, the resultant output will be as follows (Note the original source sub directories are preserved in the resultant output):
project
├─── path
│ └─── to
│ └─── output
│ ├─── a.clj
│ ├─── x
│ │ ├─── b.clj
│ │ └─── y
│ │ └─── c.clj
│ └─── d.clj
├─── src
│ └─── ... (same as before)
└─── ...
5. Verbose logging
If you want to log to the console the path of each file when it has been formatted successfully you can add the -v optional argument too. For example:
{
...
"scripts": {
"zprint": "glob \"src/**/*.clj\" | node .scripts/recursive-zprint -v -o \"path/to/output\""
},
...
}

Nodejs get absolute path relative to process.cwd()

So I have the following code block:
#!/usr/bin/env node
const path = require('path');
const yargs = require('yargs').argv;
const ghpages = require('gh-pages');
const randomstring = require("randomstring");
const dirName = randomstring.generate({
length: 12,
charset: 'alphabetic'
});
console.log(__dirname, dirName, process.cwd(), yargs.directory, yargs.branch);
ghpages.publish(path.join(process.cwd(), yargs.directory), {
branch: yargs.branch,
clone: `../../../../tmp/${dirName}`
}, () => {
console.log('removing');
});
This requires an absolute path to the clone location.
Obviously I have hard coded it at the moment for testing but what I want to do is get the absolute path to /tmp/ from the process.cwd().
So basically what I want is if I ran the script in /home/otis ../../../../tmp/${dirName} would become ../../tmp/${dirName} so I need to generate the path based on the process.cwd()
Any ideas?
Cheers/
You can use path.resolve to get the absolute path.
e.g.
path.resolve('../src/tmp')
// '/Users/yourusername/src/tmp'
Or you can use the path.relative( from, to ) which gives the relative path between from and to
So in your case, I guess it is
path.relative( process.cwd(), "../../../../tmp/" )
It's bad practice to use relative paths, especially to system folders. In case if a project location will be changed, you will have to update your code as well.
If you need the system temp directory, you can use the following:
require('os').tmpdir()
It will return you correct absolute path to your temporary folder depending on current OS.

grunt + mochaTest: Change working directory?

I`m trying to implement testing for my nodejs-project with grunt-mocha-test and have issues with different/incorrect paths.
Like I saw it elsewhere, I want to get all dependecies by just requiring my server.js.
gruntfile.js
mochaTest: {
test: {
options: {
reporter: 'spec',
require: 'app/server.js'
},
src: ['app/test/**/*.js']
}
}
My current project structure looks like this
gruntfile.js
app/server.js
app/models/..
app/controllers/..
app/tests/..
users.controller.test.js
var userCtl = require('../controllers/users.controller');
describe("return5", function () {
it("should return 5", function () {
var result = userCtl.return5(null, null);
expect(result).toBe(5);
});
});
users.controller.js
var mongoose = require('mongoose');
var User = mongoose.model('User'); // <- Mocha crash: Schema hasn't been registered for model "User".
..
In my server.js I use:
..
// config.js: https://github.com/meanjs/mean/blob/master/config/config.js
config.getGlobbedFiles('./models/**/*.js').forEach(function (path) {
require(path); // never called with mochaTest
});
..
console.log(process.cwd()); // "C:\path\project" (missing /app)
..
So the cwd is different to what it should be.
Can someone please help me getting around this issue?
I will clarify the title as soon as I know what I`m doing wrong.
Thank you.
The confusion is due to the difference between module paths and filesystem paths.
When you do require("./blah"), the . is interpreted to mean "start with the path of the current module". Since this is relative to the module you are currently in, it will resolve to different values depending on where the module is located.
When you run process.cwd() this is returning the current working directory of the process. This does not change from module to module. It changes when your code calls process.chdir(). Also, when you perform filesystem operations that use ., this is interpreted relative to process.cwd().
So that you get C:\path\project from process.cwd() is not surprising since this is where you'd typically run Grunt (i.e. at the top level of your project). What you can do if you want paths relative to a module is use __dirname. For instance, this code reads files from a foo subdirectory in the same location where the module that contains this code is located:
var path = require("path");
var fs = require("fs");
var subdir = path.join(__dirname, "foo");
var foofiles = fs.readdirSync(subdir);

Determine project root from a running node.js application

Is there a different way, other than process.cwd(), to get the pathname of the current project's root-directory. Does Node implement something like ruby's property, Rails.root,. I'm looking for something that is constant, and reliable.
There are many ways to approach this, each with their own pros and cons:
require.main.filename
From http://nodejs.org/api/modules.html:
When a file is run directly from Node, require.main is set to its module. That means that you can determine whether a file has been run directly by testing require.main === module
Because module provides a filename property (normally equivalent to __filename), the entry point of the current application can be obtained by checking require.main.filename.
So if you want the base directory for your app, you can do:
const { dirname } = require('path');
const appDir = dirname(require.main.filename);
Pros & Cons
This will work great most of the time, but if you're running your app with a launcher like pm2 or running mocha tests, this method will fail. This also won't work when using Node.js ES modules, where require.main is not available.
module.paths
Node publishes all the module search paths to module.paths. We can traverse these and pick the first one that resolves.
async function getAppPath() {
const { dirname } = require('path');
const { constants, promises: { access } } = require('fs');
for (let path of module.paths) {
try {
await access(path, constants.F_OK);
return dirname(path);
} catch (e) {
// Just move on to next path
}
}
}
Pros & Cons
This will sometimes work, but is not reliable when used in a package because it may return the directory that the package is installed in rather than the directory that the application is installed in.
Using a global variable
Node has a global namespace object called global — anything that you attach to this object will be available everywhere in your app. So, in your index.js (or app.js or whatever your main app
file is named), you can just define a global variable:
// index.js
var path = require('path');
global.appRoot = path.resolve(__dirname);
// lib/moduleA/component1.js
require(appRoot + '/lib/moduleB/component2.js');
Pros & Cons
Works consistently, but you have to rely on a global variable, which means that you can't easily reuse components/etc.
process.cwd()
This returns the current working directory. Not reliable at all, as it's entirely dependent on what directory the process was launched from:
$ cd /home/demo/
$ mkdir subdir
$ echo "console.log(process.cwd());" > subdir/demo.js
$ node subdir/demo.js
/home/demo
$ cd subdir
$ node demo.js
/home/demo/subdir
app-root-path
To address this issue, I've created a node module called app-root-path. Usage is simple:
const appRoot = require('app-root-path');
const myModule = require(`${ appRoot }/lib/my-module.js`);
The app-root-path module uses several techniques to determine the root path of the app, taking into account globally installed modules (for example, if your app is running in /var/www/ but the module is installed in ~/.nvm/v0.x.x/lib/node/). It won't work 100% of the time, but it's going to work in most common scenarios.
Pros & Cons
Works without configuration in most circumstances. Also provides some nice additional convenience methods (see project page). The biggest con is that it won't work if:
You're using a launcher, like pm2
AND, the module isn't installed inside your app's node_modules directory (for example, if you installed it globally)
You can get around this by either setting a APP_ROOT_PATH environmental variable, or by calling .setPath() on the module, but in that case, you're probably better off using the global method.
NODE_PATH environmental variable
If you're looking for a way to determine the root path of the current app, one of the above solutions is likely to work best for you. If, on the other hand, you're trying to solve the problem of loading app modules reliably, I highly recommend looking into the NODE_PATH environmental variable.
Node's Modules system looks for modules in a variety of locations. One of these locations is wherever process.env.NODE_PATH points. If you set this environmental variable, then you can require modules with the standard module loader without any other changes.
For example, if you set NODE_PATH to /var/www/lib, the the following would work just fine:
require('module2/component.js');
// ^ looks for /var/www/lib/module2/component.js
A great way to do this is using npm:
{
"scripts": {
"start": "NODE_PATH=. node app.js"
}
}
Now you can start your app with npm start and you're golden. I combine this with my enforce-node-path module, which prevents accidentally loading the app without NODE_PATH set. For even more control over enforcing environmental variables, see checkenv.
One gotcha: NODE_PATH must be set outside of the node app. You cannot do something like process.env.NODE_PATH = path.resolve(__dirname) because the module loader caches the list of directories it will search before your app runs.
[added 4/6/16] Another really promising module that attempts to solve this problem is wavy.
__dirname isn't a global; it's local to the current module so each file has its own local, different value.
If you want the root directory of the running process, you probably do want to use process.cwd().
If you want predictability and reliability, then you probably need to make it a requirement of your application that a certain environment variable is set. Your app looks for MY_APP_HOME (Or whatever) and if it's there, and the application exists in that directory then all is well. If it is undefined or the directory doesn't contain your application then it should exit with an error prompting the user to create the variable. It could be set as a part of an install process.
You can read environment variables in node with something like process.env.MY_ENV_VARIABLE.
1- create a file in the project root call it settings.js
2- inside this file add this code
module.exports = {
POST_MAX_SIZE : 40 , //MB
UPLOAD_MAX_FILE_SIZE: 40, //MB
PROJECT_DIR : __dirname
};
3- inside node_modules create a new module name it "settings" and inside the module index.js write this code:
module.exports = require("../../settings");
4- and any time you want your project directory just use
var settings = require("settings");
settings.PROJECT_DIR;
in this way you will have all project directories relative to this file ;)
the easiest way to get the global root (assuming you use NPM to run your node.js app 'npm start', etc)
var appRoot = process.env.PWD;
If you want to cross-verify the above
Say you want to cross-check process.env.PWD with the settings of you node.js application. if you want some runtime tests to check the validity of process.env.PWD, you can cross-check it with this code (that I wrote which seems to work well). You can cross-check the name of the last folder in appRoot with the npm_package_name in your package.json file, for example:
var path = require('path');
var globalRoot = __dirname; //(you may have to do some substring processing if the first script you run is not in the project root, since __dirname refers to the directory that the file is in for which __dirname is called in.)
//compare the last directory in the globalRoot path to the name of the project in your package.json file
var folders = globalRoot.split(path.sep);
var packageName = folders[folders.length-1];
var pwd = process.env.PWD;
var npmPackageName = process.env.npm_package_name;
if(packageName !== npmPackageName){
throw new Error('Failed check for runtime string equality between globalRoot-bottommost directory and npm_package_name.');
}
if(globalRoot !== pwd){
throw new Error('Failed check for runtime string equality between globalRoot and process.env.PWD.');
}
you can also use this NPM module: require('app-root-path') which works very well for this purpose
Simple:
require('path').resolve('./')
As simple as adding this line to your module in the root, usually it is app.js or app.ts.
global.__basedir = __dirname;
Then _basedir will be accessible to all your modules.
Note: For typescript implementation, follow the above step and then you will be able to use the root directory path using global.__basedir
I've found this works consistently for me, even when the application is invoked from a sub-folder, as it can be with some test frameworks, like Mocha:
process.mainModule.paths[0].split('node_modules')[0].slice(0, -1);
Why it works:
At runtime node creates a registry of the full paths of all loaded files. The modules are loaded first, and thus at the top of this registry. By selecting the first element of the registry and returning the path before the 'node_modules' directory we are able to determine the root of the application.
It's just one line of code, but for simplicity's sake (my sake), I black boxed it into an NPM module:
https://www.npmjs.com/package/node-root.pddivine
Enjoy!
EDIT:
process.mainModule is deprecated as of v14.0.0
Use require.main instead:
require.main.paths[0].split('node_modules')[0].slice(0, -1);
Try traversing upwards from __dirname until you find a package.json, and decide that's the app main root directory your current file belongs to.
According to Node docs
The package.json file is normally located at the root directory of a Node.js project.
const fs = require('fs')
const path = require('path')
function getAppRootDir () {
let currentDir = __dirname
while(!fs.existsSync(path.join(currentDir, 'package.json'))) {
currentDir = path.join(currentDir, '..')
}
return currentDir
}
All these "root dirs" mostly need to resolve some virtual path to a real pile path, so may be you should look at path.resolve?
var path= require('path');
var filePath = path.resolve('our/virtual/path.ext');
Preamble
This is a very old question, but it seems to hit the nerve in 2020 as much as back in 2012.
I've checked all the other answers and could not find the following technique mentioned (it has its own limitations, but the others are not applicable to every situation either):
Git + child process
If you are using Git as your version control system, the problem of determining the project root can be reduced to (which I would consider the proper root of the project - after all, you would want your VCS to have the fullest visibility scope possible):
retrieve repository root path
Since you have to run a CLI command to do that, we need to spawn a child process. Additionally, as project root is highly unlikely to change mid-runtime, we can use the synchronous version of the child_process module at startup.
I found spawnSync() to be the most suitable for the job. As for the actual command to run, git worktree (with a --porcelain option for ease of parsing) is all that is needed to retrieve the absolute path of the root.
In the sample at the end of the answer, I opted to return an array of paths because there might be multiple worktrees (although they are likely to have common paths) just to be sure. Note that as we utilize a CLI command, shell option should be set to true (security shouldn't be an issue as there is no untrusted input).
Approach comparison and fallbacks
Understanding that a situation where VCS can be inaccessible is possible, I've included a couple of fallbacks after analyzing docs and other answers. The proposed solutions boil down to (excluding third-party modules & packages):
Solution
Advantage
Main Problem
__filename
points to module file
relative to module
__dirname
points to module dir
same as __filename
node_modules tree walk
nearly guaranteed root
complex tree walking if nested
path.resolve(".")
root if CWD is root
same as process.cwd()
process.argv\[1\]
same as __filename
same as __filename
process.env.INIT_CWD
points to npm run dir
requires npm && CLI launch
process.env.PWD
points to current dir
relative to (is the) launch dir
process.cwd()
same as env.PWD
process.chdir(path) at runtime
require.main.filename
root if === module
fails on required modules
From the comparison table above, the following approaches are the most universal:
require.main.filename as an easy way to get the root if require.main === module is met
node_modules tree walk proposed recently uses another assumption:
if the directory of the module has node_modules dir inside, it is likely to be the root
For the main app, it will get the app root and for a module — its project root.
Fallback 1. Tree walk
My implementation uses a more lax approach by stopping once a target directory is found as for a given module its root is the project root. One can chain the calls or extend it to make the search depth configurable:
/**
* #summary gets root by walking up node_modules
* #param {import("fs")} fs
* #param {import("path")} pt
*/
const getRootFromNodeModules = (fs, pt) =>
/**
* #param {string} [startPath]
* #returns {string[]}
*/
(startPath = __dirname) => {
//avoid loop if reached root path
if (startPath === pt.parse(startPath).root) {
return [startPath];
}
const isRoot = fs.existsSync(pt.join(startPath, "node_modules"));
if (isRoot) {
return [startPath];
}
return getRootFromNodeModules(fs, pt)(pt.dirname(startPath));
};
Fallback 2. Main module
The second implementation is trivial:
/**
* #summary gets app entry point if run directly
* #param {import("path")} pt
*/
const getAppEntryPoint = (pt) =>
/**
* #returns {string[]}
*/
() => {
const { main } = require;
const { filename } = main;
return main === module ?
[pt.parse(filename).dir] :
[];
};
Implementation
I would suggest using the tree walker as the preferred fallback because it is more versatile:
const { spawnSync } = require("child_process");
const pt = require('path');
const fs = require("fs");
/**
* #summary returns worktree root path(s)
* #param {function : string[] } [fallback]
* #returns {string[]}
*/
const getProjectRoot = (fallback) => {
const { error, stdout } = spawnSync(
`git worktree list --porcelain`,
{
encoding: "utf8",
shell: true
}
);
if (!stdout) {
console.warn(`Could not use GIT to find root:\n\n${error}`);
return fallback ? fallback() : [];
}
return stdout
.split("\n")
.map(line => {
const [key, value] = line.split(/\s+/) || [];
return key === "worktree" ? value : "";
})
.filter(Boolean);
};
Disadvantages
The most obvious one is having Git installed and initialized which might be undesirable/implausible (side note: having Git installed on production servers is not uncommon, nor is it unsafe). Can be mediated by fallbacks as described above.
There is an INIT_CWD property on process.env. This is what I'm currently working with in my project.
const {INIT_CWD} = process.env; // process.env.INIT_CWD
const paths = require(`${INIT_CWD}/config/paths`);
Good Luck...
A technique that I've found useful when using express is to add the following to app.js before any of your other routes are set
// set rootPath
app.use(function(req, res, next) {
req.rootPath = __dirname;
next();
});
app.use('/myroute', myRoute);
No need to use globals and you have the path of the root directory as a property of the request object.
This works if your app.js is in the root of your project which, by default, it is.
Actually, i find the perhaps trivial solution also to most robust:
you simply place the following file at the root directory of your project: root-path.js which has the following code:
import * as path from 'path'
const projectRootPath = path.resolve(__dirname)
export const rootPath = projectRootPath
Add this somewhere towards the start of your main app file (e.g. app.js):
global.__basedir = __dirname;
This sets a global variable that will always be equivalent to your app's base dir. Use it just like any other variable:
const yourModule = require(__basedir + '/path/to/module.js');
Simple...
I know this one is already too late.
But we can fetch root URL by two methods
1st method
var path = require('path');
path.dirname(require.main.filename);
2nd method
var path = require('path');
path.dirname(process.mainModule.filename);
Reference Link:- https://gist.github.com/geekiam/e2e3e0325abd9023d3a3
process.mainModule is deprecated since v 14.0.0. When referring to the answer, please use require.main, the rest still holds.
process.mainModule.paths
.filter(p => !p.includes('node_modules'))
.shift()
Get all paths in main modules and filter out those with "node_modules",
then get the first of remaining path list. Unexpected behavior will not throw error, just an undefined.
Works well for me, even when calling ie $ mocha.
At top of main file add:
mainDir = __dirname;
Then use it in any file you need:
console.log('mainDir ' + mainDir);
mainDir is defined globally, if you need it only in current file - use __dirname instead.
main file is usually in root folder of the project and is named like main.js, index.js, gulpfile.js.
if you want to determine project root from a running node.js application you can simply just too.
process.mainModule.path
It work for me
process.env.PWD
This will step down the directory tree until it contains a node_modules directory, which usually indicates your project root:
const fs = require('fs')
const path = require('path')
function getProjectRoot(currentDir = __dirname.split(path.sep)) {
if (!currentDir.length) {
throw Error('Could not find project root.')
}
const nodeModulesPath = currentDir.concat(['node_modules']).join(path.sep)
if (fs.existsSync(nodeModulesPath) && !currentDir.includes('node_modules')) {
return currentDir.join(path.sep)
}
return this.getProjectRoot(currentDir.slice(0, -1))
}
It also makes sure that there is no node_modules in the returned path, as that means that it is contained in a nested package install.
Create a function in app.js
/*Function to get the app root folder*/
var appRootFolder = function(dir,level){
var arr = dir.split('\\');
arr.splice(arr.length - level,level);
var rootFolder = arr.join('\\');
return rootFolder;
}
// view engine setup
app.set('views', path.join(appRootFolder(__dirname,1),'views'));
I use this.
For my module named mymodule
var BASE_DIR = __dirname.replace(/^(.*\/mymodule)(.*)$/, '$1')
Make it sexy 💃🏻.
const users = require('../../../database/users'); // 👎 what you have
// OR
const users = require('$db/users'); // 👍 no matter how deep you are
const products = require('/database/products'); // 👍 alias or pathing from root directory
Three simple steps to solve the issue of ugly path.
Install the package: npm install sexy-require --save
Include require('sexy-require') once on the top of your main application file.
require('sexy-require');
const routers = require('/routers');
const api = require('$api');
...
Optional step. Path configuration can be defined in .paths file on root directory of your project.
$db = /server/database
$api-v1 = /server/api/legacy
$api-v2 = /server/api/v2
You can simply add the root directory path in the express app variable and get this path from the app. For this add app.set('rootDirectory', __dirname); in your index.js or app.js file. And use req.app.get('rootDirectory') for getting the root directory path in your code.
Old question, I know, however no question mention to use progress.argv. The argv array includes a full pathname and filename (with or without .js extension) that was used as parameter to be executed by node. Because this also can contain flags, you must filter this.
This is not an example you can directly use (because of using my own framework) but I think it gives you some idea how to do it. I also use a cache method to avoid that calling this function stress the system too much, especially when no extension is specified (and a file exist check is required), for example:
node myfile
or
node myfile.js
That's the reason I cache it, see also code below.
function getRootFilePath()
{
if( !isDefined( oData.SU_ROOT_FILE_PATH ) )
{
var sExt = false;
each( process.argv, function( i, v )
{
// Skip invalid and provided command line options
if( !!v && isValidString( v ) && v[0] !== '-' )
{
sExt = getFileExt( v );
if( ( sExt === 'js' ) || ( sExt === '' && fileExists( v+'.js' )) )
{
var a = uniformPath( v ).split("/");
// Chop off last string, filename
a[a.length-1]='';
// Cache it so we don't have to do it again.
oData.SU_ROOT_FILE_PATH=a.join("/");
// Found, skip loop
return true;
}
}
}, true ); // <-- true is: each in reverse order
}
return oData.SU_ROOT_FILE_PATH || '';
}
};
Finding the root path of an electron app could get tricky. Because the root path is different for the main process and renderer under different conditions such as production, development and packaged conditions.
I have written a npm package electron-root-path to capture the root path of an electron app.
$ npm install electron-root-path
or
$ yarn add electron-root-path
// Import ES6 way
import { rootPath } from 'electron-root-path';
// Import ES2015 way
const rootPath = require('electron-root-path').rootPath;
// e.g:
// read a file in the root
const location = path.join(rootPath, 'package.json');
const pkgInfo = fs.readFileSync(location, { encoding: 'utf8' });
This will do:
path.join(...process.argv[1].split(/\/|\\/).slice(0, -1))
path.dirname(process.mainModule.filename);
In modern versions of npm, you can add an entry to exports, to use as a shorthand. Note that if you want to be able to reference both the root itself and files within that root, you'll need both ./ and ./* respectively:
package.json:
{
"imports": {
"#root": "./",
"#root/*": "./*",
...
},
...
}
./index.js:
import {namedExport} from '#root/file.js'
./file.js:
export const namedExport = {
hi: "world",
};
Then:
$ node --experimental-specifier-resolution=node index.js
You could extend this further with a constants.js file, where you may use one of the methods in the above answers, or input an absolute path, should you require the path itself
You can also use
git rev-parse --show-toplevel
Assuming you are working on a git repository

Resources