You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NodeJS包动态同步require兼容内外JSON文件问题

解决方案

要同时支持加载包内JSON和用户项目中的JSON,核心是区分路径类型并使用对应的模块上下文进行解析,以下是具体实现方案:

核心思路

  • 对用户传入的路径进行判断:
    1. 若为相对路径(./、../开头)或绝对路径:使用用户的上下文(工作目录或用户模块目录)解析
    2. 若为包内路径(如lib/some.json或my-package/lib/some.json):使用包自身的模块上下文解析

具体实现

ESM 版本(dist/index.mjs)

import { createRequire } from 'module';
import path from 'path';
import { fileURLToPath } from 'url';

// 获取包自身的目录路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 创建基于包自身模块的require实例
const packageRequire = createRequire(import.meta.url);

export default function main(params) {
  let data;
  const jsonPath = params.json;

  // 处理用户项目的相对/绝对路径
  if (path.isAbsolute(jsonPath) || jsonPath.startsWith('./') || jsonPath.startsWith('../')) {
    let userRequire;
    // 优先使用用户传入的模块上下文(可选,更精准)
    if (params.contextUrl) {
      userRequire = createRequire(params.contextUrl);
    } else {
      // fallback到当前工作目录
      userRequire = createRequire(`file://${process.cwd()}/`);
    }
    data = userRequire(jsonPath);
  } else {
    // 处理包内路径
    try {
      // 先尝试按包名子路径加载(如用户传入'my-package/lib/some.json')
      data = packageRequire(jsonPath);
    } catch (err) {
      // 尝试拼接包内lib目录加载(如用户传入'lib/some.json'或'some.json')
      const internalPath = path.join(__dirname, '../lib', jsonPath);
      data = packageRequire(internalPath);
    }
  }

  // 此处添加data处理逻辑
  return data;
}

CJS 版本(dist/index.cjs)

const path = require('path');
// CJS环境直接使用自身的require实例
const packageRequire = require;

module.exports = function main(params) {
  let data;
  const jsonPath = params.json;

  // 处理用户项目的相对/绝对路径
  if (path.isAbsolute(jsonPath) || jsonPath.startsWith('./') || jsonPath.startsWith('../')) {
    let absolutePath;
    // 优先使用用户传入的模块目录(可选)
    if (params.contextDir) {
      absolutePath = path.resolve(params.contextDir, jsonPath);
    } else {
      // fallback到当前工作目录
      absolutePath = path.resolve(process.cwd(), jsonPath);
    }
    data = require(absolutePath);
  } else {
    // 处理包内路径
    try {
      data = packageRequire(jsonPath);
    } catch (err) {
      const internalPath = path.join(__dirname, '../lib', jsonPath);
      data = require(internalPath);
    }
  }

  // 此处添加data处理逻辑
  return data;
};

使用示例

用户加载自身项目的JSON

// ESM 用户(相对路径相对于自身模块)
import main from 'my-package';
main({ json: './path/to/my.json', contextUrl: import.meta.url });

// CJS 用户(相对路径相对于自身模块)
const main = require('my-package');
main({ json: './path/to/my.json', contextDir: __dirname });

// 或直接基于工作目录加载(无需传上下文)
main({ json: './path/to/my.json' });

用户加载包内随附的JSON

// 方式1:使用包名子路径(匹配package.json的exports配置)
main({ json: 'my-package/lib/some.json' });

// 方式2:直接传入相对包内lib的路径
main({ json: 'lib/some.json' });
main({ json: 'some.json' }); // 若JSON直接放在lib目录下

关键说明

  • 利用createRequire创建不同上下文的require实例,解决模块解析路径的上下文差异问题
  • 通过path.isAbsolute和路径前缀判断,区分用户路径和包内路径
  • 可选的上下文参数(contextUrl/contextDir)让用户可以精准控制相对路径的解析基准,避免工作目录带来的歧义
  • 结合package.json的exports配置,确保包内路径可以通过包名子路径被正确加载

内容的提问来源于stack exchange,提问作者Donnie D'Amato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 12:45:59