我最近在NodeJS项目中从CommonJS切换到了ES6模块。我面临的挑战之一是在导入模块之前定义一个全局变量。我曾经在我的主文件中使用CommonJS来做这件事
const path = require('path');
global.appRoot = path.resolve(__dirname);
const myObj = require('./my-object-file');
其中我的CCD_ 1使用CCD_。
使用ES6,我尝试了以下操作:
import path from 'path';
global.appRoot = path.resolve(path.resolve());
import myObj from './my-object-file';
其中my-object-file.js
为:
export default {
root: global.appRoot
}
但我在my-object-file.js
中得到了global.appRoot
的未定义。
这是怎么回事?
导入模块是否在我的代码中的任何内容之前调用?
我该如何解决这个问题(知道我绝对希望能够将路径定义为可在模块中访问的全局变量(?
导入模块是否在我的代码中调用之前?
是的,在导入模块中的任何代码运行之前,都会解析所有模块导入。
然而,导入的模块也按顺序执行,因此如果您执行
import './setupGlobals';
import myObj from './my-object-file';
则setupGlobals模块代码在my对象文件之前执行。所以什么时候起作用
// setupGlobals.mjs
import path from 'path';
global.appRoot = path.resolve(path.resolve());
我绝对希望能够将路径定义为可在我的模块中访问的全局变量
不,你真的不想那样做。明确声明您的依赖关系,而不是在任何地方创建全局变量!
如果您有一个单独的模块来定义全局变量,只需将export
作为这些变量,而不是将值放在global
对象上:
// globals.mjs
import path from 'path';
const appRoot = path.resolve(path.resolve());
export { appRoot as default }
然后,您可以在任何模块中声明性地使用这个全局常量:
// my-object-file.js:
import appRoot from './globals';
export default {
root: appRoot
}
我喜欢Bergi的答案:
import appRoot from './globals';
然后,任何想要访问的文件都可以访问appRoot
,并且可以保留模块性。
但是,除了这种方法之外,我在评论中的建议是,与其在导入之前设置全局,不如从模块中导出一个函数并调用该函数,将其传递给所需的路径。这是一种从父模块向模块传递初始化参数的通用方法,无需使用全局变量。
并且,我建议您使用import.meta.url
解决方案来创建等效的my-object-file
0作为这里的大纲。您对path.resolve()
所做的只是获得当前工作目录,它不一定是__dirname
,因为这取决于如何加载此模块,以确定它们是否相同。此外,如果你只是想要等价的cwd,你可以在你的子模块中使用process.cwd()
。以下是ESM模块中__filename
和__dirname
的等效值。
// create __dirname and __filename equivalents in ESM module
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
然后,导入模块初始化函数(有时称为模块构造函数(并调用模块构造函数:
从"导入myObjConstructor/我的对象文件';const myObj=myObjConstructor(__dirname(;
然后,在我的对象文件中,导出一个函数,当调用该函数时,使用传入的__dirname
初始化模块,并返回myObj
。
因此,my-object-file
:内部
function init(__dirname) {
// do whatever you want for module initialization
// using __dirname
return yourObj;
}
export { init as default };