Make node script packaged with zeit-pkg aware of full filesystem - node.js

I have a node script which uses command line parameters using the module commander.
I want to pack it with pkg, but I am running into some trouble.
Normally I would execute my script with:
node index.js --file ./test.csv
but the file argument could point to any folder in the user's filesystem.
I have looked into configuring the assets and scripts attributes for pkg in package.json, but it looks like you need to specify a folder in there, such as:
"pkg": {
"scripts": "build/**/*.js",
"assets": "views/**/*"
}
How can I make a zeit-pkg packged node script aware of any possible location in the filesystem?
I am simply building with pkg package.json , since in package.json I have the entry:
"bin" : "index.js"

In your pkg-packed source, add this in the beginning:
console.log("process.cwd() = " + process.cwd());
When you run your packaged exe this will tell you what
your executable sees as its working directory. You can
then interpret any relative arg-paths of your application
(like "./index.csv") relative to that.
It seems based on my experiments that pkg-applications have
full access to the file-system as long as your program knows
the absolute paths of the files you want to read or write
or even "require".
The only tricky thing seems to be relative paths.
The reason is that pkg wants you to be able to package
resource/asset -files into the executable and then access them
like you would any file at runtime. That is actually a
great feature but often more than you need.
If you don't need to package any (extra) files into your
executable then file-system access should be simple and
work just normally with absolute paths. You just need to
know "where you are" if you want to use relative paths.
I'm not affiliated with the pkg project so my answer is
not authoritative in any way. I hope zeit would put more
documentation about the file-system access into their site,
especially cross-platform. After doing some experimentation
myself it just seems accessing files by their absolute paths
works, on Windows.

Related

Is there any way of changing the relative path of a mjs file (to make it see a different node_modules folder)?

When I'm executing pure node.js scripts I can change the path where it searches for node_modules as the following:
export NODE_PATH="/home/user/node_modules"
node "/home/user/different/path/file.js"
This way, I can make scripts located inside /home/user/different/path/ see the node_modules folder located in /home/user/ when they are executed.
So far everything is fine, the problem starts with .mjs files. If I try running:
export NODE_PATH="/home/user/node_modules"
node "/home/user/different/path/file.mjs"
I'll receive the error Error [ERR_MODULE_NOT_FOUND] for the modules that I use in my code. The workaround that I know for that is creating a symbolic link inside my script's folder. Something like:
ln -s "/home/user/node_modules" "/home/user/different/path/node_modules"
After doing that, if I run node "/home/user/different/path/file.mjs" it'll work as expected and I'll be able to use libraries installed on /home/user/node_modules with the import statement in my script. However, I'd like to find a solution that doesn't require me to create a symbolic link of the node_modules folder. Is there any alternative solution when I'm working with .mjs files that allows me to change its relative path?

Why does require("the-module") from a file in another directory fail?

When I did node myfile.js I got an error that a module was not found. I checked module.paths like this:
$ node
> module.paths
The path where the module is installed showed up and I could require the module:
$ node
> require("the-module")
So I added console.log(module.paths) to myfile.js to see if module.paths was the same. It was not.
What is going on?
EDIT:
It was a bit more complicated.
The module.paths are different, but that does not seem to be the problem. The path where the-module is installed is in the list.
When I add require("the-module") in myfile.js it works as expected. However I do require("c:/path-to/other-file.js") and from there I do another require("the-module"). This require fails.
EDIT 2:
module.paths is other-file.js is different. Why? (And the path where the-module is installed is not in this list.)
You can see all the rules for how require() loads files when you don't specify a full path here.
When you specific only a filename, as in require("the-module"), node.js looks in the node_modules sub-directory below the directory that the current module you are calling require() from was loaded. It is done this way so that a module can have its own set of dependencies and can load them relative to it's own directory without regard from where it is in the file system.
So, if the module you are calling require() from was in c:\myprojects\team\module1 and from within a file in that directory, you call require("the-module"), then node.js will look in c:\myprojects\team\module1\node_modules to find the-module.js.
Similarly, any path that starts with ./ is relative to that same directory, but allows you to reference files in the same directory itself.
node.js does not dynamically add paths to a list of search paths. It sounds like you have an expectation that as you access various directories they are somehow automatically added to a search path. That's now how it works. The rules for where require() looks for relative paths are all spelled out here.
Also, keep in mind that there is not just one module variable across all of node.js. There's a different one in each file that you load in node.js so module.paths very well may be different in each one. In reality, most node.js developers never use module.paths in any way. If you just follow the rules for how relative paths work for require(), you will get what you expect and need.

Is there a variable that refers to the package base directory?

Is there a variable (or how to make such a variable) that refers to the package base directory (where package.json is)?
The use case:
I am using Babel to compile code from ES6 to ES5. ./src/ to ./dist/. Then I refer to the ./dist/ code in the main property of the package.json
The problem happens when ./src/ code uses files that are not JS, e.g. ./src/schemas/*.json. These files do not exist in ./dist/ folder. Therefore, when referring to non-JavaScript files from ./src/ I need to use a path that keeps a reference to ./src/ file.
I can already do this using ./../src/schemas/foo.json when requesting a file. Though, thats a fragile approach.
I know I can simply copy all the non-JavaScript files to ./dist/, but
duplication of content does not seem like an appropriate solution.
This is the appropriate solution.
Why ?
Your src folder should hold the source code of your project (not including dependencies & build routines)
Your dist folder is supposed to hold a standalone version of your app or website that you'll be able to distribute "as is" (you should be able to upload the content of dist via ssh/ftp or whatever to your remote server and it should be working)
Note: This thread is more about code organization than code itself (so anybody can have his opinion), but this is the kind of workflow yeoman and lots of build systems use.

require name instead of file path

I am looking at some code on github.
https://github.com/madhums/node-express-mongoose/blob/master/config/routes.js
On line 7 it says.
var home = require('home');
home.js is in another folder. I am wondering how this works, and how I can do this in my own code.
on
http://nodejs.org/api/modules.html#modules_folders_as_modules
it explains how to create a self-contained directory, but I can only find the package.json in the root folder. So how does this work?
It seems like a more clean way than having direct file references.
There are ways to refer to folders on the filesystem as packages in node, npm link for example, will pretend a folder is a module using symlinks.
The package you linked to is cheating a bit though, and I'd argue it's not clean at all when put like that. It's actually setting the NODE_PATH to include all controllers when the service is ran: https://github.com/madhums/node-express-mongoose/blob/master/package.json#L13
So all controllers files like home.js are autmatically available. The .js is always optional anyway.

Get the node.js install path from code

I'm trying to write a debugging framework for node.js and am having a hard time figuring out how to get the full path to a core module file like fs.js.
I've heard it's in the /lib folder of the node installation, but I'd need to get this from the code in a consistent way for a variety of install situations (including windows).
I've tried taking a look at the process and process.env values for something like a node install path but can't see anything that immediately pops out at me.
To find where the installed node executable is located you can look at the process.execPath which gives the absolute path to Node executable.
To find where a certain module is located you can use require.resolve(module);
However I think the global modules are not directly accessible from the filesystem as other regular modules since they seem to be cached somewhere within the executable.

Resources