Cargue y consuma módulos JS heredados (por ejemplo, IIFE) a través de importaciones de módulos ES6


9

Tengo funciones IIFE para algunos de los códigos de la biblioteca en una aplicación heredada que necesita funcionar para IE10 + (sin carga del módulo ES6, etc.).

Sin embargo, estoy empezando a desarrollar una aplicación React que usará ES6 y TypeScript y quiero reutilizar el código que ya tengo sin duplicar los archivos. Después de un poco de investigación, descubrí que me gustaría usar un patrón UMD para permitir que estos archivos de biblioteca funcionen como <script src=*>importaciones y para permitir que la aplicación React los importe a través de la carga del módulo ES6.

Se me ocurrió la siguiente conversión:

var Utils = (function(){
  var self = {
    MyFunction: function(){
      console.log("MyFunction");
    }
  };
  return self;
})();

a

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
    typeof define === 'function' && define.amd ? define(['exports'], factory) :
    (factory((global.Utils = {})));
}(this, (function (exports) { 
  exports.MyFunction = function(){
      console.log("MyFunction");
    };
})));

Esto permitirá cargar mediante un Import Utils from './Utils.js'comando y también permitirá que se inserte usando una etiqueta de script<script src='Utils.js'></script>

Sin embargo, algunos de mis IIFE usan otros IIFE como dependencia (malo, lo sé, pero una realidad).

var Utils = Utils; // Used to indicate that there is dependency on Utils
var RandomHelper = (function(){
  var self = {
    DoThing: function(){
      Utils.MyFunction();
    }
  };
  return self;
})();

Si gire correctamente RandomHelpery Utilsen archivos que se pueden importar, el Reaccionar aplicación no es compatible con esta técnica. Haciendo simplemente

Import Utils from './Utils.js'
Import RandomHelper from './RandomHelper.js'

no funciona porque creo que Utils no tiene un alcance de ventana. Se cargará sin problemas pero RandomHelper.DoThing()arrojará que Utils no está definido.

En la aplicación heredada

<script src='Utils.js'></script>
<script src='RandomHelper.js'></script>

funciona perfectamente.

¿Cómo puedo hacer que RandomHelper pueda usar Utils en una aplicación React, manteniéndolo compatible con IE y ES5 pero aún así trabajando en react? ¿Quizás de alguna manera establecer una ventana / variable global?

PD: Entiendo que el objetivo de la carga del módulo ES6 es tratar las dependencias y mis IIFE existentes no son ideales. Planeo cambiar eventualmente las clases de es6 y un mejor control de dependencia, pero por ahora quiero usar lo que está disponible sin tener que volver a escribir


44
React usa jsx y ningún navegador entiende jsx, por lo que necesita babel de todos modos, no tiene sentido no usar declaraciones de importación en un proyecto react porque de todos modos tiene que usar babel. React también se está alejando de OO, por lo que decir que desea utilizar las clases de ES6 con react no tiene mucho sentido. Todavía admite clases, pero se está moviendo hacia componentes funcionales.
HMR

Sí, tengo babel / webpack y uso el marco CRA.
ParoX

En node.js también puedo usar global.Utils = (func ... y var Utils = global.Utils; entonces.
Tom

Podría frotar un poco de amor de componentes web con algunas plantillas que imagino dependiendo de lo que necesite soportar.
Chris W.

1
Creo que realmente debería pasar a la sintaxis de importación ES6 para todo lo que desea usar en su nueva aplicación y volver a compilarla en el formato IIFE (o simplemente UMD) para la aplicación heredada. No tiene que volver a escribir el archivo completo, sino corregir las declaraciones de dependencia.
Bergi el

Respuestas:


2

Vamos a aclarar esto primero, las funciones del módulo, si no se exportan explícitamente, tienen un ámbito privado para el módulo de definición . No puedes evitar este hecho. Pero hay opciones alternativas que puede considerar.

1. Asumir una modificación mínima del código heredado es aceptable

Una solución alternativa con cambios mínimos en su código heredado sería simplemente agregar Utilsy RandomHelperal windowobjeto. Por ejemplo, cambie var Utils = (...)();a window.Utils = (...)();. En consecuencia, se podrá acceder al objeto desde el objeto global mediante códigos heredados (cargados mediante import) y una base de código más reciente.

2. Asumiendo que no se puede tolerar absolutamente ninguna modificación en el código heredado

Se debe crear un nuevo módulo ES6 como proxy para cargar los scripts heredados:

// ./legacy-main.js

const utilsScript = await fetch( './Utils.js' )
const randomHelperScript = await fetch( './RandomHelper.js' )

const utilsScriptText = await utilsScript.text()
const randomHelperScriptText = await randomHelperScript.text()

// Support access to `Utils` via `import` 
export const Utils = Function( `${utilsScriptText}; return Utils;` )()
// Additionally support access via global object 
Object.defineProperty(window, 'Utils', { value: Utils })

// Support access to `RandomHelper` via `import`
// Note that `Utils` which is a dependency for `RandomHelper` ought to be explicitly injected
// into the scope of execution of `RandomHelper`.
export const RandomHelper = Function( 'Utils', `${randomHelperScriptText}; return RandomHelper;` )( Utils )
// Additionally support access via global object 
Object.defineProperty(window, 'RandomHelper', { value: RandomHelper })

Por último, es posible importar Utilsy RandomHelperdesde legacy-main.jscuando sea necesario:

import { Utils, RandomHelper } from './legacy-main.js'

Utils.MyFunction()
RandomHelper.DoThing()

0

Un enfoque que podría considerar es alguna forma de inyección de dependencia : haga que su aplicación React reciba RandomHelper, o algunas de sus propiedades, del mundo exterior. Luego puede quitarlo cuando esté listo para cortar el cordón.

var Utils = (function(){
  var self = {
    MyFunction: function(name){
      return `Hello, ${name}!`;
    }
  };
  return self;
})();

var RandomHelper = (function(){
  var self = {
    DoThing: function(name){
      return Utils.MyFunction(name);
    }
  };
  return self;
})();

const ComponentOne = ({hello}) => {
  return <h1>{hello('ComponentOne')}</h1>;
}

const ComponentTwo = ({hello}) => {
  return <h2>{hello('ComponentTwo')}</h2>
}

const App = ({ExternalFunctions}) => {
  return (
    <header>
      <ComponentOne hello={ExternalFunctions.hello} />
      <ComponentTwo hello={ExternalFunctions.hello} />
    </header>
  )
}

ReactDOM.render(
  <App ExternalFunctions={{hello: RandomHelper.DoThing}} />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.