NodeJS包动态同步require兼容内外JSON文件问题
解决方案
要同时支持加载包内JSON和用户项目中的JSON,核心是区分路径类型并使用对应的模块上下文进行解析,以下是具体实现方案:
核心思路
- 对用户传入的路径进行判断:
- 若为相对路径(./、../开头)或绝对路径:使用用户的上下文(工作目录或用户模块目录)解析
- 若为包内路径(如
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
相关产品推荐
相关产品推荐

