Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do node_modules packages read config files in the project root?

I am creating an npm package that needs to be able to read config files from the project root. I'm not sure how to do this.

For example,

  • Next.js is able to read ./pages/ and ./next.config.js from the project root
  • Jest is able to read ./jest.config.js from the project root
  • ESLint is able to read ./.eslintrc.json from the project root
  • Prettier is able to read ./.prettierrc.js from the project root
  • Typescript is able to read ./tsconfig.json from the project root
  • Babel is able to read ./.babelrc from the project root

I've tried looking at their source code to see how they do it but the projects are so large that I can't find the relevant section.

How do they achieve this?

like image 435
Jake Avatar asked Dec 01 '25 01:12

Jake


1 Answers

First search in path.dirname(process.mainModule.filename) then go up the directory tree ../, ../../, ../../../ and so on until you find the configuration file.

Here is the code I use stolen from rc (https://github.com/dominictarr/rc) package, it will read and json parse configuration from a file named .projectrc:

const fs = require('fs');
const path = require('path');

// Utils shamefully stolen from
// https://github.com/dominictarr/rc/blob/master/lib/utils.js

find(...args) {
  const rel = path.join.apply(null, [].slice.call(args));
  return findStartingWith(path.dirname(process.mainModule.filename), rel);
}

findStartingWith(start, rel) {
  const file = path.join(start, rel);
  try {
    fs.statSync(file);
    return file;
  } catch (err) {
    // They are equal for root dir
    if (path.dirname(start) !== start) {
      return findStartingWith(path.dirname(start), rel);
    }
  }
}

parse(content) {
  if (/^\s*{/.test(content)) {
    return JSON.parse(content);
  }
  return undefined;
}

file(...args) {
  const nonNullArgs = [].slice.call(args).filter(arg => arg != null);

  // path.join breaks if it's a not a string, so just skip this.
  for (let i = 0; i < nonNullArgs.length; i++) {
    if (typeof nonNullArgs[i] !== 'string') {
      return;
    }
  }

  const file = path.join.apply(null, nonNullArgs);
  try {
    return fs.readFileSync(file, 'utf-8');
  } catch (err) {
    return undefined;
  }
}

json(...args) {
  const content = file.apply(null, args);
  return content ? parse(content) : null;
}

// Find the rc file path
const rcPath = find('.projectrc');
// Or
// const rcPath = find('/.config', '.projectrc');

// Read the contents as json
const rcObject = json(rcPath);
console.log(rcObject);

You can also use the rc package as a dependency npm i rc, then in your code:

var configuration = require('rc')(appname, {
  // Default configuration goes here
  port: 2468
});

This will read config from a file named .${appname}rc.

like image 138
Andrei Avatar answered Dec 02 '25 13:12

Andrei