Recientemente cambié de módulos CommonJS a ES6 en mi proyecto NodeJS. Uno de los desafíos que enfrento es definir una variable global antes de importar uno de mi módulo. Solía hacer eso con CommonJS en mi archivo principal:
const path = require('path'); global.appRoot = path.resolve(__dirname); const myObj = require('./my-object-file'); donde my my-object-file usa global.appRoot .
Con ES6, he intentado lo siguiente:
import path from 'path'; global.appRoot = path.resolve(path.resolve()); import myObj from './my-object-file'; siendo my-object-file.js :
export default { root: global.appRoot } Pero no estoy definido para global.appRoot en my-object-file.js .
¿Que esta pasando aqui?
¿Se llaman los módulos de importación antes que nada en mi código?
¿Cómo puedo resolver esto (sabiendo que absolutamente quiero poder definir la ruta como una variable global accesible en mis módulos)?
¿Se llaman los módulos de importación antes que nada en mi código?
Sí, todas las importaciones de módulos se resuelven antes de que se ejecute cualquier código en el módulo de importación.
Sin embargo, los módulos importados también se ejecutan en orden, por lo que si lo hace
import './setupGlobals'; import myObj from './my-object-file';entonces el código del módulo setupGlobals se ejecuta antes que el de my-object-file . Entonces funcionará cuando lo haga
// setupGlobals.mjs import path from 'path'; global.appRoot = path.resolve(path.resolve());Absolutamente quiero poder definir la ruta como una variable global accesible en mis módulos
No, realmente no quieres hacer eso. En lugar de una variable global que podría crearse en cualquier lugar, ¡declare explícitamente su dependencia!
Si tiene un módulo separado para definir sus globales de todos modos, simplemente haga que export esas variables en lugar de poner los valores en el objeto global :
// globals.mjs import path from 'path'; const appRoot = path.resolve(path.resolve()); export { appRoot as default }Luego puede usar declarativamente esta constante global en cualquiera de sus módulos:
// my-object-file.js: import appRoot from './globals'; export default { root: appRoot }Me gusta la respuesta de Bergi con:
import appRoot from './globals'; Entonces, cualquier archivo que desee puede obtener acceso a appRoot y preservar la modularidad.
Pero, además de ese enfoque, mi sugerencia en los comentarios fue que, en lugar de configurar un global antes de importar, exporte una función de su módulo y llame a esa función, pasándole la ruta deseada. Esta es una forma de propósito general de pasar parámetros de inicialización a un módulo desde el módulo principal sin usar globales.
Y le sugiero que use la import.meta.url para crear el equivalente de __dirname como se describe aquí . Lo que estaba haciendo con path.resolve() es simplemente obtener el directorio de trabajo actual, que no es necesariamente __dirname , ya que depende de cómo se cargó este módulo para saber si son iguales o no. Además, si solo quisiera el equivalente de cwd, podría usar process.cwd() de todos modos en su módulo secundario. Este es el equivalente para __filename y __dirname en un módulo ESM.
// 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);Luego, importa la función de inicialización del módulo (a veces llamada constructor de módulos) y llama al constructor de módulos:
importar myObjConstructor desde './my-object-file'; const miObj = miObjConstructor(__dirname);
Luego, dentro de my-object-file, exporta una función y cuando se llama a esa función, inicializa su módulo usando el __dirname pasado y devuelve myObj .
Entonces, dentro de my-object-file :
function init(__dirname) { // do whatever you want for module initialization // using __dirname return yourObj; } export { init as default };