Para compartir datos entre módulos, un patrón habitual es encapsular los datos en un módulo común e importarlos en otros módulos.

En mi caso, los datos que se compartirán son un registrador, que deben inicializarse antes de usarse. Llamo a init() en el punto de entrada de mi solicitud.

// main.js

let logger = require('@my/logger');
logger.init({...});

let xxx = require('./moduleX');
let yyy = require('./moduleY');

En otros módulos, se puede usar el registrador inicializado:

// moduleX.js

let logger = require('@my/logger');
const log = logger('moduleX');

function x() {
  log.debug('some msg');
}

El código anterior funciona bien en node.js. Pero si cambio a la sintaxis del módulo ES6, no funciona porque la importación del módulo ES6 está activada.

// main.js

import {logger} from '@my/logger';
logger.init({...});          // this line is run after import moduleX
import {x} from './moduleX';

// moduleX.js

import {logger} from '@my/logger';
const log = logger('moduleX');        // logger is not initialized !

export function x() {
  log.debug('some msg');
}

Con el módulo ES6, ¿cómo puedo inicializar algunos datos y compartirlos con otros módulos?

Hubo una pregunta similar, pero la respuesta no se ajusta a mi caso.

Actualizar:

Algunas respuestas sugieren poner en funcionamiento el código que accede a los datos compartidos para que el código no se invoque inmediatamente al cargar el módulo. Pero, ¿qué sucede si realmente necesito acceder a él durante la carga del módulo? Actualicé mi código para demostrar el caso de uso: sería demasiado trivial llamar a logger(name) en cada función si no se hace log como constante de alcance del módulo.

2
aleung 11 dic. 2015 a las 17:50

5 respuestas

La mejor respuesta

Finalmente lo resuelvo de la manera que @PaoloMoretti mencionó en su comentario.

Escribir un módulo en mi aplicación para iniciar el registrador para mi aplicación:

// logger_init.js
import {logger} from '@my/logger';
logger.init({...});

Importe el módulo de inicialización una vez en el punto de entrada de la aplicación, antes de importar cualquier otro módulo que también use el registrador. Garantiza que la inicialización se realice antes de cargar otros módulos.

// main.js
import './logger_init'; 
import {x} from '@my/other_module';
import {y} from './module_in_myapp';

Otros módulos pueden usar el registrador inicializado directamente:

// @my/other_module

import {logger} from '@my/logger';
const log = logger('moduleX');       // logger has been initialized

export function x() {
  log.debug('some msg');
}

El árbol de dependencias es:

                           <init>
myapp --+--> logger_init ------------> @my/logger
        |                       <use>   ↑ 
        +--> module_in_myapp -----------+
        |                       <use>   |
        +--> @my/other_module ----------+

La razón por la que no adopto la forma en que agrego un módulo contenedor que inicia y devuelve un registrador (como la respuesta de Bergi) se debe a que los módulos que utilizan el registrador podrían ser módulos reutilizables que no están en mi aplicación.

2
aleung 14 dic. 2015 a las 04:29

Un registrador, que debe inicializarse antes de usarse. ¿Qué sucede si necesito acceder a él durante la carga del módulo?

Cree un módulo adicional con un registrador inicializado:

// main.js
import {x as xxx} from './moduleX';
import {y as yyy} from './moduleY';
// logger_ready.js
import {logger} from '@my/logger';
logger.init({…});
export default logger;
// moduleX.js
import logger from 'logger_ready';
const log = logger('moduleX');        // logger is initialized here!

export function x() {
  log.debug('some msg');
}
0
Bergi 13 dic. 2015 a las 11:19

Después de los experimentos, descubrí que el BroadcastChannel api es perfecto para compartir datos o eventos fácilmente entre diferentes módulos es6, pestañas, trabajadores, marcos ...

Podemos pasar objetos o matrices usando json stringify allí también:

Para enviar datos:

new BroadcastChannel('myapp_section8').postMessage('Hello world!')

Ejemplo de recepción, desde otro módulo:

new BroadcastChannel('myapp_section8').addEventListener('message', function(e){
  console.log(e.data) 
})

Evita usar cualquier elemento DOM para dispatchEvent , simplifica mucho las cosas .

0
NVRM 22 dic. 2018 a las 00:10

Intente proporcionar algunos puntos de entrada a sus módulos xxx.js y aaa.js o incluso hágalos como funciones.

// main.js
import {logger} from '@my/logger';
import * as xxx from './xxx';

logger.init({...});

xxx.run();

// xxx.js
import {logger} from '@my/logger';
export function run () {
   logger.debug('In xxx');
}
0
webschik 11 dic. 2015 a las 15:14

Puede hacer que cada módulo que depende de alguna rutina de inicialización devuelva una función que puede ejecutarse manualmente para invocar su funcionalidad, en lugar de exponer esa funcionalidad como un efecto secundario inmediato de importarla. Por ejemplo, en xxx.js:

// xxx.js
export default function (log) {
    log('xxx');
}

Luego coloque todas las operaciones de inicialización dentro de un archivo de entrada e invoque los módulos definidos de la manera anterior después de que estas operaciones estén completas:

// main.js
import xxx from './xxx';
import {logger} from '@my/logger';
logger.init({...});
xxx(logger);

Pero, ¿qué sucede si realmente necesito acceder a él durante la carga del módulo?

Consulte los ejemplos de código enmendado anteriores. Pase la instancia de logger a la función exportada por cada módulo.

0
sdgluck 11 dic. 2015 a las 16:46