Tengo la siguiente estructura de directorio
app ├── default.js ├── index.html ├── ObserverPattern ├── ConcreteObserver.mjs ├── ConcreteSubject.mjs ├── ObserverList.mjs ├── Observer.mjs └── Subject.mjs En index.html tengo <script type="module" src="default.js"></script>
En default.js tengo el siguiente código
import { Observer } from "./ObserverPattern/Observer.mjs"; import { ObserverList } from "./ObserverPattern/ObserverList.mjs"; import { Subject } from "./ObserverPattern/Subject.mjs"; import { ConcreteObserver } from "./ObserverPattern/ConcreteObserver.mjs"; import { ConcreteSubject } from "./ObserverPattern/ConcreteSubject.mjs"; En ConcreteObserver.mjs tengo el siguiente código
class ConcreteObserver extends Observer { constructor(element) { super(); this.element = element; } update(value) { this.element.checked = value; } } export { ConcreteObserver }; Cuando ejecuto a través del servidor web local, aparece el error de que Uncaught ReferenceError: Observer is not defined
Si luego agrego import { Observer } from './Observer.mjs'; en la parte superior de ConcreteObserver.mjs , entonces funciona sin errores.
¿Hay alguna manera de importar todos los módulos en default.js para que no tenga que incluir import { Observer } from './Observer.mjs'; en cada implementación concreta?
Algo así como la autoload del compositor php
Gracias
Una buena parte del objetivo de los módulos es aislar el código para que no termine con una gran cantidad de variables dentro del alcance que no se utilizan.
Dado que parece estar ejecutándose en un navegador, podría asignar explícitamente valores al objeto global...
import { Observer } from "./ObserverPattern/Observer.mjs"; window.Observer = Observer; Y luego use window.Observer . Observer en otro lugar.
Pero eso hace que el código sea difícil de administrar. Linters no podrá detectar errores en los que no haya podido asignar la variable correctamente. Corre el riesgo de condiciones de carrera en las que intenta leer el valor antes de asignarlo al objeto de la ventana.
Si necesita usar Observer , impórtelo donde necesite usarlo.
Uno de los puntos de los módulos es que son autónomos y las relaciones entre ellos están definidas explícita y estáticamente (principalmente, hay una forma dinámica de importación). No hay importación automática en ESM.
Para que la implementación de ConcreteObserver funcione tal cual, Observer tendría que ser global y tendría que definirse antes de evaluar ConcreteObserver . Eso es algo que podría hacer, aunque mi opinión es que no debería, al hacer que Observer.mjs asigne Observer a una propiedad en globalThis (en entornos modernos, global en Node.js más antiguo o window en navegadores más antiguos). Pero aparte de eso, necesitará al menos una import en ConcreteObserver.mjs .
Hay un par de cosas que puede hacer para mantener baja la cantidad de declaraciones de import distintas, si ese es un objetivo. Por ejemplo, puede agrupar las cosas un poco más ( Observer , ObserverList y Subject parecen estar estrechamente relacionados, por lo que podrían ir todos en un solo módulo). Pero aún necesitaría esa import en ConcreteObserver.mjs . También es posible que un módulo vuelva a exportar cosas de otros módulos (por ejemplo: export { Something } from "./somewhere.mjs"; ), si desea tener un módulo maestro para todas las cosas de ObserverPattern que exportaron todo lo definido en los archivos que lo componen. Pero nuevamente, aún necesitaría import en ConcreteObserver.mjs