0

I try to build my first npm package, but now I got stuck.

I want to load from my package a config file that is located in the root of my test-project

I used "npm link my-package" to install it locale for testing (if this important)

This is my folder structure

- my-package 
- test-project
  - node-modules 
    - my-package (npm link)
  - config.json

The package is a vuejs app that should start a server and serve a page

I run this script from my test-project

"scripts": {
  "generatePage": "npm explore my-package -- npm run serve"
},

script from my package

"scripts": {
  "serve": "node readFile.js & vue-cli-service serve"
},

my-package/readFile.js

file_path = path.join(process.cwd(), 'config.json')
console.log('file_path', file_path)

If I'm running my script I get this path /Users/name/work/my-package/config.json but I need /Users/name/work/test-project/config.json

How do I get the correct path?

Gregor Voinov
  • 2,203
  • 7
  • 34
  • 52
  • Are you looking for the user of your package to provide a config? Or do you have a config file in your package that you are trying to read? If it is the latter you most likely need to add your config.json to your package.json files list. – Mike Coakley Feb 24 '21 at 14:45
  • The user must create this config.json in his project, so that the package can read it. Next step is to auto-create this config.json, during installation, with an example how the structure should look like. – Gregor Voinov Feb 24 '21 at 15:04
  • Understood. stackoverflow to the rescue... check out https://stackoverflow.com/a/7352912/7102037 - it seems to be exactly what you are looking for. Reply here if it isn't so your question can continue to get answers. – Mike Coakley Feb 25 '21 at 01:54
  • No it doesn't solved my problem. I also figured out some mistakes. Now I'm calling the readFile directly from package -> scripts. I have updated my questions regarding that. – Gregor Voinov Feb 25 '21 at 08:33

1 Answers1

0

When you write a library that will be used by another code base you cannot be sure where exactly NPM or yarn (or whatever package manager you choose) will install your library. It may be directly in node_modules but it may be nested depending upon the use case. However, as indicated by the stackoverflow answer here the process.main.filename variable will tell us exactly where the main process that is calling us lives. We can use this value to determine where the config file you want to read exists.

Here is some example code:

The config-lib library reads a configuration.

index.js file:

const fs = require("fs");
const path = require("path");
const promisify = require("util").promisify;

const readFilep = promisify(fs.readFile);

module.exports = async function loadConfig(filename = "config.json") {
  const configPath = path.resolve(
    path.dirname(require.main.filename),
    filename
  );
  console.log("(load-config lib) Config Path: " + configPath);
  try {
    const data = await readFilep(configPath, "utf8");
    return JSON.parse(data);
  } catch (err) {
    console.log(err);
  }
};

This library has a simple package.json

{
  "name": "config-lib",
  "version": "1.0.0",
  "description": "I read a config",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Some Cool Guy <somecoolguy@example.com>",
  "license": "MIT"
}

Now the project itself requires this library. Here is the projects package.json

{
  "name": "project",
  "version": "1.0.0",
  "description": "I am the project",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Some Other Cool Guy <someoneelse@example.com>",
  "license": "MIT",
  "dependencies": {
    "config-lib": "file:../lib"
  }
}

(The config-lib library in this example was loaded from a local folder.)

The config-lib library requires me, in my project, to create a configuration file called config.json (BTW... name it something more specific to your library as to not collide with a local project configuration if they have one).

Here is an example config.json:

{
  "key1": "value1",
  "key2": "value2",
  "key3": "value3"
}

Finally, in my project I can use the config-lib library to read my configuration file:

const configLib = require("config-lib");

(async () => {
  console.log("Reading config");
  const data = await configLib();

  console.log("Here is my config: " + JSON.stringify(data));
  console.log("key1 value: " + data.key1);
})();
Mike Coakley
  • 181
  • 1
  • 7
  • hmm now I get this path: ```/Users/name/work/my-package/node_modules/@vue/cli-service/bin/config.json```. And I don't need the config.json in "test-project" it will be only used by "my-package" to generate a page with design-tokens, that devs have them always available. Sry I'm a UI designer with some minor coding skills ;) – Gregor Voinov Feb 25 '21 at 15:37
  • Honestly, I've never used `npm link` for testing, I've always just used a file based install for testing my libraries. This may be the issue. Try installing your package using a file install. For example, for the test code above I had a root testing folder `/user/guy/testing`, then I have a `lib` folder for the library and a `project` folder for the project. In the project folder I executed `npm install ../lib` to install my library. Try that. – Mike Coakley Feb 25 '21 at 15:45
  • no also with ```npm i ../my-package```I get the same path. But is it normal behaviour that if I edit something inside my installed package and save it the "original" package also gets updated? Maybe the problem is how I call the package with ```npm explore my-package -- npm run serve``` ? – Gregor Voinov Feb 25 '21 at 17:25
  • First, I used `npm link` in my lib folder (from the example code) and then `npm link config-lib` and everything worked as is expected. Second, if you run `npm explore my-package -- npm run serve` that will run the `node` process from your package and that is why you are finding the path you are finding. You need to have the `npm run serve` in your application side to find the application config. Try my code and you will see what you want to work, from the config perspective, will work. – Mike Coakley Feb 25 '21 at 18:15
  • First thank you for your time. but I need to run ```npm run serve``` from "my-package" this will start the vuejs server and builds the pages based on the config.json. Or is there a way to read the config from my application and pass it down to my lib? Maybe I got everything wrong in my head ;) – Gregor Voinov Feb 25 '21 at 19:11
  • Without seeing more of your code that is hard to answer. But I can say you almost always want the application to start the service, not the package. It is exactly similar to how Vue is doing it. Vue is the package but it doesn't start anything, your code does. Vue provides all the tooling but doesn't actually start anything. Also, that is outside the scope of your question. I believe my answer resolves your issue about finding the correct path from a package. You probably should ask another question in regard to how to start your Vue app given your criteria. – Mike Coakley Feb 26 '21 at 00:35