npm node_modules包如何读取项目根目录中的配置文件?

w51jfk4q  于 2022-12-13  发布在  其他
关注(0)|答案(4)|浏览(526)

我正在创建一个npm包,它需要能够从项目根目录读取配置文件。我不知道该如何做。
例如,

  • Next.js能够从项目根目录读取./pages/./next.config.js
  • Jest能够从项目根目录读取./jest.config.js
  • ESLint能够从项目根读取./.eslintrc.json
  • Prettier能够从项目根目录读取./.prettierrc.js
  • Typescript能够从项目根目录读取./tsconfig.json
  • Babel能够从项目根读取./.babelrc

我试着看他们的源代码,看看他们是如何做到这一点,但项目是如此之大,我找不到相关的部分。
他们是如何做到这一点的?

anauzrmj

anauzrmj1#

首先在path.dirname(process.mainModule.filename)中搜索,然后向上到目录树../, ../../, ../../../,依此类推,直到找到配置文件。
下面是我使用的从rc(https://github.com/dominictarr/rc)包中偷来的代码,它将从一个名为.projectrc的文件中读取和json解析配置:

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);

你也可以使用rc包作为一个依赖npm i rc,然后在你的代码中:

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

这将从名为.${appname}rc的文件中读取配置。

balp4ylt

balp4ylt2#

我在制作第一个npm包时遇到了这个问题,findup-sync库很好地解决了这个问题:

const findup = require('findup-sync');
const filePath = findup('filename');

https://www.npmjs.com/package/findup-sync

ipakzgxi

ipakzgxi3#

它们从文件所在的目录开始,在文件系统树中向上递归查找,直到找到要查找的文件。
大概是这样的:

const FILE_NAME = 'target-file.json';

const fsp = require('fs').promises,
      path = require('path');

let find = async (dir=__dirname) => {
  let ls = await fsp.readdir(dir);
  if(ls.includes(FILE_NAME))
    return path.join(dir,FILE_NAME);
  else if(dir == '/')
    throw new Error(`Could not find ${FILE_NAME}`);
  else
    return find(path.resolve(dir,'..'));
}

或者,如果您要查找一个标准节点“project root”,您可能需要向上递归,找到一个包含名为'node_modules'的目录,如下所示:

const fsp = require('fs').promises,
      path = require('path');

let find = async (dir=__dirname) => {
  let ls = await fsp.readdir(dir);
  if(ls.includes('node_modules'))
    return dir;
  else if(dir == '/')
    throw new Error(`Could not find project root`);
  else
    return find(path.resolve(dir,'..'));
}
n6lpvg4x

n6lpvg4x4#

有多种方法可以做到这一点。我已经创建了一个test-package和一个演示项目node-package-test来测试它。
为了便于参考,请在此处提供主要代码:

项目主目录\节点模块\测试包\索引.js:

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

const CONFIG_NAME = 'cfg.json';

function init(rootDir = null) {
  console.log(`test-package: process.cwd(): ${process.cwd()}`);
  console.log(`test-package: path.resolve('./'): ${path.resolve('./')}`);

  if (!rootDir) {
    //rootDir = path.resolve('./');
    // OR
    rootDir = process.cwd();
  }

  //const configPath = path.resolve('./', CONFIG_NAME);
  // OR
  const configPath = path.join(rootDir, CONFIG_NAME);

  if (fs.existsSync(configPath)) {
    console.log(`test-package: Reading config from: ${configPath}`);
    try {
      //const data = fs.readFileSync(configPath, 'utf8');
      //const config = JSON.parse(data);
      // OR
      const config = require(configPath);
      console.log(config);
    } catch (err) {
      console.error(err)
    }
  } else {

    console.log(`test-package: Couldn't find config file ${configPath}. Using default.`)
  }

  console.log('\n')
}

//init()
const features = {
  init: init,
  message: `Hello from test-package! 👋`
}

module.exports = features;

项目主文件\main.js:

const utils = require('@onkarruikar/test-package')

utils.init();
// OR use
//utils.init('/path/to/rootdir');

console.log(`${utils.message}`);

输出:

E:\node-package-test-main>npm install

added 1 package, and audited 2 packages in 4s

found 0 vulnerabilities

E:\node-package-test-main>npm start

> start
> node .

test-package: process.cwd(): E:\node-package-test-main
test-package: path.resolve('./'): E:\node-package-test-main
test-package: Reading config from: E:\node-package-test-main\cfg.json
{ compilerOptions: { allowJs: true, checkJs: true, noEmit: true } }

Hello from test-package! 👋

相关问题