How should I load a file that is inside my own module? - node.js

Current code in /config/index.js
const options = (require('js-yaml')).safeLoad(
(require('fs')).readFileSync(`./config/default-config.yaml`, "utf8"));
module.exports = options;
Works fine. Until I publish and use it in my other project. Then it's unable to find the file (naturally) as ./config/default-config.yaml doesn't exist in that project.
The only option I can think of involves checking to see if the file exists at that path, then trying to load it from node_modules/#company/alpha-gamma/config/default-config.yaml. This seems really hacky.
The config object is large, 200+ keys. I don't think it belongs in the code.
What's the best solution for loading a file that exists inside your module? I need to be able to load it for unit tests before publishing and load it at runtime when the library is required by another module.
Maybe the best alternative is to use json since I can then use the require module to load it in, instead of fs.

While I originally suggested utilizing __dirname as a valid option, I was wrong. Calling process.cwd() to fetch the application root and building the path off of that is the best approach.
As documented here:
Proper way to reference files relative to application root in Node.JS

Related

AppImage from electron-builder with file system not working

I’m using Electron Builder to compile my Electron app to an .AppImage file, and I’m using the fs module to write to an .json file, but it’s not working in the appimage format (it’s working fine when I have the normal version not made with Electron Builder). I can still read from the file.
The code (preload):
setSettings: (value) => {fs.writeFileSync(path.join(__dirname, "settings.json"), JSON.stringify(value), "utf8")}
The code (on the website):
api.setSettings(settings);
The project: https://github.com/Nils75owo/crazyshit
That's not a problem with AppImage or Electron Builder but with the way you're packaging your app. Since you didn't post your package.json*, I can only guess what's wrong, but probably you haven't changed Electron Builder's default behaviour regarding packing your application.
By default, Electron Builder compiles your application, including all resources, into a single archive file in the ASAR format (think of it like the TAR format). Electron includes a patched version of the fs module to be able to read from the ASAR file, but writing to it is obviously not supported.
You have two options to mitigate this problem: Either you store your settings somewhere in the user's directory (which is the way I'd go, see below) or you refrain from packing your application to an ASAR file, but that will leave all your JavaScript code outside the executable in a simple folder. (Note that ASAR is not capable of keeping your code confidential, because there are applications which can extract such archives, but it makes it at least a little harder for attackers or curious eyes to get a copy of your code.)
To disable packing to ASAR, simply tell Electron Builder that you don't want it to compile an archive. Thus, in your package.json, include the following:
{
// ... other options
"build": {
// ... other build options
"asar": false
}
}
However, as I mentioned above, it's probably wiser to store settings in a common place where advanced users can actually find (and probably edit, mostly for troubleshooting) them. On Linux, one such folder would be ~/.config, where you could create a subdirectory for your application.
To get the specific application data path on a cross-platform basis, you can query Electron's app module from within the main process. You can do so like this:
const { app } = require ("electron"),
path = require ("path");
var configPath;
try {
configPath = path.join (app.getPath ("appData"), "your-app-name");
} catch (error) {
console.error (error);
app.quit ();
}
If you however have correctly set your application's name (by using app.setName ("...");), you can instead simply use app.getPath ("userData"); and omit the path joining. Take a look at the documentation!
For my Electron Applications, I typically choose to store settings in a common hidden directory (one example for a name could be the brand under which you plan to market the application) in the user's home directory and I then have separate directories for each application. But how you organise this is up to you completely.
* For the future, please refrain from directing us to a GitHub repository and instead include all information (and code is information too) needed to replicate/understand your problem in your question. That'd save us a lot of time and could potentially get you answers faster. Thanks!

How do i keep a single variable(Access Token) accessed by all test suits in JEST Test?

