简体   繁体   中英

Define global variable before importing ES6 module

I have recently switched from CommonJS to ES6 modules in my NodeJS project. One of the challenge I'm facing is to define a global variable before I import one of my module. I used to do that with CommonJS in my main file:


const path = require('path');

global.appRoot = path.resolve(__dirname);

const myObj = require('./my-object-file');

where my my-object-file uses global.appRoot .

With ES6, I have tried the following:

import path from 'path';

global.appRoot = path.resolve(path.resolve());

import myObj from './my-object-file';

with my-object-file.js being:

export default {
    root: global.appRoot
}

But I get undefined for global.appRoot in my-object-file.js .

What is going on here?

Are import modules called before anything in my code?

How can I solve this (knowing that I absolutely want to be able to define the path as a global variable accessible in my modules)?

Are import modules called before anything in my code?

Yes, all module imports are resolved before any code in the importing module runs.

However, imported modules are also executed in order, so if you do

import './setupGlobals';
import myObj from './my-object-file';

then the setupGlobals module code is executed before the my-object-file one. So it will work when do

// setupGlobals.mjs
import path from 'path';    
global.appRoot = path.resolve(path.resolve());

I absolutely want to be able to define the path as a global variable accessible in my modules

No, you really don't want to do that. Instead of a global variable that might be created anywhere, explicitly declare your dependency!

If you have a separate module to define your globals anyways, just make that export those variables instead of putting the values on the global object:

// globals.mjs
import path from 'path';    
const appRoot = path.resolve(path.resolve());
export { appRoot as default }

Then you can declaratively use this global constant in any of your modules:

// my-object-file.js:

import appRoot from './globals';

export default {
    root: appRoot
}

I like Bergi's answer with:

import appRoot from './globals';

Then, any file that wants to can get access to appRoot and you preserve modularity.

But, in addition to that approach, my suggestion in comments was that rather than setting a global before you import, you export a function from your module and call that function, passing it the desired path. This is a general purpose way of passing initialization parameters to a module from the parent module without using globals.

And, I suggest you use the import.meta.url work-around for creating the equivalent of __dirname as outline here . What you were doing with path.resolve() is just getting you the current working directory, which is not necessarily __dirname as it depends upon how this module was loaded for whether they are the same or not. Besides if you just wanted the equivalent of cwd, you could just use process.cwd() anyway in your child module. Here's the equivalent for __filename and __dirname in an ESM module.

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

Then, import the module initialization function (sometimes called a module constructor) and call the module constructor:

import myObjConstructor from './my-object-file'; const myObj = myObjConstructor(__dirname);

Then, inside of my-object-file, you export a function and when that function is called, you initialize your module using the passed in __dirname and return the myObj .

So, inside of my-object-file :

function init(__dirname) {
   // do whatever you want for module initialization
   // using __dirname

   return yourObj;
}

export { init as default };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM