How to get the root of project which installed my npm module? - node.js

I am developing an NPM package. Now I want to know the easiest way to get the root of the project which utilizes my custom package.
Within my package itself it is pretty easy to get the root in node.js like so:
__dirname
This points to the root of my package itself though. I would like to get the root of the project which actually performed the npm install of my package though.
Obviously, I could simply go up from the node_modules directory and assume that the root directory is there but this sounds really bad.
Is there a standard way to achieve this?

you could use app-root-path which is an npm module and its pretty neat.
npm i -S app-root-path
after that just do
var reqlib = require('app-root-path').require;
var myModule = reqlib('/lib/my-module.js');

You can use the info from: require.main
The Module object representing the entry script loaded when the
Node.js process launched. See "Accessing the main module".
const path = require('path');
console.log(path.dirname(require.main.filename));
Having this folder structure:
/app
entry.js
node_modules/
my-package/
index.js
app/entry.js
const myPackage = require('my-package');
app/node_modules/my-package/index.js
const path = require('path');
console.log(path.dirname(require.main.filename));
And when you call: node entry.js
You will get: /app printed to stdout.

KISS
const fullPath = path.dirname(require.main.filename);
const regexResp = /^(.*?)node_modules/.exec(fullPath);
const appRoot = regexResp ? regexResp[1] : fullPath;
console.log(appRoot); // outputs the directory which is the root of this project

Related

How to access the base package form a node_module

I am looking to access a JSON config file that the user would place next to their package.json from a node_module package that I created. Is there a best approach to do this. I tried a relative import but that didn't really work and I am not sure how best to accomplish dynamic imports if the config file doesn't exist because I want to allow it to not exist as well.
Here is how I tried to handle dynamic imports though:
export const overrides = (function () {
try {
return require('../../../../../../overrides.json');
} catch (_err) {
return null;
}
})();
Also I tried fs but I get a browser config error I am not sure if that is something else. I should research but I didn't understand the docs around that.
using a library
This worked for me: find-package-json
Basically on any js file who needs the base, home or workspace path, do this:
var finder = require('find-package-json');
var path = require('path');
var f = finder(__dirname);
var rootDirectory = path.dirname(f.next().filename);
rootDirectory will be the location of the folder in which the main package.json exist.
If you want to optimize, get the appRootPath variable at the start of your app and store/propagate the variable to the hole nodejs system.
no libraries
Without any library, this worked for me:
console.log("root directory: "+require('path').resolve('./'));
This will get you the root directory of your nodejs app no matter if you are using npm run start or node foo/bar/index.js
More ways to get the root directory here:
Determine project root from a running node.js application
usage
If you achieve to obtain the root directory of your nodejs app and your file is at the package.json level, use this variable like this to locate any file at root level:
rootDirectory+"/overrides.json"

Finding the root directory of a dependency in NPM

Let's say I have installed awesome-package inside my-app, and let's say the structure looks like:
my-app/
node_modules/
awesome-package/
node_modules/
another-package/
static/
index.js
dist/
index.js
dist/
index.js
Inside my-app/index.js I do require('awesome-package'). Now I want to get the root directory of awesome-package, so I can basically fs.readFileSync something from another-package
How can I get the root directory of a script?
I think require.resolve can be used to achieve that. It will give you the full path to the module. Getting the root directory from that should be easy.
const path = require('path');
let loc = require.resolve('awesome-package');
// most likely something like the following depends on the package
// /path/to/my-app/node_modules/awesome-package/static/index.js
console.log(loc);
// something like the following will give you the root directory
// of the package
console.log(path.join(
loc.substring(0,a.lastIndexOf('node_modules')),
'node_modules',
'awesome-package'
));
Accepted answer doesn't work on esm package.
Accepted answer return cjs path.
Answer for esm path
const fullPath = await import.meta.resolve("package_name");
console.log(fullPath);
need to add flag: --experimental-import-meta-resolve

How to create a config file for node pkg