I am new to jest testing and I am trying to find a way to access the access token for all test-suites in my project. I have tried global variable and the setup files of jest but nothing worked for me.
I tried keeping all in one describe like this answer but how can I mention only the folder name rather than file name in it?
How can I write my access token into an empty file present in my project and access that inside my test suits?
This is what I do to use common data for Jest.
Make a separate file containing whatever you need.
Then in the test file do this:
const TESTDATA = require("./test_data/auth-key.json");
Hope this helps!

Do each parent directories need to have their own node_modules folder?

I am working on an app powered by node which has a few (three) different folders. It looks like this:
Client-
Server-
-node_modules
-mongoose
Database-
-index.js
Config-
-credentials.js
I have made an exports object with all of my passwords and put it in the database folder (this way I can easily ignore it from being checked in to any version control).
I am wondering if there is a way to have ALL of the node_modules used by my server and database directories in the server directory so that the package.json file in my server directory would contain all of the needed packages for the "backend" of my project.
However, when I do this, and try to require(mongoose) from the Database/index.js file, I get "cannot find module" errors. I tried the following combinations and still get the error in every case:
require(mongoose) require(../server/mongoose) require(../server/node_modules/mongoose)
Installing the mongoose module directly in the Database directory fixes this problem but this means that I have to have a node_modules (and thus package.json) file in each directory. Is that the right way to fix this issue or is there a more simple solution?
Thanks
Maybe you find interesting having a look at the following article: "Where does Node.js and require() look for modules?", in order to understand why the different ways you are trying to "require" mongoose are not actually working - and that is because the way you are organizing your code (your node_modules directory is inside your Server and your Database directory is under the / - root directory).
So, in your case, you will have to specify your /Database/index.js the relative file path to mongoose in order to find your module:
require('../server/node_modules/mongoose');
Another solution (I personally organize my code like this) would be moving your database code within the server code; after all, it's all backend code.
I aware this not elegant way but i have an advice for your case.
You can try like below;.
var mongoose = require('../server/node_modules/mongoose/index');
I was simulated your case in my local and this worked.

How can I get the application base path from a module in Node.js?

I'm building a web application in Node.js, and I'm implementing my API routes in separate modules. In one of my routes I'm doing some file manipulation and I need to know the base app path. If I use __dirname, it gives me the directory that houses my module of course.
I'm currently using this to get the base application path (given that I know the relative path to the module from base path):
path.join(__dirname, "../../", myfilename)
Is there a better way than using ../../? I'm running Node.js under Windows, so there isn't any process.env.PWD, and I don't want to be platform-specific anyway.
The approach of using __dirname is the most reliable one. It will always give you correct directory. You do not have to worry about ../../ in Windows environment as path.join() will take care of that.
There is an alternative solution though. You can use process.cwd() which returns the current working directory of the process. That command works fine if you execute your Node.js application from the base application directory. However, if you execute your Node.js application from different directory, say, its parent directory (e.g., node yourapp\index.js) then the __dirname mechanism will work much better.
You can define a global variable like in your app.js file:
global.__basedir = __dirname;
Then you can use this global variable anywhere. Like this:
var base_path = __basedir
You can use path.resolve() without arguments to get the working directory which is usually the base application path. If the argument is a relative path then it's assumed to be relative to the current working directory, so you can write
require(path.resolve(myfilename));
to require your module at the application root.

Snap configuration file

How would I correctly use configuration file in Snap?
At the moment, I hard code DB host and DB name. If I wanted to put it in a file within projectroot/config directory, how would I make it available within a handler or within app init function?
It is mentioned briefly in snaplets tutorial that configurator library can be used but there was no explanation of how to actually use it.
Thanks.
Just call getSnapletUserConfig which returns a Config. Then use functions from configurator to get the information you need. Look at snaplet-postgresql-simple's use of config files for a working example.
The config file defaults to devel.cfg in the current snaplet file path. So if you are using getSnapletUserConfig in your top-level application, then the config file will be in your project root. Otherwise it will be in snaplets/foo where "foo" is the name of whatever snaplet you are in.

Resources