I use node pkg to create a .exe of my nodejs service: https://www.npmjs.com/package/pkg
My question is: how do I make the .exe use a config.js for some setup values? Basic stuff like ip, port, database name etc. Because I have 3 environments, and I would like to use the same exe for all, but different config.js files for each.
So far, if I do pkg app.js then it creates an .exe that doesn't look at any other files. Totally stand alone. How do I make it look at config.js when it is started up?
On the website they do have a section on config https://github.com/zeit/pkg#config but I do not understand how to make use of it. At the moment I have my app.js, and I have secrets.js which holds the config information.
I am not sure this is right way, but I hope this can be helpful to somebody.
Refer to pkg document, on the run time, __dirname becomes "/snapshot/project".
So, by checking __dirname, you can identify in which environment you are.
(node app.js or app.exe).
Then we can separate require sentence like below.
const PKG_TOP_DIR = 'snapshot';
const runInPKG = (function(){
const pathParsed = path.parse(__dirname);
const root = pathParsed.root;
const dir = pathParsed.dir;
const firstDepth = path.relative(root, dir).split(path.sep)[0];
return (firstDepth === PKG_TOP_DIR)
})();
let config = require('./appconfig.json');
if(runInPKG) {
const deployPath = path.dirname(process.execPath);
config = require(path.join(deployPath, 'appconfig.json'));
}
Adding above code to your app.js makes some warning when pkg build.
pkg . --targets node8-win-x64 --out-path ./dist
pkg#4.4.0
Warning Cannot resolve 'path.join(deployPath, 'appconfig.json')'
app.js
Dynamic require may fail at run time, because the requested file
is unknown at compilation time and not included into executable.
Use a string literal as an argument for 'require', or leave it
as is and specify the resolved file name in 'scripts' option.
https://github.com/vercel/pkg/issues/195
use fs to read config file insead of require or import
eg:
const configPath = path.join(process.cwd(), './config/config.json');
lset data = fs.readFileSync(configPath);
same question link:excluding config file while converting node js files to exe using pkg

How get path to folder "node_modules" in js file?

Node.js - 8.2.1
I my index.js I hard code path to node_modules:
'use strict';
var NPM_NODE_MODULES_BASE_DIR = 'd:\\Programs\\nodejs\\node_modules\\npm\\node_modules\\'
var express = require(NPM_NODE_MODULES_BASE_DIR + '\express'),
bodyParser = require(NPM_NODE_MODULES_BASE_DIR +'body-parser');
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
But it's not very good, because code is not portable. How I can get path to folder node_modules of Node.js ?
Instead of installing npm modules globally you could install them in your src folder, whenever you are in the src folder and do an npm install it should be installed in the local npm modules folder in the src file making it portable, you could use --save to add it to your dependencies so you can get it while initialising your node project
Here is an excerpt from the nodejs current master branch source documentation [doc/api/modules.md]...
...high-level algorithm in pseudocode of what require.resolve() does:
require(X) from module at path Y
If X is a core module,
a. return the core module
b. STOP
If X begins with '/'
a. set Y to be the filesystem root
If X begins with './' or '/' or '../'
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
LOAD_NODE_MODULES(X, dirname(Y))
THROW "not found"
Please note that you can have more than one node_modules (see https://docs.npmjs.com/files/folders).
Most of the times, the node_modules you want is the parent path of the directory your current module lives in:
const path = require('path').resolve(__dirname, '..');

fs doesn't get file if i publish module to npm

I'm facing a problem when i publish my module to npm.
Here's the file structure:
- node_modules
- lib
-- file.txt
- index.js
- package.json
I use it like that:
var a = fs.readFileSync('./lib/file.txt');
It works in local development. But when i publish my module to npm, it says:
Error: ENOENT, no such file or directory './lib/file.txt'
This error comes from fs, it doesn't get file. Is it about nested node_modules folder?
I mean when i want to test my module in clear folder, i install module:
npm install <my-module-name>
Creating a test.js file and puting that codes inside it:
var myModuleName = require('my-module-name');
var a = myModuleName();
console.log(a);
So new structure become:
- node_modules
-- my-module-name
-- node_modules
-- lib
-- file.txt
-- index.js
-- package.json
- test.js
Any idea?
This is because fs.readFileSync is looking for the file relative to the current working directory. Try using __dirname:
var path = require('path');
var a = fs.readFileSync(path.join(__dirname, 'lib', 'file.txt'));

Resources